Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,41 @@ readability; agents want minimal characters.
never cost correctness).
- Human-only adornments (spinners, prompts, ANSI codes) leaking into
non-interactive output.

## Conventions for changing commands (and how they're enforced)

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-edit `src/generated/**`.
(`verify:generated`)
- Auth/meta commands are hand-authored in `catalog.ts`'s `AUTH_COMMANDS`, kept
in sync with the routing in `cli.ts`. (`catalog.test.ts` parity;
`auth-flag-coverage.test.ts` proves 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 trips
`catalog-shape.test.ts`. Scopes come from the OpenAPI `x-required-scopes`
extension.
- 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 bare `Error` for 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 in `error-contract.test.ts`; every
`throw new Error(` without that marker fails `cli-error-usage.test.ts`)
- Exception: the device-flow verbs `auth login start`/`poll` always emit
their `{status,message,…}` envelope on **stdout** (it is the command's
primary output, relayed to the user), signalling failure via the exit code;
`poll` uses exit 75 for a still-`pending` authorization. A thrown `CliError`
on these paths keeps its own `error_code`/exit code.
41 changes: 13 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,36 +41,37 @@ npx @amplitude/developer-cli help

## Authentication

Run `amp auth login` to authenticate via the OAuth device flow. Creating a
profile is force-explicit — name it and pick its environment:
Run `amp auth login` to authenticate via the OAuth device flow. Omit
`--profile` and the CLI targets `default` — the implicit profile used when you
don't name one. Picking a region stays explicit:

```bash
amp auth login --profile prod --env prod # device flow → save + activate
amp auth login --region us # device flow → "default" profile
amp auth status # active credential, type, expiry
amp context
```

Profiles bind a credential to an environment (its `base_url`), so a staging
token can never be sent to prod. Add more and switch between them:
Profiles bind a credential to a region (its `base_url`), so an EU token can
never be sent to prod. Name one explicitly when you want more than one:

```bash
amp auth login --profile staging --env staging # activates staging
amp auth login --profile eu --region eu # activates the EU profile
amp auth use prod # switch back (no re-auth)
amp auth list # * marks the active profile
amp logout --profile staging # remove one
amp logout --profile eu # remove one
amp logout --all # remove every profile
```

A bare `amp auth login` re-authenticates the active profile in place. Profiles
are saved to `~/.amplitude/amp/credentials.json` (0600).

Prefer a Personal Access Token? `amp auth pat --with-token --profile <name> --env <env>`
reads a PAT from stdin (or a masked prompt at a terminal) and saves it as a
profilesame force-explicit create rule, same store, just a different
credential type. `--with-token` is required.
Prefer a Personal Access Token? `amp auth pat --with-token --region <us|eu>` reads a
PAT from stdin (or a masked prompt at a terminal) and saves it as a profile —
`--profile` optional (defaults to `default`), same force-explicit create rule,
same store. `--with-token` is required.

```bash
echo "$PAT" | amp auth pat --with-token --profile ci --env prod
echo "$PAT" | amp auth pat --with-token --region us
```

For CI or a one-off shell, set a raw token — it overrides stored profiles:
Expand All @@ -82,22 +83,6 @@ export AMP_TOKEN=amp_... # amp_… is treated as a PAT, anything else a b
`AMP_PROFILE` selects a stored profile by name; `amp auth token` prints the
active access token to stdout (`TOKEN=$(amp auth token)`).

## Base URL

Defaults to production:

```text
https://developer-api.amplitude.com
```

Override for staging or a local server:

```bash
export AMP_API_BASE_URL=http://localhost:3036
# or
amp --base-url http://localhost:3036 context
```

## Examples

