This package is the amp CLI: the human- and agent-facing surface over the
Amplitude Developer API. It is published as a standalone package, so treat
everything here as public and hold it to a high bar.
The Amplitude Developer API OpenAPI spec is the contract; this CLI is a thin,
generated client over it. The CLI manifest and bundled spec under
src/generated/ and openapi/bundled/ are generated artifacts — never edit
them by hand.
These break ties when a decision is ambiguous. They are deliberately aligned with the Developer API golden standards.
The best surface needs no explanation. A user should be able to guess the next command and never get surprised by what one does.
What good looks like
- Discoverable help:
amp help→ surfaces →amp <surface>→amp <cmd> --help. - Consistent verbs across surfaces (
list,get,create,update,archive). - Safe defaults: destructive actions confirm (interactive
y/N, or--yesin scripts); reads are free. - Errors are actionable — they say what to do next, not just what failed.
- Conventions users already expect work:
--version/-v,--help/-h.
Anti-patterns
- A flag whose effect you can't infer from its name (e.g. a
--dry-runthat still performs the write). - Requiring the README to use a command safely.
This source is public. Readers judge Amplitude by it, so optimize for clarity, not just function.
What good looks like
- Small, single-purpose modules with names that read like a table of contents.
- Public-facing code and docs use familiar, widely understood names instead of coined internal jargon.
- Generated code is quarantined under
src/generated/and never hand-edited. - Validate untrusted input (API responses, saved credentials, user JSON) with schemas, not ad-hoc coercion.
Anti-patterns
- A grab-bag module that mixes parsing, auth, transport, and routing.
- TODOs, dead code, or aspirational claims in shipped files or the README.
Cover pure logic exhaustively and protect the safety-critical paths. Skip tests whose only purpose is coverage of trivial glue.
What good looks like
- Pure functions (arg parsing, request building, output formatting) are unit tested.
- Security-relevant behavior has explicit tests: token precedence, the
destructive-action gate, and credential file permissions (
0600). - Test files mirror their source module.
Anti-patterns
- Mocking away the exact branch you mean to verify.
- No coverage on the code that can delete data or leak a secret.
Every command is read by a person at a terminal and by an agent over a pipe. Optimize each for what it needs: humans want maximal visibility and readability; agents want minimal characters.
What good looks like
- Interactive (TTY) output is formatted for scanning: aligned tables, short summaries, collapsed redundant columns, and color used only as emphasis.
- Piped / non-interactive output is compact and lossless — the full data with no decoration, no indentation, and nothing the caller must strip.
- The two formats carry the same information; only the presentation differs.
--jsonalways yields machine-parseable output; piping never changes the meaning of a command, only its verbosity.
Anti-patterns
- Spending agent tokens on pretty-printing, banners, color codes, or repeated values that carry no extra information.
- Truncating or dropping data on the piped path to save space (terseness must never cost correctness).
- Human-only adornments (spinners, prompts, ANSI codes) leaking into non-interactive output.
The rubric: the CLI optimizes for the agent characteristics that underpin MCP — self-describing, semantic-not-prescriptive, structured/typed, uniform, progressive, actionable-failure, stable-identity, explicit — expressed CLI-natively rather than as a bolt-on protocol.
Edit / add / remove a command checklist — each item names the guard that enforces it:
- API commands come from the OpenAPI spec → regenerate (
pnpm generate:cli); the manifest is the source of truth, never hand-editsrc/generated/**. (verify:generated) - Auth/meta commands are hand-authored in
catalog.ts'sAUTH_COMMANDS, kept in sync with the routing incli.ts. (catalog.test.tsparity;auth-flag-coverage.test.tsproves handlers only read declared/global flags, so the misplaced-flag reject can't false-positive) - Every catalog command appears in help + JSON.
(
help-drift.test.ts/help-json-drift.test.ts) - Only authoritative/sourced fields belong in the catalog — no invented state
(e.g. no method-derived
destructive). Adding a serialized field tripscatalog-shape.test.ts. Scopes come from the OpenAPIx-required-scopesextension. - Describe behavior semantically; no audience-targeting or scripted recipes in
summaries, descriptions, hints, or help. (
semantic-copy.test.ts) - Reader-aware output: prose at a TTY, JSON when piped or with
--json(shouldUseJsonOutput/formatJsonOutput). - Failures: a structured JSON error on stderr plus a differentiated exit code
via
CliError— never a bareErrorfor a user-facing failure. Sanctioned exceptions (e.g. a TTY-only cancellation) carry a// plain-error-ok: <reason>marker on the throw. (exit-code map inerror-contract.test.ts; everythrow new Error(without that marker failscli-error-usage.test.ts)- Exception: the device-flow verbs
auth login start/pollalways emit their{status,message,…}envelope on stdout (it is the command's primary output, relayed to the user), signalling failure via the exit code;polluses exit 75 for a still-pendingauthorization. A thrownCliErroron these paths keeps its ownerror_code/exit code.
- Exception: the device-flow verbs