summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authort <t@tjp.lol>2026-06-03 09:11:36 -0600
committert <t@tjp.lol>2026-06-03 12:33:44 -0600
commit2416a308c0e467f8dbdbe09942aa903bca751c0e (patch)
treec6f5f724ec83b1cf045c478d0a668d69a6a9d6e3
parent442888c6c306cfff0708c3d4bbbeda685cec2e75 (diff)
plan doc: claude subscription provider
-rw-r--r--docs/anthropic-subscription-provider.md180
1 files changed, 180 insertions, 0 deletions
diff --git a/docs/anthropic-subscription-provider.md b/docs/anthropic-subscription-provider.md
new file mode 100644
index 0000000..c6d44eb
--- /dev/null
+++ b/docs/anthropic-subscription-provider.md
@@ -0,0 +1,180 @@
+# Anthropic subscription provider sketch
+
+Goal: expose a pantograph provider backed by an interactive Claude Code subscription session, without using Anthropic API keys, `claude -p`, or Agent SDK metering.
+
+## Core idea
+
+Run `claude` as an interactive TUI process under a PTY, but make it behave like a minimal local model provider:
+
+- pantograph owns the outer UX and provider API.
+- Claude Code provides subscription-backed model turns.
+- Claude built-in tools are disabled.
+- pantograph tools are exposed to Claude Code through MCP.
+- Claude Code hooks emit structured lifecycle/tool/session events to pantograph over a private FIFO or Unix socket.
+
+This avoids parsing only terminal paint where possible. The PTY remains necessary for interactive subscription behavior, but structured telemetry comes from hooks.
+
+## Why not `--bare`
+
+`claude --bare` is not suitable for this provider. Local `claude --help` says it:
+
+- skips hooks,
+- skips keychain reads,
+- sets `CLAUDE_CODE_SIMPLE=1`,
+- and uses only `ANTHROPIC_API_KEY` or `apiKeyHelper` auth.
+
+That defeats both requirements: subscription auth and hook instrumentation.
+
+## Intended invocation
+
+Approximate command shape:
+
+```sh
+env -u ANTHROPIC_API_KEY \
+ PANTO_HOOK_EVENTS="$PANTO_HOOK_EVENTS" \
+ claude \
+ --system-prompt "$PANTO_SYSTEM_PROMPT" \
+ --tools "" \
+ --disable-slash-commands \
+ --no-chrome \
+ --strict-mcp-config \
+ --mcp-config "$PANTO_MCP_CONFIG" \
+ --settings "$PANTO_CLAUDE_SETTINGS" \
+ --setting-sources local \
+ --dangerously-skip-permissions \
+ --model sonnet
+```
+
+`PANTO_HOOK_EVENTS` should point at a private FIFO or Unix socket created by pantograph before launching Claude Code.
+
+Notes:
+
+- `--system-prompt` replaces Claude Code's default system prompt. Do not use `--append-system-prompt` for provider mode.
+- `--tools ""` disables Claude Code's built-in tool set.
+- A manual test confirmed MCP tools still work with `--tools ""`.
+- `--strict-mcp-config` prevents ambient MCP servers from user/project config leaking into the session.
+- `--dangerously-skip-permissions` bypasses both tool permission prompts and the workspace trust prompt.
+- Because dangerous-skip may not mark the workspace trusted, do not rely on project `.claude/settings.json`; pass harness settings explicitly via `--settings`.
+- Always clear `ANTHROPIC_API_KEY` so Claude Code cannot silently choose API billing.
+
+## MCP tool bridge
+
+pantograph should expose its active tool registry as an MCP server, probably named `pantograph`.
+
+Claude sees tools such as:
+
+```text
+mcp__pantograph__read
+mcp__pantograph__edit
+mcp__pantograph__bash
+mcp__pantograph__write
+```
+
+This gives pantograph control over:
+
+- permission policy,
+- extension-provided tools,
+- tool result formatting,
+- audit logging,
+- sandboxing,
+- and future compatibility with non-Claude providers.
+
+Claude Code should not execute meaningful work through built-in tools in this mode.
+
+## Hook harness
+
+Claude Code hooks should be generated into `$PANTO_CLAUDE_SETTINGS`. Hooks write newline-delimited JSON events to a private FIFO or Unix socket.
+
+Events to capture:
+
+- `SessionStart`
+- `SessionEnd`
+- `UserPromptSubmit`
+- `PreToolUse`
+- `PostToolUse`
+- `PostToolUseFailure`
+- `PostToolBatch`
+- `Stop`
+- `StopFailure`
+- `Notification`
+- `PermissionRequest` if it still appears unexpectedly
+- `PermissionDenied` if auto policy blocks anything
+
+Example event envelope:
+
+```json
+{
+ "type": "claude_hook",
+ "event": "PreToolUse",
+ "session_id": "...",
+ "tool_name": "mcp__pantograph__bash",
+ "tool_input": {},
+ "timestamp_ms": 0
+}
+```
+
+The hook program should be tiny and deterministic:
+
+1. read hook JSON from stdin,
+2. wrap it in a panto event envelope,
+3. write one NDJSON line to the hook event endpoint,
+4. return the desired Claude Code hook decision.
+
+For normal MCP tool use, hooks should observe, not deny.
+
+## Built-in tool policy
+
+Preferred path: `--tools ""` removes all built-in tools, leaving only MCP tools.
+
+Fallback if a future Claude Code release changes behavior:
+
+- allow the minimum required built-ins,
+- install `PreToolUse` hooks matching `Bash|Read|Write|Edit|Glob|Grep|Task|WebFetch|WebSearch|Notebook.*`,
+- deny them with a reason telling Claude to use the corresponding `mcp__pantograph__...` tool.
+
+Hooks can block built-ins, but they cannot transparently replace a built-in tool call with a successful custom result. Replacement should happen by steering the model toward MCP tools, not by hijacking built-ins.
+
+## PTY responsibilities
+
+The PTY layer still matters for:
+
+- satisfying Claude Code's interactive mode requirements,
+- sending user prompts,
+- receiving assistant-visible text,
+- detecting gross process state,
+- handling login/session expiry screens,
+- and recovering from unexpected prompts.
+
+Do not depend on terminal scraping for tool execution state if hooks can provide it. Terminal scraping should be best-effort display mirroring.
+
+## Provider behavior
+
+The first implementation should be deliberately narrow:
+
+1. one long-lived Claude Code process per panto provider session,
+2. no `claude -p`,
+3. no session resume until the basic flow is stable,
+4. no built-in Claude tools,
+5. panto tools only through MCP,
+6. hook NDJSON as the structured event stream,
+7. PTY text as the assistant display stream.
+
+Start with a single-turn text response, then add MCP tools, then add session lifecycle handling.
+
+## Known risks
+
+- Anthropic may change Claude Code's CLI flags, hook schemas, or trust behavior.
+- Heavy automation of the interactive subscription product may be treated differently in the future.
+- `--dangerously-skip-permissions` is acceptable only if pantograph enforces its own policy at the MCP layer.
+- Hook delivery is only as reliable as Claude Code's hook system and the FIFO/socket transport.
+- Terminal UI changes can still break prompt submission or assistant text extraction.
+- OAuth/keychain subscription auth must remain active; API-key auth must be prevented.
+
+## Open questions
+
+- Can assistant message streaming be captured from a hook or debug channel, or only from the PTY?
+- Does `--setting-sources local` load `--settings` exactly as needed across Claude Code versions?
+- Which Claude Code lifecycle event best marks an assistant turn as complete?
+- How should pantograph handle Claude Code compacting or context management?
+- Can a generated settings file fully avoid user/project Claude configuration?
+- What is the safest hook event transport: FIFO or Unix socket?