Co-authored-by: ben-davis <2607068+ben-davis@users.noreply.github.com> Co-authored-by: bensnell-stripe <47830399+bensnell-stripe@users.noreply.github.com> Co-authored-by: danhilltech <876990+danhilltech@users.noreply.github.com> Co-authored-by: kreese-stripe <215516483+kreese-stripe@users.noreply.github.com> Co-authored-by: qaisjp <923242+qaisjp@users.noreply.github.com> Co-authored-by: raubrey-stripe <185865758+raubrey-stripe@users.noreply.github.com> Co-authored-by: shirleyz-stripe <264516373+shirleyz-stripe@users.noreply.github.com> Co-authored-by: sjkaliski <602845+sjkaliski@users.noreply.github.com>
6.3 KiB
CLAUDE.md
This file provides guidance to Claude Code when working with code in this repository.
Project Overview
Link CLI — lets agents get secure, one-time-use payment credentials from a Link wallet. pnpm + Turborepo monorepo:
@stripe/link-sdk(packages/sdk): Repository interfaces, API implementations, types, and local storage. Entry:src/index.ts.@stripe/link-cli(packages/cli): Commander.js + Ink/React CLI that consumes@stripe/link-sdk. Entry:src/cli.tsx.
Commands
pnpm install # install dependencies
pnpm run build # build all packages (turbo)
pnpm run dev # watch mode
pnpm run test # run all tests
pnpm run typecheck # type-check all packages
pnpm biome check . # lint + format check (CI)
pnpm run check # lint + format with auto-fix
Run a single test:
cd packages/cli && pnpm vitest run src/utils/__tests__/line-item-parser.test.ts
The CLI integration tests in packages/cli/src/__tests__/cli.test.ts run against the compiled dist/cli.js. Run pnpm run build before running them if the source has changed.
Run the CLI locally:
node packages/cli/dist/cli.js <command>
Architecture
SDK Resources
Defined in packages/sdk/src/resources/interfaces.ts:
IAuthResource— device auth flow (initiate, poll, refresh)ISpendRequestResource— CRUD + request-approval for spend requests
CLI Command Structure
Commands in packages/cli/src/cli.tsx (Commander.js). Each has two output modes:
- Interactive (default): Ink/React components from
packages/cli/src/commands/ - JSON (
--output-json): JSON to stdout, errors as JSON to stderr with exit code 1
Commands: auth login|logout|status, spend-request create|update|retrieve|request-approval, payment-methods list, mpp pay, skill.
When adding a new command, always update configureRootHelp in packages/cli/src/utils/configure-root-help.ts to include it in the root help output. Pass the command as a parameter and add it to the appropriate section (or a new one).
When changing commands, flags, or schema descriptions, always update all four together: README.md, skills/link-cli/SKILL.md, the schema description strings in the relevant schema.ts file, and CLAUDE.md. These can easily drift apart.
Input: flags OR --json (mutually exclusive) via resolveInput in packages/cli/src/utils/json-options.ts.
InputSchema and .strict() gotcha: resolveInput validates input with z.object(...).strict(), which rejects any key not defined in the schema. This means every field that can be passed via --json must be defined in the command's InputSchema — including boolean flags like request_approval. If a field is only registered as a standalone .option() call, it will be rejected when using --json.
Always add new flags/options via InputSchema, never via standalone .option() calls. Define the field in the relevant InputSchema with its flag, schema, and description — registerSchemaOptions will register the Commander option automatically. Standalone .option() calls bypass schema validation and break --json input.
auth login
auth login --client-name <name>— optional flag to identify the agent or app; shown in the user's Link app as<name> on <hostname>. Defined inLOGIN_INPUT_SCHEMAinpackages/cli/src/commands/auth/schema.ts.
spend-request command
CLI command is spend-request (user-facing). Implemented in packages/cli/src/commands/spend-request/. The SDK interfaces (ISpendIntentRepository, CreateSpendIntentParams, UpdateSpendIntentParams) and API endpoints (/spend-intents) retain their original names.
Key input field notes:
- CLI input uses
payment_method_id; mapped topayment_detailswhen calling the SDK request_approvalis part ofCREATE_INPUT_SCHEMA(not a separate Commander flag) so it works via both--jsonand--request-approvalflagtestis part ofCREATE_INPUT_SCHEMA— pass--testor"test": truein JSON to create testmode credentials (real testmode SPT from test card data) instead of livemode onescontextrequires min 100 characters;amountis in cents with max 50000create --request-approvalandrequest-approvalboth show an approval URL in interactive mode and poll until approved/denied/expired/failed. In JSON mode (--output-json), they block silently and return the finalSpendRequestwhen complete.- The
request-approvalcommand now returnsSpendRequest(notRequestApprovalResponse) — output schema updated toSPEND_REQUEST_OUTPUT_SCHEMA cardcredentials includebilling_address(name, line1, line2, city, state, postal_code, country) andvalid_until(unix timestamp — when the card expires/stops working)
mpp pay
mpp pay <url> --spend-request-id <id> [--method <method>] [--data <body>] [--header <header>]...— completes the 402 flow: retrieves the spend request withinclude: ['shared_payment_token'], probes the URL, parses thewww-authenticatestripe challenge, builds theAuthorization: Paymentcredential, and retries.--headeris repeatable and uses"Name: Value"format.Content-Type: application/jsonis auto-applied when--datais provided; user-provided headers take precedence.- Requires an approved spend request with
credential_type: "shared_payment_token". The SPT is one-time-use — a failed payment requires a new spend request. - Implemented in
packages/cli/src/commands/mpp/— pay.tsx (logic), schema.ts (input/output schema), index.tsx (Commander registration).
Code Conventions
- ESM everywhere —
"type": "module"in all package.json files - Biome — 2-space indent, single quotes, organized imports
- tsup — ESM output, Node 18 target
- Vitest — test files in
__tests__/directories adjacent to source - TypeScript strict mode —
tsconfig.base.jsonat root - React 18 + Ink 5 for interactive rendering
conffor local auth token storage
Environment Variables
| Variable | Effect |
|---|---|
LINK_API_BASE_URL |
Override API base URL |
LINK_AUTH_BASE_URL |
Override auth base URL |
LINK_HTTP_PROXY |
Route all SDK requests through an HTTP proxy (requires undici installed) |