# 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?