---
name: honest-pitches
description: >-
  Create, list, update, and publish Honest Pitches pitches via the hosted MCP,
  hp CLI, or Pitch SDK. Use when the user wants to draft or manage a pitch,
  connect Cursor/Claude to Honest Pitches, install @honest-pitches/cli or
  @honest-pitches/pitch-sdk, mint or use an hp_pk_ API key, or act as an agent
  on behalf of a pitcher.
---

# Honest Pitches — agent skill

Honest Pitches treats AI agents as first-class users. You act on behalf of a
**pitcher** (the human who creates pitches). Three interchangeable surfaces
share one `hp_pk_…` API key and one 12-tool catalog.

**Human briefing:** https://www.honestpitches.com/agents/
**This skill (raw):** https://www.honestpitches.com/agents/SKILL.md

## Pick a surface

| Prefer | When | How |
|---|---|---|
| **MCP** (recommended) | Client speaks MCP (Cursor, Claude Desktop, …) | Point at `https://mcp.honestpitches.com/mcp` with Bearer `hp_pk_…`. No install. |
| **CLI** | Shell agent (Aider, Codex, terminal) | `npm install -g @honest-pitches/cli` → binary `hp` |
| **SDK** | Typed TypeScript / custom integration | `pnpm add @honest-pitches/pitch-sdk` → `createPitcherClient({ apiKey })` |

The SDK is a thin HTTP client for the MCP. The CLI is a thin argv shim over
the SDK. The MCP is the canonical server.

## Auth (all surfaces)

1. User mints a key in Studio → **Settings → API keys**
   (`https://studio.honestpitches.com/settings/api-keys`).
2. Key shape: `hp_pk_…` (shown once at issue time — treat as a secret).
3. Send `Authorization: Bearer hp_pk_…` on every call.
4. Env var name for CLI/SDK: `PITCHER_API_KEY`.

Do **not** invent backend URLs, vendor config, `endpoint`, or `projectId`.
Config is `{ apiKey }` only. Default MCP base: `https://mcp.honestpitches.com`.

### MCP host config (Cursor / Claude)

```json
{
  "mcpServers": {
    "honest-pitches": {
      "url": "https://mcp.honestpitches.com/mcp",
      "headers": {
        "Authorization": "Bearer hp_pk_…"
      }
    }
  }
}
```

OAuth discovery (RFC 8707) is also available at
`https://mcp.honestpitches.com/.well-known/oauth-protected-resource`
for clients that prefer standards-based auth.

### CLI

```bash
npm install -g @honest-pitches/cli
export PITCHER_API_KEY=hp_pk_…
hp pitches list
```

Commands: `pitches create|get|list|transition|scaffold|media list`,
`frameworks list|sections`.

### SDK

```ts
import { createPitcherClient } from "@honest-pitches/pitch-sdk";

const client = createPitcherClient({
  apiKey: process.env.PITCHER_API_KEY!,
});
const pitches = await client.pitches.list({ limit: 10 });
```

## Tool catalog (12)

| Tool | Purpose |
|---|---|
| `list_frameworks` | Browse frameworks (PAS, AIDA, BAB, FAB, PSS, 4Ps, custom, DRTV…) |
| `get_framework` | One framework definition |
| `get_segment` | One segment (SectionKind) definition |
| `suggested_sections_for_framework` | Empty section stubs for a framework |
| `scaffold_pitch_from_framework` | Local draft only (no network) |
| `create_pitch` | Persist a draft (`creatorId` required) |
| `get_pitch` | Fetch by id |
| `list_pitches` | List with optional status filter |
| `list_pitch_media` | Uploaded assets **and** auto-generated thumbnail/OG IDs |
| `update_pitch` | Update draft (framework locked after preview) |
| `transition_pitch_status` | Move lifecycle (`to`: draft \| preview \| live \| archived) |
| `get_my_creator` | Caller's creators row id (or `null`) |

> **SDK alias (added 2026-07-30):** the same lookup is exposed on the
> SDK as `client.getMyCreator(): Promise<string | null>` (returns
> `null` when the user has no creators row yet). Use the SDK method
> when you're already inside an SDK consumer; use the MCP tool when
> you're talking to the hosted MCP via stdio or HTTP.

## Lifecycle (branch on `lifecycle`)

Every pitch row returns **both**:

- **`lifecycle`** (computed — branch on this): `draft` \| `preview` \| `live` \| `expired` \| `archived`
- **`status`** (persisted): `draft` \| `pending_payment` \| `live` \| `expired` \| `removed`

| lifecycle | status | Notes |
|---|---|---|
| `draft` | `draft` | No `previewToken` |
| `preview` | `draft` | `previewToken` present |
| `live` | `live` | Published |
| `expired` | `expired` | Time-boxed lapse |
| `archived` | `removed` | Intentional rename — use `lifecycle` |

**Token gate:** `to=preview` and `archived → draft` require `previewToken`.
There is **no** single-step `archived → preview` — go `archived → draft` then
`draft → preview`.

**Media:** auto-generated `thumbnailFileId` / `ogImageFileId` live on the
pitch row, not in uploaded assets. For a complete list use
`list_pitch_media` / `client.pitches.listMedia(id)`, not `get_pitch` alone.

**Partial updates require re-sending `sections` (2026-07-30):** the
server-side canonical normalizer at `@honest-pitches/pitch-core`
treats `sections` as a required field on the create path. The
update path also runs the same normalizer today, so a `PATCH
/pitches/:id` with `{ title: "..." }` returns `400 Invalid sections:
empty` because `sections` is missing. Workaround: re-send the full
sections array on every update call (fetch via `get_pitch` first,
mutate the field you want to change, then call `update_pitch` with
the merged payload). The proper fix — splitting the normalizer into
`normalizeCreatePitchInput` and `normalizeUpdatePitchInput` so the
update path doesn't require `sections` — is deferred to a follow-up
PR (tracked in the 2026-07-30 audit; not blocking).

## Suggested first steps

1. Confirm auth: `list_frameworks` or `hp pitches list`.
2. Resolve creator: `get_my_creator` (create a creator in Studio if `null`).
3. Scaffold → `create_pitch` → iterate with `update_pitch`.
4. `transition_pitch_status` to `preview`, then `live` when ready.

## Do not

- Call `www.honestpitches.com/api/*` (static CDN — returns 405).
- Install `@honest-pitches/mcp` from npmjs (hosted MCP only; package is private).
- Reveal or invent backend vendor names, endpoints, or project IDs.
- Unarchive without the stored `previewToken`.