```bash
Expand Down
58 changes: 28 additions & 30 deletions docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,42 +5,42 @@ OpenAPI spec. A handwritten runtime in `src/cli.ts` maps flags to HTTP requests.

## Authentication

Authenticate via the OAuth device flow and save the result as a named profile.
Creating a profile is force-explicit — name it and pick its environment:
Authenticate via the OAuth device flow and save the result as a profile. Omit
`--profile` and the CLI targets `default` — the implicit profile used when you
don't name one. Picking a region stays explicit:

```bash
amp auth login --profile prod --env prod
amp auth login --region us
```

That runs the device flow against the chosen environment's Developer API, saves
That runs the device flow against the chosen region's Developer API, saves
the token to `~/.amplitude/amp/credentials.json` (0600), and activates the
profile. A
profile binds a credential to an environment (`base_url`), so a staging token
can never be sent to prod.
profile. A profile binds a credential to a region (`base_url`), so an EU
token can never be sent to prod.

```bash
amp auth login --profile staging --env staging # activates staging
amp auth login --profile eu --region eu # activates the EU profile
amp auth use prod # switch (no re-auth)
amp auth list # * marks the active profile
amp auth status # type, base URL, expiry
amp logout --profile staging # remove one
amp logout --profile eu # remove one
amp logout --all # remove every profile
```

A bare `amp auth login` re-authenticates the active profile in place (env from
its record). `--env` maps `local|dev|staging|prod|prod-eu` to a base URL; pass
`--base-url <url>` instead to target an arbitrary host.
A bare `amp auth login` re-authenticates the active profile in place (region
from its record). `--region` maps `us|eu` to a base URL.

To use a Personal Access Token instead of the device flow:

```bash
echo "$PAT" | amp auth pat --with-token --profile ci --env prod # stdin
amp auth pat --with-token --profile ci --env prod # masked prompt at a TTY
echo "$PAT" | amp auth pat --with-token --region us # stdin → "default" profile
amp auth pat --with-token --profile ci --region us # name it; masked prompt at a TTY
```

`--with-token` reads the PAT from stdin when piped (the agent / CI path) or a
masked prompt at a terminal (the human path). Same force-explicit create rule
and store as `login`; the credential is saved as `{ "type": "pat" }`.
`--with-token` reads the PAT from stdin when piped, or from a masked prompt at a
terminal. Same rules as `login`: `--profile`
is optional (defaults to `default`) and `--region` is required to create a
profile; the credential is saved as `{ "type": "pat" }`.

`--with-token` is mandatory: it makes the supply-an-existing-PAT path explicit
and keeps the bare `amp auth pat` verb reserved.
Expand All @@ -54,7 +54,7 @@ profile; `amp auth status` announces when it is in effect.

```bash
export AMP_TOKEN=amp_... # one-off / CI; overrides stored profiles
export AMP_PROFILE=staging # select a stored profile by name
export AMP_PROFILE=eu # select a stored profile by name
```

Accepted forms for `--token` / `AMP_TOKEN`:
Expand All @@ -78,15 +78,20 @@ scopes below document what each command needs.
| `context`, `projects list` | `read:projects` |
| `events *` | `read:taxonomy`, `write:taxonomy` |
| `flags *` | `read:flags`, `write:flags` |
| `charts *` | `read:analytics` |

Route-level scopes are defined on each OpenAPI operation (`x-required-scopes`).

When adding new CLI scopes, ensure the OAuth client used for `amp auth login`
allows those scopes before default login requests them. This requires an
out-of-band update on Amplitude's side — contact Amplitude if your integration
needs additional scopes.

## Global flags

| Flag / env | Purpose |
| --------------------------------------- | ------------------------------------------ |
| `--base-url` / `AMP_API_BASE_URL` | API host (default: prod) |
| `--env <env>` | Friendly env name → base URL |
| `--region <us\|eu>` | Data region name → base URL |
| `--profile <name>` / `AMP_PROFILE` | Select a stored profile |
| `--token` / `AMP_TOKEN` / saved profile | Auth token |
| `--json` | Force raw JSON output (default when piped) |
Expand All @@ -97,7 +102,7 @@ Route-level scopes are defined on each OpenAPI operation (`x-required-scopes`).
## Help and output

```bash
amp help # product surfaces (context, projects, events, flags, …)
amp help # product surfaces (context, projects, events, flags, charts, …)
amp help flags # commands within a surface
amp flags list --help # flags and examples for one command
amp version
Expand Down Expand Up @@ -125,19 +130,12 @@ Manual checklist:
3. **Projects** — `amp projects list`
4. **Flags read** — `amp flags list --project <id> --limit 5`
5. **Flags write** — create → get → update description → archive dry-run → archive
6. **Events** — list → create → update → (optional delete with `--yes`)
6. **Charts read** — `amp charts list --project <id> --limit 5`
7. **Events** — list → create → update → (optional delete with `--yes`)

Known issue: `flags update --enabled false` fails for deployment-less flags.
Avoid that path in smoke tests until it is fixed.

## Local server

Point at a running local server:

```bash
amp --base-url http://localhost:3036 context
```

## Generated files

Do not edit by hand:
Expand Down
Loading
Loading