@honest-pitches/cli
v0.5.5
Published
The Honest Pitches CLI — a thin argv shim around @honest-pitches/pitch-sdk. v0.5.5 ships pitches create/get/list/update/transition/scaffold/media and frameworks list/sections. Auth via PITCHER_API_KEY (hosted MCP) or PITCHER_SESSION_JWT. List is force-sco
Readme
@honest-pitches/cli (Honest Pitches CLI)
Install:
npm install -g @honest-pitches/cli
# or, for a one-shot test:
npx @honest-pitches/cli pitches listCheck the installed version:
hp --version
# or:
hp -V
# Prints: `hp 0.5.1` (and exits 0; no auth required)The hp CLI is the third of three customer-facing surfaces for the
Honest Pitches pitcher stack. It is a thin argv shim around the
@honest-pitches/pitch-sdk
(in jwt mode) and around the
@honest-pitches/mcp
HTTP transport (in apiKey mode). The CLI does not implement pitch
logic; it delegates every command to the SDK or the MCP.
| Agent surface | Best for | Underlying transport |
| --- | --- | --- |
| @honest-pitches/pitch-sdk (direct) | Programmatic; build on top of | TablesDB REST via the SDK |
| @honest-pitches/cli (this package) | Shell-using agents (Aider, Codex, dev terminal) | Calls the SDK in jwt mode, or the MCP in apiKey mode |
| @honest-pitches/mcp (MCP server) | MCP-aware agents (Cursor, Claude Desktop) | Tools call into the SDK; the SDK does the REST |
v0.5.0 command surface (7 commands)
hp pitches create [--framework <id>] [--slug <s>] [--title <t>] [--cta-url <u>] [--creator-id <c>] [--input -] [--dry-run] [--json] [...]
hp pitches get <id> [--json]
hp pitches list [--status <s>] [--listing-mode <m>] [--limit <n>] [--json]
hp pitches transition <id> --to <draft|preview|live|expired|archived> [--preview-token <t>] [--json]
hp pitches scaffold --framework <id> --slug <s> --title <t> --cta-url <u> --creator-id <c> [...] (pure local)
hp frameworks list [--json]
hp frameworks sections <framework> [--json]| CLI subcommand | MCP tool | Local-only? | Notes |
| --- | --- | --- | --- |
| hp pitches create | create_pitch | no | --dry-run and --input - are the script-friendly flags. Without --input -, requires --framework, --slug, --title, --cta-url, --creator-id. |
| hp pitches get <id> | get_pitch | no | <id> is the pitcher record $id. |
| hp pitches list | find_pitches | no | Filters: --status, --listing-mode, --limit (default 25). |
| hp pitches transition <id> --to <state> | transition_pitch_status | no | <state> is one of draft, preview, live, expired, archived. |
| hp pitches scaffold ... | scaffold_pitch_from_framework | yes | Pure-local helper. Prints a CreatePitchInput JSON to stdout (no create call). Designed to pipe into hp pitches create --input -. |
| hp frameworks list | list_frameworks | yes | Returns the SDK's framework ids with name / origin / description. |
| hp frameworks sections <framework> | suggested_sections_for_framework | yes | Returns the suggested section stubs for a framework. |
Auth modes
The CLI has two auth modes, selected by env vars:
| Env vars set | Mode | Where requests go |
| --- | --- | --- |
| PITCHER_API_KEY=hp_pk_… only | apiKey-MCP (default) | POST {PITCHER_MCP_URL}/mcp with Authorization: Bearer ${PITCHER_API_KEY} |
| PITCHER_JWT=<jwt> only | jwt-SDK (fallback) | Direct to the pitcher REST API via the SDK |
| Both | (error) | PITCHER_AUTH_AMBIGUOUS exit 2 |
| Neither | (error) | "set PITCHER_API_KEY (recommended) or PITCHER_JWT" exit 2 |
Optional: PITCHER_MCP_URL (defaults to the SDK's default; the SDK in
turn defaults to the hosted MCP at https://mcp.honestpitches.com,
or the local dev port when NODE_ENV !== "production").
Why two modes
The SDK accepts an apiKey in its config, but the
pitches.create / update / transition methods require a session
token before any HTTP call. So the API key has to be resolved
into a per-session token by something else before the SDK can
use it. That "something else" is the pitcher-mcp HTTP transport,
which special-cases Authorization: Bearer hp_pk_…, verifies the
key against the pitcher_api_keys table, and mints a fresh
session token per request. The CLI's job is to sit at the front
of that chain.
If you already have a session token (e.g. a dev token from the
Studio browser session), you can skip the MCP entirely with the
PITCHER_JWT fallback.
How to get a hp_pk_… API key
The API-key issuance system is already wired end-to-end. The one human step in the entire "no human in the loop" flow is to issue the key once in the Studio:
- Open the Studio at
/settings/api-keys. - Click "create", label it (e.g.
hp-cli-no-human), choose scopes["sdk", "mcp"]. - Copy the raw
hp_pk_…token from the one-time modal. - Paste it into your environment as
PITCHER_API_KEY.
The token format is hp_pk_<48-char base62>. It's stored hashed;
the 8-char prefix after hp_pk_ is the lookup key.
The full "no human" flow
# 1. Operator step (one-time, in a browser): issue the api key.
# - Open /settings/api-keys
# - Click "create", label it "hp-cli-no-human", scope = ["sdk", "mcp"]
# - Copy the raw hp_pk_… token from the one-time modal
# - Paste it into your .env / shell
# 2. Set the CLI env (the default — apiKey via MCP, hitting the
# hosted mcp at https://mcp.honestpitches.com).
export PITCHER_API_KEY="hp_pk_abc12345abc12345abc12345abc12345abc12345abc12345"
# 3. Scaffold a new pitch (pure local — no network).
hp pitches scaffold \
--framework pas \
--slug my-no-human-pitch-$(date +%s) \
--title "Created by hp CLI" \
--cta-url "https://example.com" \
--json > /tmp/pitch.json
# 4. Create it (the apiKey-MCP path: POSTs JSON-RPC to the MCP).
PITCH_ID=$(hp pitches create --input - < /tmp/pitch.json --json | jq -r '.$id')
# 5. Promote it (two transitions: draft -> preview -> live).
hp pitches transition "$PITCH_ID" --to preview --json
hp pitches transition "$PITCH_ID" --to live --json
# 6. Verify it's live.
hp pitches get "$PITCH_ID" --json | jq '.status, .lifecycle'
# Expect: "live" "live"That is the script that proves v0.5.0 ships working. The one human step is step #1 (issue the api key in the Studio). Steps #2 onward are fully scriptable — a cron job, a GitHub Action, or an LLM agent running in a sandbox can do them all.
Stdout vs stderr policy
- stdout: command result (the JSON or human summary). Always parseable by downstream pipes.
- stderr: errors, warnings, "no rows matched" messages.
- Exit codes:
0— success1— runtime error (SDK threw, network failed, validation failed)2— usage error (missing required flag, unknown subcommand, ambiguous auth)3— auth error (expired token) — distinct from runtime errors so scripts can retry-with-refresh
Build / test (for contributors)
pnpm install
pnpm build # tsup → dist/ (with shebang)
pnpm test # vitest run
pnpm typecheck # tsc --noEmit
pnpm test:ci # full chain (typecheck && test && contract tests)License
MIT — published as a public package. See LICENSE.
