Farther ShoreDocs
Go to Farther Shore
What is FartherShore
Install the CLI
Quickstart
Core concepts
The @Product class
Meters & resources
Features & routes
Capabilities & entitlements
@CapabilitycapabilityGrant — granting on a plan@EntitlementHow the pieces connect
Plans & pricing
The Manifest IR
Bring your own backend
Transport modes
Metering & verification
Runtime tokens
Frontend SDK
Root & data components
Auth & sessions
Entitlement gates
Connect Stripe
Subscriptions & usage
Plan changes & grandfathering
Billing strategies
Apply & deploy
Environments
Migrations
Docs versions & archive
Operate with an agent
Operation classes
MCP server
End-to-end via CLI/MCP
CLI reference
@farthershore/product
@farthershore/backend
@farthershore/farthershore-js
Environment variables
Response & deny codes
Add a metered capability
Gate a feature
Change a price
Prepaid credits
Meter AI tokens
Operate via an agent
Prepare for launch
Status
Docs/Define your product/Capabilities & entitlements

Capabilities & entitlements

@Capability, @Entitlement, and capabilityGrant — bundling access and granting it on plans.

PreviousFeatures & routesNextPlans & pricing

A @Capability is a named bundle of access — the features, policies, and other capabilities a subscriber gets when they hold it. Plans grant capabilities (optionally with per-capability resource limits) via capabilityGrant. An @Entitlement is a reusable, product-level grouping of capabilities, feature gates, limits, and meters that the dashboard and portals read.

import { Product, Resource, Capability, Feature, Plan, capabilityGrant } from "@farthershore/product";

@Product({ name: "croncloud", origin: "https://api.example.com" })
export default class CronCloud {
  @Resource("cron_jobs", { display: "Cron jobs", countSource: "action_inferred" })
  cronJobs!: unknown;

  @Capability("managed-cron", {
    title: "Managed Cron Jobs",
    includesFeatures: ["cron-jobs"],
  })
  managedCron!: unknown;

  @Feature("cron-jobs", { plans: ["starter"], routes: { "GET /v1/cron-jobs": {} } })
  cronJobsFeature!: unknown;

  @Plan("starter", {
    name: "Starter",
    grants: [capabilityGrant("managed-cron", { limits: { cron_jobs: 10 } })],
    limits: { requests: { rate: 600, interval: "minute" } },
  })
  starter!: unknown;
}

@Capability

@Capability(key, options) declares a capability. The key is the string plans and pages reference. includesFeatures names feature keys this capability unlocks; the named features must exist or the build fails (capability "…" depends on missing feature "…").

OptionTypeMeaning
titlestringHuman label for the capability.
descriptionstringLonger description.
includesFeaturesstring[]Feature keys this capability unlocks.
includesPoliciesstring[]Policy keys this capability includes.
includesCapabilitiesstring[]Other capability keys this one composes.
mutationClass"runtime" | "contractual"Mutation classification.
@Capability("managed-cron", {
  title: "Managed Cron Jobs",
  includesFeatures: ["cron-jobs"],
})
managedCron!: unknown;

compiles to a capability layer:

{ "capability": "managed-cron", "includes_features": ["cron-jobs"] }

References may be declared in any order — a capability can name a feature declared later in the class. Only truly missing references fail the build.

capabilityGrant — granting on a plan

A plan grants a capability through capabilityGrant(key, { limits }) in its grants[]. The optional limits set per-capability resource caps (numeric or boolean) — this is how you cap a counted resource like cron_jobs on a specific plan.

import { capabilityGrant } from "@farthershore/product";

@Plan("starter", {
  name: "Starter",
  grants: [capabilityGrant("managed-cron", { limits: { cron_jobs: 10 } })],
  limits: { requests: { rate: 600, interval: "minute" } },
})
starter!: unknown;

@Plan("pro", {
  name: "Pro",
  grants: [capabilityGrant("managed-cron", { limits: { cron_jobs: 100 } })],
  limits: { requests: { rate: 6000, interval: "minute" } },
})
pro!: unknown;

On the starter plan this folds into:

{ "key": "starter", "capabilities": ["managed-cron"], "capability_limits": { "cron_jobs": 10 } }

capabilities is a first-class array on the plan; the limits land in capability_limits.

For a capability with no per-capability limits, two spellings are equivalent: a bare grants: [capabilityGrant("managed-cron")], or the shorthand capabilities: ["managed-cron"] on the plan. Use capabilityGrant with limits only when you need the resource caps.

@Entitlement

@Entitlement(key, options) groups capabilities, feature gates, limits, and meters into one reusable, product-level bundle. Unlike a capability (which a plan grants), an entitlement is descriptive metadata the platform surfaces — it composes existing declarations into a named access tier.

OptionTypeMeaning
descriptionstringHuman description.
capabilitiesstring[]Capability keys in this entitlement.
featureGatesRecord<string, boolean>Feature-gate flags.
limitsPlanLimit[]Rate limits (the IR limits[] shape: { dimension, window, capacity }).
metersstring[]Meter keys in this entitlement.
@Meter("workflow_runs", { unit: "run" })
workflowRuns!: unknown;

@Capability("premium_tools")
premium!: unknown;

@Entitlement("premium_access", {
  capabilities: ["premium_tools"],
  featureGates: { premium_tools: true },
  meters: ["workflow_runs"],
  limits: [
    { dimension: "workflow_runs", window: { type: "named", name: "month" }, capacity: 1000 },
  ],
})
premiumAccess!: unknown;

compiles to product.entitlements:

{ "key": "premium_access",
  "capabilities": ["premium_tools"],
  "featureGates": { "premium_tools": true },
  "limits": [{ "dimension": "workflow_runs", "window": { "type": "named", "name": "month" }, "capacity": 1000 }],
  "meters": ["workflow_runs"] }

The limits on an @Entitlement use the raw IR limit shape ({ dimension, window, capacity }), not the ergonomic { rate, interval } shape that @Plan limits use. They are different surfaces: a plan's limits are authored ergonomically and normalized; an entitlement carries the IR shape verbatim.

How the pieces connect

@Resource("cron_jobs")            ← a counted thing
        ▲ capped by
@Capability("managed-cron")       ← bundles features, granted on plans
   includesFeatures: ["cron-jobs"]
        ▲ granted by
@Plan(...).grants:
   capabilityGrant("managed-cron", { limits: { cron_jobs: 10 } })

A subscriber on the starter plan holds managed-cron, which unlocks the cron-jobs feature and its routes, and may create up to 10 cron_jobs. See features & routes for the actions that maintain the count and plans & pricing for the full plan shape.