@farthershore/cli
v0.33.5
Published
FartherShore CLI — create and operate software businesses
Maintainers
Readme
@farthershore/cli
Create and operate FartherShore software businesses from the terminal.
Status: 0.33.5. Pre-1.0 — the command surface is stable but may still
change between minor versions. Pin an exact version in CI.
FartherShore lets you define a software business as code, then sells, meters,
and bills access to it at the edge. Business behavior — plans, pricing, limits,
routes and meters — is authored in your GitHub repo with
@farthershore/business
and reconciled through repository checks and the apply timeline after you push.
This CLI is the tool layer around that repo: provision a managed business repo,
validate it locally before you push, inspect publication state, and run
day-to-day operations (consumers, secrets, backends, webhooks, promo codes,
usage). It is designed to be safe for both humans and agents — every command
takes --format json for non-interactive scripting, and the MCP server exposes
the explicitly agent-operable subset of the CLI surface.
Install
npm install -g @farthershore/[email protected]Or run it directly with npx:
npx -p @farthershore/[email protected] farthershore --helpThe package also ships an MCP stdio server for agents:
npx -p @farthershore/[email protected] farthershore-mcpAuthentication
Start the device login. The CLI opens the complete authorization request in your browser without printing a code, then waits for you to approve access:
farthershore login
farthershore auth whoami --format jsonOn a headless machine, print the manual verification URL and user code without trying to open a browser:
farthershore login --headlessNormal login creates a user-bound CLI session. It uses your live role in each organization instead of copying a permission list into the credential. By default it follows all of your current and future organization memberships and all businesses in them. Normal login has no permission or scope choices: use an organization-scoped MakerToken when automation needs narrower access.
Choose the active organization for a command with --organization <id-or-slug>,
or save a default context:
farthershore auth organization list
farthershore auth organization use <id-or-slug>For a separately issued organization-scoped MakerToken, pipe it through bounded stdin:
printf %s "$FARTHERSHORE_MAKER_TOKEN" | farthershore login --token-stdinFARTHERSHORE_TOKEN accepts an organization-scoped MakerToken as an ephemeral
process override and is never persisted automatically. farthershore logout deletes the stored credential after
revoking the current user CLI session on the platform. Signing in again also
supersedes older user CLI sessions.
Membership and role changes take effect on the next authenticated request. A
restricted MakerToken remains available through --token-stdin or
FARTHERSHORE_TOKEN. Never write
credentials into the managed repository.
Quickstart
Create a managed business repo, author the business, validate it, and push:
# 1. Create the managed repo. Human output is exactly its URL.
REPO_URL=$(farthershore business create weather-api \
--idempotency-key <persisted-business-create-attempt-key>)
# 2. Clone it and author business/ from scratch.
git clone "$REPO_URL"
cd weather-api
# ...author business/ with @farthershore/business...
# 3. Validate the same way the PR check will, before pushing
farthershore validate --business weather-api
# 4. Push — the GitHub bot validates and records apply state
git push --set-upstream origin feature/pricing
farthershore apply-timeline list weather-api # inspect checks + apply state
# 5. Inspect accepted state, then use the CLI for platform operations.
farthershore business status weather-api --format json
farthershore operations list --format jsonDo not infer a successful apply from a push alone. A default-branch runtime-only change may publish after validation; an economic change is deferred to a GitHub Release. Preview-environment branches publish only to that environment. Inspect the repository checks and apply timeline for the actual outcome.
Plans, prices, limits, routes, and meters are repo-controlled: change them
by editing the program under business/ and pushing. Presentation and origin bindings
are platform-owned operating state. The CLI's
write commands cover operational state that lives outside the manifest
(consumers, secrets, backends, webhooks, promo codes, brand presentation).
Global flags
| Flag | Description |
| --------------------- | -------------------------------------------------------- |
| --api-url <url> | Override platform Core API URL |
| --env <environment> | Environment scope (production/prod/main aliases) |
| --format <format> | json for machine-readable output (default for non-TTY) |
| --no-input | Never prompt; use non-interactive, agent-safe paths |
| --version | Show version |
| --help | Show help |
Environment variables
| Variable | Description |
| ----------------------------------------- | ------------------------------------------------------------------------ |
| FARTHERSHORE_TOKEN | Ephemeral organization-scoped MakerToken; never persisted |
| FARTHERSHORE_API_URL | Platform Core API URL (default https://core.farthershore.com) |
| FARTHERSHORE_ENV | Default environment scope when --env is omitted |
| FARTHERSHORE_CONSUMER_TOKEN | Ephemeral portal consumer session for service-account; never persisted |
| FARTHERSHORE_ENVIRONMENT_ID | Portal environment UUID fallback for service-account |
| FARTHERSHORE_SUBSCRIBER_ORGANIZATION_ID | Subscriber organization UUID fallback for service-account |
| FS_CLI_CHANNEL | stage enables stage-channel commands for one invocation (see below) |
| FS_CLI_STAGE_HOSTS | Extra hosts (comma separated) the stage-channel gate treats as stage |
Stage-channel commands
A few operations exist only to service stage. farthershore business delete is
the only one today: deleting a business is unrecoverable, and there is no
builder reason to do it from a terminal against production — the dashboard owns
that path.
They are gated twice:
- Registration. The command is registered only when the CLI runs in the
stage channel.
make cli-stagewrites{"channel":"stage"}into~/.farthershore/config.json(make cli-prodwrites"prod"), andFS_CLI_CHANNEL=stagedoes the same for a single invocation. Without the marker the command is absent fromfarthershore business --helpand invoking it is an unknown-command error — so the published CLI, as a builder installs it, does not have it at all. - Target. Even in the stage channel, the command refuses when the api-url
it would call is not a stage host —
--api-url https://core.farthershore.com, orFARTHERSHORE_API_URLpointed at production. It exits 2 withCOMMAND_NOT_AVAILABLE_IN_PRODUCTIONbefore any request is made.
Delete a production business from the dashboard instead.
Commands
Browse platform documentation (no login)
Docs are a read-only virtual filesystem: collections are root folders, sidebar sections are directories, and pages are files. Listing a page shows its heading anchors. Paths come from the published docs index, not your working directory.
farthershore docs ls --format json
farthershore docs ls backend-sdk --format json
farthershore docs tree backend-sdk --format json
farthershore docs ls backend-sdk/connect-your-application --format json
farthershore docs read backend-sdk/connect-your-application/metering --format json
farthershore docs ls backend-sdk/connect-your-application/metering --format json
farthershore docs read backend/metering --section "choose-the-correct-metering-channel" --format json
farthershore docs search "runtime token" --collection backend-sdk --limit 10 --format json
farthershore docs collection backend-sdk --format jsonUse an anchor returned by docs ls <page> for --section. read also accepts the canonical slug or an
official docs URL with a #heading fragment, so links in skills can be used
directly. get aliases read; list aliases ls. A section includes all its
child headings and complete code fences. Full pages and collections are not
truncated; search results are bounded and include a total match count.
farthershore docs --stage ls selects stage; production is the default and
--api-url does not change the documentation origin. No credentials or
organization context are sent. JSON includes source URL and, for content reads,
the docs source commit. Human output is available with --format table.
The collection-aware llms.txt and corpus artifacts must be published first;
unavailable artifacts produce an error, not stale bundled guidance. Business
knowledge commands are separate authenticated resources.
Run farthershore <group> --help for the full flag set of any command.
Database-backed list commands use Core's shared query contract: repeat
--filter field=value for exact AND filters, pass one
--sort field[:asc|desc] (ascending when omitted), and use
--search <text> for case-insensitive text search. Core applies all three
before pagination; the CLI does not sort or filter a partial page locally.
Each command rejects fields outside its endpoint-specific allowlist shown by
--help.
farthershore create
Create local project components inside a managed builder repo. create api
scaffolds a starter backend into api/ by downloading the public Node template
tarball, then patches the repo root .gitignore.
farthershore create api
farthershore create api --path ../weather-api
farthershore create api --force
farthershore create api --node --ref v0.1.0 --format json--node is the default language today: Node (TypeScript + Express). --ref
accepts a template tag or branch name, trying tags first. More languages are
planned.
farthershore build
Compile the program under business/ to a Manifest IR envelope locally (default
output business-build.json). The CLI uses the Business SDK installed under
business/, falling back to a root install. This is local compilation only;
server-side validation and apply happen when you push business/** changes.
farthershore build
farthershore build --entry business/business.ts --out business-build.json
farthershore build --format jsonfarthershore validate
Run the same verdict the GitHub farthershore/validate PR check produces, before
you push. It builds the manifest twice and compares the IR hash (the determinism
check the build runner enforces), then — when you pass --business — submits the
IR for a server verdict that returns compile diagnostics, the semantic diff, and
an economic-change verdict. The server may retain a diagnostic compilation
record, but validation never accepts or publishes business state, so it is safe
to repeat and does not take an idempotency key.
farthershore validate # local build + determinism only
farthershore validate --business weather-api
farthershore validate --local-only --format jsonfarthershore business
Business lifecycle. Creation provisions a managed GitHub repo as the source of truth for business behavior and returns its URL. A new business starts as a DRAFT with repository tooling but no predefined business program.
farthershore business list --format json
farthershore business list --filter status=ACTIVE --sort updatedAt:desc --search weather --format json
farthershore business show weather-api --format json
farthershore business show weather-api --env preview --format json
# Is the slug free? (normalized, blocked-word and collision checked)
farthershore business subdomain-check weather-api --format json
farthershore business create weather-api \
--display-name "Weather API" \
--idempotency-key <persisted-business-create-attempt-key> \
--format json
farthershore business publish weather-api --format json --idempotency-key <persisted-business-publish-attempt-key>
farthershore business rollback weather-api wfe_previous --reason "bad release" --format json --idempotency-key <persisted-business-rollback-attempt-key>Deleting a business is stage only — the command is not registered in the
published CLI at all (see Stage-channel commands).
Run make cli-stage first; production businesses are deleted from the
dashboard.
farthershore business delete weather-api --yes --format jsonThe JSON result includes data.business, data.repoUrl, and recovery metadata.
Gather the product requirements, create the business/ program, and author its
plans, prices, limits, routes, and meters from scratch.
business update changes platform-owned fields such as display name,
description, icon, logo (icon/logo accept PNG, JPEG, or WEBP), and whether the
product is listed on the organization's public page
(https://farthershore.io/organization/<org-slug>, listed by default). Plans,
prices, limits, routes, and meters are repo-controlled and must be changed
through the Business SDK code path.
farthershore business update weather-api \
--display-name "Weather" \
--description "Weather API for agents" \
--icon-file ./brand/icon.png \
--logo-file ./brand/logo.webp \
--format json
farthershore business update weather-api \
--clear-icon --clear-logo --format json
farthershore business update weather-api \
--unlist-from-org-page --format jsonbusiness publish enforces the same go-live gates as the dashboard and returns
stable remediation errors when a prerequisite is missing.
business rollback enqueues a rollback of the specified prior publish workflow
and requires the exact business:rollback permission.
business rbac reads a business's Managed-RBAC state — the platform-owned
rbacEnabled flag. business rbac enable / disable toggle that flag (like
docsEnabled, it is platform-owned and never repo-authored); once enabled,
subscriber organizations manage roles in their portal. Both toggles are
idempotent. Subscriber role and assignment state is kept server-side on
disable, so re-enabling is a pure flag flip.
farthershore business rbac weather-api --format json
farthershore business rbac enable weather-api --format json
farthershore business rbac disable weather-api --format jsonbusiness rbac subjects list lists the custom permission vocabulary: subjects
whose <subject>:<verb> permissions are grantable to subscriber roles
alongside the route-derived catalog. Subjects are repo-owned — declared via
a permission-carrying fs.group(id, routes, { permission: { verbs, escalatory,
description } }) in the business repo's business/ folder and synced from the
accepted spec. To change them, edit the group declaration, run
farthershore validate, and push; there are no CLI write commands.
farthershore business rbac subjects list weather-api --format jsonfarthershore apply-timeline
Inspect repo-backed applies — PRs, pushes, releases, checks, semantic diffs, and apply state — for a business.
farthershore apply-timeline list weather-api --format json
farthershore apply-timeline inspect weather-api 42 --format json # by id, PR #, branch, or SHAfarthershore env
Manage preview/production environments. Production is the default scope when
--env is omitted (production, prod, and main are aliases).
farthershore env list weather-api --format json
farthershore env list weather-api --filter branch=env/preview --sort createdAt:desc --search preview --format json
farthershore env create weather-api --name preview --branch env/preview --format json
farthershore env delete weather-api preview --yes --format jsonfarthershore organization
Manage organization members and the exact platform-permission roles assigned to them. Built-in and custom roles use the same list contract.
farthershore organization role list <organizationId> --filter builtIn=true --sort name --search security --format json
farthershore organization members <organizationId> --filter roleKey=auditor --sort email:asc --search person --format json
# Primary owner only; hands ultimate authority to another existing member.
farthershore organization ownership-transfer <organizationId> <newOwnerUserId> --yes --format json --idempotency-key <persisted-organization-ownership-transfer-attempt-key>Selecting the default organization is a local credential concern, not an API
call: farthershore auth organization use <id-or-slug> changes the stored
default, and --org <id> overrides it for one command.
farthershore token
Create and administer organization-owned MakerTokens. These commands require a
signed-in user CLI session (farthershore login); an existing MakerToken cannot
list, mint, approve, rotate, revoke, or otherwise administer credentials. The
entire group is CLI-only and is deliberately absent from farthershore-mcp.
# Exact permissions a human may delegate — read this before choosing --permissions.
farthershore token permission-catalog --org --format json
# Omit --businesses to snapshot ALL current and future org businesses.
farthershore token create deploy-bot --org \
--permissions '["business:read","business:publish"]' \
--businesses business_1,business_2 \
--idempotency-key org-token-create-2026-08-11 \
--format json
farthershore token list --org --format json
farthershore token approvals --org --format json
farthershore token approve <approvalId> --org --format json --idempotency-key <persisted-token-approve-attempt-key>
farthershore token approve <approvalId> --org \
--idempotency-key <persisted-token-approve-attempt-key> \
--permissions '["business:read"]' --format json # trim on approval
farthershore token deny <approvalId> --org --format json
farthershore token update <tokenId> --org \
--permissions '["business:read"]' \
--idempotency-key org-token-update-2026-08-11 --format json
farthershore token rotate <tokenId> --org --format json --idempotency-key <persisted-token-rotate-attempt-key>
farthershore token revoke <tokenId> --org --yes --format jsonCreation and updates that exceed the caller's live authority return
data.status: "PENDING", an approval id, and no plaintext credential. A
direct ACTIVE create, an approved CREATE, or a rotation returns data.token
exactly once; store it immediately. Human output follows the same rule: it
prints plaintext only for an ACTIVE one-time-secret response and says explicitly
when a PENDING request minted nothing.
Create and update require --idempotency-key. Persist the key before the first
dispatch and reuse it only when repeating that exact logical request after an
interrupted invocation. The CLI never generates a key: a process-local key
would be lost across the restart where retry safety matters most.
farthershore stripe
Read the Stripe Connect account a business bills through (a per-business
override when one exists, otherwise the organization default) and remove a
per-business override. Both require a signed-in owner session; a MakerToken is
rejected. Connecting Stripe is a browser-only onboarding handshake with Stripe,
so there is deliberately no stripe connect command — do it from the
dashboard and confirm with stripe status.
farthershore stripe status weather-api --format json
farthershore stripe disconnect weather-api --yes --format jsonstripe disconnect is refused while any subscription on the business is still
money-bearing.
farthershore service-account
Manage service accounts owned by a subscriber organization. This is a separate
subscriber-plane trust boundary: it requires a current identity-provider portal
consumer session in FARTHERSHORE_CONSUMER_TOKEN, plus the exact environment
and subscriber organization context. The consumer bearer has no argv flag and
is never exchanged or persisted by the CLI. A builder login or MakerToken cannot
substitute for it.
export FARTHERSHORE_CONSUMER_TOKEN='<current portal session token>'
export FARTHERSHORE_ENVIRONMENT_ID='<environment UUID>'
export FARTHERSHORE_SUBSCRIBER_ORGANIZATION_ID='<subscriber organization UUID>'
farthershore service-account list <businessId> --format json
farthershore service-account create <businessId> deploy-bot \
--permissions '["route:read","route:write"]' \
--scopes '["production"]' \
--idempotency-key sa-create-2026-08-11 --format json
farthershore service-account update <businessId> <serviceAccountId> \
--permissions '["route:read"]' \
--idempotency-key sa-update-2026-08-11 --format json
farthershore service-account approvals <businessId> --format json
farthershore service-account approve <businessId> <approvalId> \
--permissions '["route:read"]' --format json # optional trim
farthershore service-account deny <businessId> <approvalId> --format json
farthershore service-account rotate <businessId> <serviceAccountId> --format json --idempotency-key <persisted-service-account-rotate-attempt-key>
farthershore service-account revoke <businessId> <serviceAccountId> --yes --format jsonPass --environment-id and --subscriber-organization to override the two
context environment variables for one command. PENDING create/update responses
never print plaintext. ACTIVE creates
and rotations print the one-time key once. Create, update, and rotate require a
caller-persisted key, just like one-time-secret org-token operations. A replayed
success includes meta.idempotency.replayed: true; follow it with a list read
before reporting current state.
This group is direct CLI-only and deliberately has no MCP projection: the MCP operation registry carries builder principals, not portal consumer sessions.
farthershore limit
Manage subscriber-owned usage limits with a portal consumer session. list
reads the current limits; set creates a limit when --limit-id is omitted and
updates that limit when --limit-id is present; remove deletes a limit.
farthershore limit list <business-id> --format json
farthershore limit set <business-id> \
--quantity requests --mode BLOCK --scope ORG --units 10000 \
--format json
farthershore limit set <business-id> \
--limit-id <limit-id> --mode NOTIFY --units 20000 \
--notify-at 0.8 --format json
farthershore limit remove <business-id> <limit-id> --format jsonChanging a limit's scope, subject, or quantity requires removing and recreating the limit with the new target.
Every limit command requires FARTHERSHORE_CONSUMER_TOKEN, containing the
current portal consumer session token. Pass --environment-id and
--subscriber-organization, or set their respective fallbacks
FARTHERSHORE_ENVIRONMENT_ID and
FARTHERSHORE_SUBSCRIBER_ORGANIZATION_ID. These subscriber-portal credentials
are separate from the organization-scoped MakerToken used by the rest of the
CLI and are never persisted automatically.
farthershore plan
Read code-managed plans. The CLI does not create, update, or delete plan definitions — edit the Business SDK program for that.
farthershore plan list weather-api # table (default in TTY)
farthershore plan list weather-api --format jsonfarthershore frontend
Managed Frontend Hosting status, rollback, and a local preview. Builds are
Git-triggered: production builds on a GitHub Release and preview environments
build on pushes to their environment branch. preview runs the generated
frontend/'s vite dev with an injected window.__FS_CONFIG__ shim so the
portal renders locally exactly as it serves in production. Pass --mock to
inject { mock: true } instead of Core/Clerk config for local page inspection
with placeholder data and auth bypassed.
farthershore frontend status weather-api --format json
farthershore frontend rollback weather-api --release-id <hash> --format json
# Local preview (shells out to vite; needs a frontend/ project)
farthershore frontend dev # hot-reloading dev server, mock mode by default
farthershore frontend preview # production build served as-is, mock mode by default
farthershore frontend dev --live # against the real platform
farthershore frontend preview --core-url http://localhost:8787
# Local preview signed in as a test persona (hot reload against the real platform)
farthershore frontend dev --live --business acme --env preview --persona alice
farthershore frontend dev --live --business acme --env preview --persona persona_123 --port 4321--live --business --env --persona (all three required, not combinable with
--mock or --core-url) opens http://localhost:<port> (default 5173)
already signed in as that test persona, exactly as the hosted portal would
be. The CLI issues a short-lived, origin-bound preview lease from Core and
holds it only in its own process memory; Vite runs on a private random
loopback port behind a CLI-owned proxy that attaches the lease to portal
requests and serves the secret-free sign-in bridge. Nothing secret ever
reaches the browser URL, DOM, storage, or logs — the browser only ever holds
the same HttpOnly session cookie the hosted portal uses. The lease renews
automatically while the command runs and is revoked when it exits (Ctrl-C
included); a lease that cannot be revoked expires within five minutes. Core
is always the one selected for the authenticated CLI (--api-url /
FARTHERSHORE_API_URL).
farthershore persona
Create temporary subscriber users in a test-strategy environment so an agent can exercise the same customer RBAC, browser session, and gateway paths as a human. The Business SDK contributes raw permissions; the subscribing organization composes those permissions into its own product roles.
# First persona creates and owns a temporary subscriber workspace.
farthershore persona bootstrap weather-api --env preview --plan pro --format json --idempotency-key <persisted-persona-bootstrap-attempt-key>
farthershore persona list weather-api --env preview --format json
farthershore persona login weather-api <ownerPersonaId> --env preview --format json
# Join the same subscriber after its owner has enabled subscriber RBAC and
# created roles/defaults through the normal customer RBAC surface.
farthershore persona bootstrap weather-api --env preview --plan pro \
--subscriber-id <subscriberId> --account-role member --role viewer \
--format json --idempotency-key <persisted-member-bootstrap-attempt-key>
farthershore persona rotate weather-api <personaId> --env preview --format json --idempotency-key <persisted-persona-rotate-attempt-key>
farthershore persona delete weather-api <personaId> --env preview --format jsonBootstrap and rotation return a key once. login sends the 60-second,
single-use handoff only in the browser URL fragment to the platform-owned
/persona-sign-in bridge. The bridge establishes an HttpOnly browser session
and returns to the exact original portal path, query, and fragment. CLI output
contains portal metadata but never the handoff or a session bearer. Product
role keys must already exist in that subscriber's role catalog; omit --role to use its
configured default. Deletion tears down the temporary user and credential, and
deleting the environment also removes the remaining persona-owned workspace.
After an environment-branch apply, existing personas remain available but are
detached from the superseded subscription. Use persona login with the same
persona id and select a plan from the new branch contract; the CLI does not
fall back to a production plan. The old raw test key stays invalid. After the
persona is reattached, run persona rotate to mint a replacement key for
gateway testing; its product roles and explicit scope ceiling are preserved.
farthershore usage
Read recent usage off the management API.
farthershore usage summary weather-api --format jsonfarthershore consumer
Manage live business users. These are operational actions, not repo-authored behavior.
farthershore consumer list weather-api --format json
farthershore consumer block weather-api <subscriberId> --yes --format json
farthershore consumer remove weather-api <subscriberId> --yes --format jsonUse consumer list first to find a subscriberId. block suspends a user and
revokes active API keys. remove is irreversible and tears down subscriber state
across billing, edge credentials, and subscriptions.
farthershore variables
Manage platform-owned variables. The name is the class: an FS_PUBLIC_ prefix
makes a value public (inlined into the frontend bundle, readable by every
visitor); any other name is a write-only secret — available to the isolated
managed build (leak-scanned from its artifact) and injected by Gateway for any
compiled integration that references it.
farthershore variables list weather-api --format json
printf '%s' "$SENTRY_AUTH_TOKEN" | farthershore variables set weather-api \
SENTRY_AUTH_TOKEN --format json --idempotency-key <persisted-sentry-variable-attempt-key>
printf '%s' "$POSTHOG_PROJECT_KEY" | farthershore variables set weather-api \
FS_PUBLIC_POSTHOG_KEY --format json --idempotency-key <persisted-posthog-variable-attempt-key>
farthershore variables revoke weather-api POSTHOG_SECRET --yes --format json --idempotency-key <persisted-variables-revoke-attempt-key>
farthershore variables rm weather-api POSTHOG_SECRET --yes --format json --idempotency-key <persisted-variables-rm-attempt-key>There is no builder-managed public-variable surface and values are never revealed after write. Rotation preserves the delivery phase; changing phase requires revoke, delete, and recreate.
farthershore backend
Create bring-your-own backends and provision runtime tokens for your upstream
services. Only token hashes are stored; the raw token is returned once and should
be deployed as FS_RUNTIME_TOKEN.
farthershore backend list weather-api --format json
farthershore backend create weather-api \
--name "Production API" \
--origin-url https://api.example.com \
--idempotency-key <persisted-backend-create-attempt-key> \
--format json
farthershore backend bind weather-api api \
--env preview-42 \
--origin-url https://api-pr-42.example.com \
--format json
farthershore backend tokens create weather-api --backend <backendId> --format json --idempotency-key <persisted-backend-tokens-create-attempt-key>
farthershore backend tokens rotate weather-api <tokenId> --format json --idempotency-key <persisted-backend-tokens-rotate-attempt-key>
farthershore backend tokens revoke weather-api <tokenId> --yes --format jsonPair the token with
@farthershore/backend in
your upstream:
import { fartherShore } from "@farthershore/backend";
const fs = fartherShore.initFromEnv();
export async function POST(request: Request) {
const url = new URL(request.url);
const body = await request.clone().arrayBuffer();
const ctx = await fs.verifyRequest({
method: request.method,
path: url.pathname,
query: url.search,
headers: request.headers,
body: new Uint8Array(body),
});
const result = await runWorkflow(await request.json());
await ctx.report({
meter: "tokens_used",
values: { tokens_used: result.tokensUsed },
});
return Response.json(result);
}farthershore webhook
Provision outbound webhook endpoints and inspect delivery health. Endpoints are platform-owned operate records: they never live in the managed repo, so these writes work the same for every business regardless of repo linkage.
farthershore webhook list weather-api --format json
farthershore webhook create weather-api \
--url https://hooks.example.com/farthershore \
--events subscription.created,payment.failed \
--idempotency-key <persisted-webhook-create-attempt-key> \
--format json
farthershore webhook update weather-api <webhookId> --disable --format json
farthershore webhook test weather-api <webhookId> --idempotency-key <persisted-test-attempt-key> --format json
farthershore webhook trigger weather-api <webhookId> --type payment.failed --idempotency-key <persisted-trigger-attempt-key> --format json
farthershore webhook deliveries weather-api <webhookId> --limit 20 --format json
farthershore webhook rotate weather-api <webhookId> --format json --idempotency-key <persisted-webhook-rotate-attempt-key>
farthershore webhook delete weather-api <webhookId> --yes --format jsonwebhook create and webhook rotate return the signing secret once; store it
in the receiving app. In human mode they also print it as an
FS_WEBHOOK_SECRET= line plus a createWebhookHandler snippet.
webhook test sends the plain webhook.test ping. webhook trigger --type
sends a signed, realistic sample of one catalog event (the deliveries log
records it under that type) so every handler branch can be exercised locally.
For a receiver on your machine, webhook listen is the Stripe-CLI-style loop:
it opens a Cloudflare quick tunnel to --forward-to, creates a temporary
endpoint on it, prints the endpoint id / tunnel URL / (with --print-secret)
the FS_WEBHOOK_SECRET= line, tails deliveries as
time type status responseStatus id, and deletes the endpoint on Ctrl-C.
farthershore webhook listen weather-api \
--forward-to http://localhost:3000/webhooks/farthershore \
--print-secret --trigger payment.failed
farthershore webhook listen weather-api --forward-to localhost:3000/webhooks \
--events subscription.created,payment.failed --format jsonlisten needs cloudflared — bundled as an optional
@farthershore/cloudflared-<platform> dependency, or on your PATH. It has no
MCP tool (long-running, process-owning). A listener killed hard leaves an
endpoint with a *.trycloudflare.com URL; webhook delete --yes removes it.
farthershore promo-code
Manage checkout promo codes (operational state, not part of the manifest).
farthershore promo-code list weather-api --format json
farthershore promo-code create weather-api \
--code LAUNCH25 --kind percent_off --percent 25 --duration-months 3 \
--idempotency-key <persisted-promo-code-create-attempt-key> \
--plan <planId> --format json
farthershore promo-code create weather-api \
--idempotency-key <persisted-promo-code-create-attempt-key> \
--code SAVE500 --kind amount_off --amount-cents 500 --duration-months 1 --format json
farthershore promo-code archive weather-api <promoCodeId> --format json
farthershore promo-code reactivate weather-api <promoCodeId> --format jsonBecause a Stripe coupon change requires a complete discount spec, promo-code
update requires --kind, --duration-months, and the amount flag for that kind
whenever you change the code, amount, dates, plan scope, or redemption limits.
Use --all-plans to clear plan scoping.
Farther Shore agent skills
Install or refresh the platform-verified skills bundle together. The platform
pins this immutable release, and CI plus a daily repository check compare it to
GitHub's latest stable release so the guidance cannot silently drift.
This command requires @farthershore/cli 0.33.5 or newer.
set -euo pipefail
CLI_VERSION=$(farthershore --version)
printf '%s' "$CLI_VERSION" | node -e 'let v=""; process.stdin.on("data", c => v += c).on("end", () => { const m = /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:\+[0-9A-Za-z.-]+)?$/.exec(v.trim()); if (!m || !(+m[1] > 0 || +m[2] > 33 || (+m[2] === 33 && +m[3] >= 5))) { console.error("Stop: CLI 0.33.5 or newer is required; ask the human to upgrade."); process.exitCode = 1; } })'
farthershore skills install --help
farthershore skills installIf either prerequisite fails, stop and ask the human to run
npm install -g @farthershore/[email protected], then repeat the checks.
Do not install or upgrade global tooling autonomously.
The Farther Shore CLI downloads the exact installer archive and verifies this SHA-512 before it extracts or executes any installer code.
farthershore operations
Print the machine-readable action boundary: which operations are repo-authored
(contract) and which are CLI/API operations (operate).
farthershore operations list --format jsonErrors and exit codes
In --format json mode, every command prints a single canonical envelope to
stdout — { ok, op, data } on success, or { ok: false, op, error } on failure,
where error carries a stable code, message, HTTP status, a retryable
flag, and a remediation hint when one is registered. Diagnostics go to stderr.
In table mode, failures print Error [CODE]: message plus a Hint: line. The
bracketed code is stable across releases — quote it in support threads.
Exit codes are a branchable taxonomy so a script can tell failure classes apart without parsing text:
| Exit | Meaning |
| ---- | -------------------------------------------------------------- |
| 0 | Success |
| 2 | Validation error (HTTP 400/422) — fix your input |
| 3 | Auth / permission error (401/403) — re-authenticate |
| 4 | Conflict / managed-by-code (409) — change it in the repo |
| 5 | Server error (5xx) — retry only when error.retryable is true |
| 1 | Any other failure (local error, 402/404, argument errors, …) |
CI and agent usage
Authenticate before unattended work, or supply an organization-scoped
MakerToken through FARTHERSHORE_TOKEN. Device login waits for human approval; use
--headless when the CLI cannot open a browser. farthershore build and
farthershore validate --local-only need no network or auth and are safe to
run in CI.
MCP server
The MCP server (farthershore-mcp) projects its tools from the same operation
registry that defines the CLI commands. Every MCP tool has a CLI sibling, but
not every CLI command is exposed through MCP. Tool names use the fs_* prefix
and cover only operations explicitly marked agent-operable in that registry.
Organization, role, member, invitation, and org MakerToken administration
requires a live-user CLI session and is not projected into MCP; audit logs,
notifications, and apply timelines are also CLI-only.
farthershore-mcpLearn more
- Platform documentation: farthershore.com
- Author business behavior:
@farthershore/business - Report usage from your backend:
@farthershore/backend
License
MIT
