Run Claude Agent SDK apps through the same interactive Claude Code terminal humans use.
中文文档 · Quick start · Integrations · Compatibility matrix
cctty is a drop-in claude executable replacement for the official Claude
Agent SDKs. Your app keeps using the Python or TypeScript SDK. cctty replaces
only the executable path, launches interactive Claude Code inside a real PTY,
drives it like a person would, and translates the terminal session back into
SDK-compatible stream-json.
If non-interactive Claude Code or Claude Agent SDK execution is separately
billed, restricted, unavailable, or behaviorally different from the terminal
experience, cctty gives you the escape hatch:
keep the official SDK API; run the actual work through interactive Claude Code.
cctty is not affiliated with Anthropic. It still requires a locally installed
and authenticated Claude Code CLI.
| Capability | Status |
|---|---|
| Official TypeScript SDK | Supported via pathToClaudeCodeExecutable: "cctty". |
| Official Python SDK | Supported via ClaudeAgentOptions(cli_path="cctty"). |
| Permissions | SDK can_use_tool callbacks are bridged to Claude's keyboard-driven TTY forms for Bash, file writes/edits, and common approval menus. |
| Plan mode | Supported and live-tested, including long SDK prompts that Claude collapses into terminal paste forms. |
| MCP | Native --mcp-config is passed to Claude; SDK in-process MCP servers are proxied through a temporary stdio MCP bridge. |
Forms / AskUserQuestion |
Structured SDK questions are forwarded, and visible terminal forms are parsed as a fallback. SDK answers are textified and fed back into Claude. |
| Streaming input | --input-format stream-json is accepted; multi-turn SDK stdin flows are supported. |
| Model / permissions controls | SDK set_model and set_permission_mode update launch args and restart the idle TTY for the next turn. |
| Thinking / effort / max turns | --thinking, --thinking-display, --effort, --max-thinking-tokens, and --max-turns are forwarded to Claude. |
| Fast mode | Treated as Claude-owned terminal behavior. cctty does not implement a separate set_fast_mode SDK control yet. |
brew install Pyiner/cctty/ccttyor tap once:
brew tap Pyiner/cctty
brew install ccttyDownload a release archive:
curl -L -o cctty.tar.gz \
https://github.com/Pyiner/cctty/releases/download/v0.2.4/cctty-0.2.4-aarch64-apple-darwin.tar.gz
tar -xzf cctty.tar.gz
sudo install -m 0755 cctty /usr/local/bin/ccttyPublished release targets:
aarch64-apple-darwinx86_64-apple-darwinx86_64-unknown-linux-musl(static Linux build; no modern glibc required)
cargo install --git https://github.com/Pyiner/ccttyConfirm the real Claude CLI is installed and authenticated:
claude --version
cctty --versionRun a direct smoke test:
cctty --print --output-format stream-json "Reply exactly CCTTY_OK"Point an SDK app at cctty instead of claude:
- cli_path="/path/to/claude"
+ cli_path="/path/to/cctty"or in TypeScript:
- pathToClaudeCodeExecutable: "/path/to/claude"
+ pathToClaudeCodeExecutable: "/path/to/cctty"Everything else stays on the official SDK: streaming messages, permission
callbacks, permissionMode, maxTurns, model, settingSources, MCP config,
and normal SDK options continue to flow through the SDK you already use.
By default cctty finds claude on PATH. To point at a specific underlying
Claude binary:
CCTTY_CLAUDE_PATH=/path/to/claude cctty -p "Reply OK"cctty can also wrap official Claude Code auth commands. Normal auth commands
are passed through unchanged:
cctty auth status --json
cctty auth logout
cctty auth login --claudeaiFor host apps that need to drive login from a UI, auth login supports a
machine-readable event stream:
cctty auth login --json-events --claudeaiThis launches the real claude auth login in a PTY, emits JSON lines for the
authorization URL and code prompt, and forwards lines received on stdin back to
Claude. The entered authorization code is not echoed in JSON events. cctty
does not implement Claude's OAuth flow and does not store tokens; credentials
are still managed by the official Claude Code CLI.
cctty replaces the claude executable used by Claude Agent SDK apps and
claude -p style non-interactive flows. It does not replace higher-level
wrappers such as ACP servers, editor adapters, or project-specific agent
runtimes.
- If an app exposes
cli_path,pathToClaudeCodeExecutable, orCLAUDE_CODE_EXECUTABLE, point that setting atcctty. - If an app is an ACP adapter, keep the ACP adapter in place and configure its
internal Claude executable path to
ccttywhen it offers one. - If a wrapper hard-codes
claude, use a PATH shim or ask the wrapper to expose the executable-path option. cctty --acp --stdiois not a supported interface.--acpbelongs to third-party wrappers above Claude Code, not to the core Claude executable thatccttyreplaces.
cctty writes a small local diagnostic log by default. It records process
startup, resolved Claude path, SDK control requests, permission decisions,
synthetic result/idle events, and timeout summaries. It does not log full prompt
text by default.
Default paths:
- macOS:
~/Library/Logs/cctty/cctty.log - Linux:
${XDG_STATE_HOME:-~/.local/state}/cctty/cctty.log
Controls:
CCTTY_LOG_FILE=/tmp/cctty.log cctty --version
CCTTY_LOG=0 cctty --version
CCTTY_LOG_TTY=1 CCTTY_LOG_FILE=/tmp/cctty.log cctty -p "Reply OK"CCTTY_LOG_TTY=1 records recent visible TTY text around waits/timeouts. Use it
only for local debugging because that text can include prompts and model output.
Install the official SDK:
npm install @anthropic-ai/claude-agent-sdkUse cctty as the SDK executable:
import { query } from "@anthropic-ai/claude-agent-sdk";
for await (const message of query({
prompt: "Create a tiny README for this project.",
options: {
pathToClaudeCodeExecutable: "cctty",
permissionMode: "default",
settingSources: ["project", "local"],
},
})) {
console.log(message);
}With a permission callback:
import { query } from "@anthropic-ai/claude-agent-sdk";
const canUseTool = async (toolName: string, input: Record<string, unknown>) => {
if (["Read", "Write", "Edit", "MultiEdit"].includes(toolName)) {
return { behavior: "allow" as const };
}
if (toolName === "Bash") {
const command = String(input.command ?? "");
if (command === "pwd" || command.startsWith("ls ")) {
return { behavior: "allow" as const };
}
}
return {
behavior: "deny" as const,
message: `${toolName} is not allowed by this app`,
};
};
async function* prompt() {
yield {
type: "user" as const,
message: {
role: "user" as const,
content: "Write index.html for a tiny canvas game.",
},
};
}
for await (const message of query({
prompt: prompt(),
options: {
pathToClaudeCodeExecutable: "cctty",
permissionMode: "default",
canUseTool,
settingSources: ["project", "local"],
},
})) {
console.log(message);
}Install the official SDK:
pip install claude-agent-sdkUse cctty as the SDK executable:
import asyncio
from pathlib import Path
from claude_agent_sdk import ClaudeAgentOptions, query
async def main():
options = ClaudeAgentOptions(
cli_path="cctty",
cwd=Path.cwd(),
permission_mode="default",
setting_sources=["project", "local"],
)
async for message in query(
prompt="Create a tiny README for this project.",
options=options,
):
print(message)
asyncio.run(main())With a permission callback:
import asyncio
from pathlib import Path
from claude_agent_sdk import (
ClaudeAgentOptions,
PermissionResultAllow,
PermissionResultDeny,
query,
)
async def can_use_tool(tool_name, input, context):
if tool_name in {"Read", "Write", "Edit", "MultiEdit"}:
return PermissionResultAllow()
if tool_name == "Bash":
command = str(input.get("command", ""))
if command == "pwd" or command.startswith("ls "):
return PermissionResultAllow()
return PermissionResultDeny(message=f"{tool_name} is not allowed by this app")
async def prompt():
yield {
"type": "user",
"message": {
"role": "user",
"content": "Write index.html for a tiny canvas game.",
},
}
async def main():
options = ClaudeAgentOptions(
cli_path="cctty",
cwd=Path.cwd(),
permission_mode="default",
can_use_tool=can_use_tool,
setting_sources=["project", "local"],
)
async for message in query(prompt=prompt(), options=options):
print(message)
asyncio.run(main())Surveyed and tested on 2026-05-21. The support target is always the same:
cctty replaces the underlying Claude executable/core, while the host project
keeps owning its own SDK, ACP, editor, or orchestration protocol.
| Project / package | Integration style | Status | Configure cctty | Tested coverage | Known gaps |
|---|---|---|---|---|---|
@anthropic-ai/claude-agent-sdk |
Official TypeScript Claude Agent SDK | Supported | pathToClaudeCodeExecutable: "cctty" |
Deterministic SDK test with fake Claude; live mini-game write test under permissionMode: "default" with SDK canUseTool approvals; live direct SDK smoke through cctty. |
Result metadata is synthesized when interactive Claude does not write a result frame. --include-partial-messages emits SDK-compatible text events after transcript persistence, not token-by-token partials. |
claude-agent-sdk |
Official Python Claude Agent SDK | Supported | ClaudeAgentOptions(cli_path="cctty") |
Deterministic SDK test with fake Claude; live mini-game write test under permission_mode="default" with SDK can_use_tool approvals. |
Same result metadata and synthetic partial-message limits as TypeScript. |
| Hermes Agent | OpenAI-like agent runtime with a Claude SDK provider | Supported on the cctty branch | Select provider claude-sdk or alias cctty; set HERMES_CLAUDE_SDK_COMMAND=/path/to/cctty or CCTTY_CLI_PATH=/path/to/cctty. |
Hermes unit coverage for provider routing and a local ClaudeSDKClient smoke through cctty. copilot-acp remains separate. |
Upstream release has to include the claude-sdk provider path; cctty does not implement Hermes' ACP adapter. |
NanoClaw / NanoBot (qwibitai/nanoclaw) |
Containerized TypeScript Agent SDK runner | Core supported; project integration needs a path override | Its runner passes pathToClaudeCodeExecutable to the SDK, but currently hard-codes /pnpm/claude. Patch NanoClaw to expose that setting, or install/symlink cctty at /pnpm/claude inside the agent image and set CCTTY_CLAUDE_PATH to the real Claude binary. |
Source inspected at commit 0683c6e / nanoclaw@2.0.64; NanoClaw-pinned @anthropic-ai/claude-agent-sdk@0.2.138 smoke passed with cctty. |
Full container/session runtime not run. Upstream should expose the executable path as config. |
@agentclientprotocol/claude-agent-acp |
ACP server powered by the TypeScript Claude Agent SDK | Supported as a core executable override | Set CLAUDE_CODE_EXECUTABLE=/path/to/cctty in the ACP adapter environment. |
0.36.1 smoke passed through acpx, including SDK initialization metadata, includePartialMessages, idle session-state handling, SDK MCP proxying, and dynamic set_model / set_permission_mode argument updates. |
ACP behavior belongs to the adapter. cctty only supplies the Claude executable behind it. |
@zed-industries/claude-code-acp |
Deprecated ACP server powered by the TypeScript Claude Agent SDK | Supported as a core executable override | Set CLAUDE_CODE_EXECUTABLE=/path/to/cctty in the ACP adapter environment. |
0.16.2 smoke passed through acpx. npm marks this package deprecated in favor of @agentclientprotocol/claude-agent-acp. |
Same boundary as above: keep the ACP adapter, replace only its Claude executable. |
acp-claude-code |
ACP bridge for Claude Code | Conditional | Set ACP_PATH_TO_CLAUDE_CODE_EXECUTABLE=/path/to/cctty. |
0.8.0 path override works. A smoke passed with the older SDK-exporting @anthropic-ai/claude-code@1.0.128 dependency and fake Claude under cctty. |
A fresh install currently resolves @anthropic-ai/claude-code: latest to a CLI-only package, so the wrapper can fail before cctty starts. This is a wrapper dependency issue, not an ACP feature cctty should implement. |
claude-code-acp / cc-acp |
Alternate ACP bridge for Claude Code | Unsupported without wrapper changes | No cctty setting found. | 0.1.1 source/package inspected. |
The wrapper hard-resolves its bundled @anthropic-ai/claude-code/cli.js and ignores CLAUDE_CODE_EXECUTABLE; it needs an upstream executable-path option. |
Other surveyed SDK hosts generally fit the same rule: if the host exposes
cli_path, pathToClaudeCodeExecutable, CLAUDE_CODE_EXECUTABLE, or a similar
Claude executable-path option, point it at cctty. If it imports an SDK module
path, bundles a specific cli.js, or manages an interactive terminal itself,
the host needs a small upstream option before cctty can be selected cleanly.
Normal interactive commands, --help, and --version are proxied to the real
claude binary. The --print / --input-format stream-json path is handled by
starting interactive Claude in a PTY, submitting prompts with bracketed paste,
tailing Claude's JSONL transcript, and emitting text, json, or
stream-json output.
For SDK permission callbacks, cctty consumes the hidden
--permission-prompt-tool stdio flag, emits SDK-style can_use_tool
control_request messages, waits for SDK control_response decisions, and then
drives Claude's interactive permission UI with keyboard input.
For SDK host metadata and controls, cctty returns Claude-compatible
initialization metadata including the current model aliases used by Claude Code
SDK hosts (default, opus, haiku, sonnet[1m], and full model names). When
the host sends set_model or set_permission_mode between turns, cctty
updates the underlying Claude launch arguments, restarts the idle TTY, and uses
the new model or permission mode for the next prompt.
Claude's interactive AskUserQuestion forms are bridged through the same SDK
control channel. When Claude asks a structured question, cctty forwards the
original AskUserQuestion tool input to the SDK caller when it is already in
the transcript. If Claude shows the terminal form before persisting that tool
call, cctty falls back to parsing the visible TTY form and still sends an
SDK-shaped AskUserQuestion request. If the caller returns
updatedInput.answers, answers, content, or similar structured form data,
cctty renders those answers as text and feeds them back into Claude's TTY. If
Claude opens a follow-up prompt, cctty writes there; if Claude returns to the
main prompt after cancelling the form, cctty submits the answers as the next
user message. SDK hosts can answer forms without pretending to click the
terminal UI.
Fast deterministic tests use a fake interactive Claude binary:
cargo testSDK integration tests download the official SDK packages and run them against
cctty with the fake interactive Claude underneath:
CCTTY_SDK_INTEGRATION=1 cargo test --test sdk_integration -- --ignored --nocaptureLive differential tests compare claude --print and cctty --print against the
real Claude CLI. These require local Claude auth and spend real Claude calls:
CCTTY_LIVE_CLAUDE_DIFF=1 cargo test --test claude_differential -- --ignored --nocaptureThe focused live permission test forces a per-project Bash approval prompt with
a temporary .claude/settings.local.json, then verifies both SDK allow and deny
responses against the real interactive Claude TTY:
CCTTY_LIVE_PERMISSION=1 cargo test --test claude_differential live_permission_prompt_stdio_honors_project_ask_rules -- --ignored --nocaptureLive permission-mode smoke tests cover plan, auto, dontAsk, and
acceptEdits, including the first-run auto-mode consent form and an
acceptEdits file-write run:
CCTTY_LIVE_PERMISSION_MODES=1 cargo test --test claude_differential live_permission_modes_smoke_common_modes -- --ignored --nocapture
CCTTY_LIVE_PERMISSION_MODES=1 cargo test --test claude_differential live_accept_edits_writes_file_without_sdk_permission_callback -- --ignored --nocaptureLive SDK game tests install the official Python and TypeScript SDKs, run them
against real cctty/Claude, keep permissionMode at default, approve file
edits through SDK can_use_tool callbacks, and verify that a small browser game
is actually written:
CCTTY_LIVE_SDK_GAME=1 cargo test --test sdk_integration live_python_sdk_builds_game_with_cctty_permissions -- --ignored --nocapture
CCTTY_LIVE_SDK_GAME=1 cargo test --test sdk_integration live_typescript_sdk_builds_game_with_cctty_permissions -- --ignored --nocaptureThe repository includes GitHub Actions for CI and tagged releases.
git tag v0.2.4
git push origin v0.2.4The release workflow builds macOS and Linux archives and publishes SHA-256
sums. If the repository secret HOMEBREW_TAP_TOKEN is configured with write
access to Pyiner/homebrew-cctty, the same workflow also updates the Homebrew
tap. The formula is not published as a release asset; users should install
through the tap.
Captured from claude --help on Claude Code 2.1.148.
Status legend:
- Supported: implemented by
cctty, or proxied to real Claude with a passing test for the relevant path. - Pass-through: forwarded to the underlying interactive Claude TTY. Parser coverage exists, but behavior parity still belongs to Claude and may need a live differential before users rely on it for SDK replacement.
- Partial: accepted, but output or behavior is known to differ from
claude --print. - Unsupported: accepted only as a no-op or not bridged yet. Do not rely on it.
| Option(s) | Status | Current handling in cctty --print |
Test coverage / known difference |
|---|---|---|---|
--add-dir |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--agent, --agents |
Pass-through | Forwarded to interactive Claude. | Parser coverage plus fake-PTY argv capture. No live agent behavior differential yet. |
--allow-dangerously-skip-permissions |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--allowedTools, --allowed-tools |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. Permission behavior not live-tested. |
--append-system-prompt |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--bare |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. Bare auth/config behavior not differential-tested. |
--betas |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--brief |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--chrome |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
-c, --continue |
Partial | Forwarded. Transcript tail falls back to newest project transcript because no session id is known up front. | Parser coverage only. Needs live resume/continue differential. |
--dangerously-skip-permissions |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. Dangerous behavior is intentionally not exercised in default tests. |
-d, --debug |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--debug-file |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--disable-slash-commands |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--disallowedTools, --disallowed-tools |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. Tool-denial behavior not live-tested yet. |
--effort |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--exclude-dynamic-system-prompt-sections |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--fallback-model |
Partial | Forwarded, but Claude documents this as print-only. Since cctty runs underlying Claude interactively, parity is not proven. |
Parser coverage only. Needs live overload/fallback strategy test. |
--file |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--fork-session |
Partial | Forwarded. cctty tails whichever transcript Claude writes. |
Parser coverage only. Needs live resume/fork differential. |
--from-pr |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
-h, --help |
Supported | Entire command is proxied to real Claude. | Fake proxy test covers --version; README coverage test covers both aliases. |
--ide |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--include-hook-events |
Partial | Forwarded. Hook events appear only if interactive transcript writes them; stream semantics are not guaranteed to match --print. |
Parser coverage only. |
--include-partial-messages |
Partial | Consumed by cctty. When transcript text arrives, cctty emits SDK-compatible synthetic stream_event text deltas before the persisted assistant frame so SDK wrappers that render partial messages can work. |
Parser coverage plus fake-PTY stream-event test and live @agentclientprotocol/claude-agent-acp / @zed-industries/claude-code-acp smokes. It is not token-by-token live streaming; chunks arrive after transcript persistence. |
--input-format |
Supported | text prompts are read from argv/stdin. stream-json SDK input is read from stdin. |
Fake-PTY test, Python SDK test, TypeScript SDK test, plus live Python/TypeScript SDK game tests. |
--json-schema |
Partial | Forwarded, but cctty synthesizes result frames when interactive transcript lacks one; structured_output parity is not proven. |
Parser coverage only. Needs structured-output differential. |
--max-budget-usd |
Partial | Forwarded, but Claude documents this as print-only. Underlying interactive behavior is not proven equivalent. | Parser coverage only. |
--mcp-config |
Supported | Normal Claude-compatible stdio/SSE MCP configs are forwarded to interactive Claude. SDK in-process MCP servers are bridged: TypeScript initialize.sdkMcpServers and Python { "type": "sdk" } entries are rewritten into a temporary stdio MCP proxy, and mcp_message control requests are round-tripped back to the SDK. |
Parser coverage, fake-PTY argv passthrough for normal MCP configs, and TS/Python SDK-MCP round-trip tests covering initialize, tools/list, and tools/call. |
--mcp-debug |
Pass-through | Forwarded to interactive Claude. | Parser coverage plus fake-PTY argv passthrough test. |
--model |
Pass-through | Forwarded to interactive Claude. | Parser coverage and live differential with default configured model path. Specific model aliases not exhaustively tested. |
-n, --name |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--no-chrome |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--no-session-persistence |
Supported | Consumed by cctty. The underlying interactive run uses the normal Claude config/auth, then cctty removes the generated transcript and empty project directories after the run. |
Parser coverage plus fake-PTY persistence cleanup test. This preserves auth better than replacing CLAUDE_CONFIG_DIR. |
--output-format |
Partial | text, json, and stream-json are emitted by cctty. stream-json includes transcript frames plus a synthetic result frame if interactive Claude did not write one. |
Fake-PTY and live stream-json differential pass. Result metadata is partial. |
--permission-mode |
Supported | Forwarded to interactive Claude for all documented modes: acceptEdits, auto, bypassPermissions, default, dontAsk, plan. The first-run auto-mode consent form is handled by keyboard and chooses "enable auto mode" for the current run, not "make default". SDK permission callbacks are bridged when the caller also supplies hidden --permission-prompt-tool stdio. |
Parser coverage for all modes plus fake-PTY argv capture for all modes. Live tests cover plan, auto, dontAsk, acceptEdits, bypassPermissions, and default with project-local permissions.ask rules. Live SDK game tests exercise file-write approvals through Python and TypeScript SDK callbacks. |
--plugin-dir |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--plugin-url |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
-p, --print |
Supported | Consumed by cctty; underlying Claude is intentionally launched interactively through a PTY. |
Fake-PTY and live differential pass for basic query. |
--remote-control |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. Remote Control warnings may appear in transcript as system messages. |
--remote-control-session-name-prefix |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--replay-user-messages |
Partial | Consumed by cctty. User transcript frames may still be emitted, but exact replay semantics are not implemented separately. |
Parser coverage marks it consumed. |
-r, --resume |
Partial | Forwarded. cctty tails the requested session transcript when a session id is supplied. |
Parser coverage only. Needs live resume differential. |
--session-id |
Supported | Forwarded and used to locate the transcript. If omitted in print mode, cctty creates one. |
Fake-PTY and live differential cover session-id based transcript tailing. |
--setting-sources |
Pass-through | Forwarded to interactive Claude. | Parser coverage, including --setting-sources=project. |
--settings |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--strict-mcp-config |
Pass-through | Forwarded to interactive Claude. | Parser coverage plus fake-PTY argv passthrough test. |
--system-prompt |
Pass-through | Non-empty values are forwarded to interactive Claude. Empty or whitespace-only SDK values are consumed so they do not erase Claude Code's built-in interactive system prompt. | Parser coverage for non-empty pass-through and empty-value consumption. |
--tmux |
Pass-through | Forwarded. --tmux=classic is preserved as an equals-form flag; plain --tmux does not swallow the prompt. |
Parser regression test. |
--tools |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
--verbose |
Pass-through | Forwarded. cctty itself does not require it for stream-json, but real Claude does, so SDK callers usually include it. |
Parser and live differential coverage. |
-v, --version |
Supported | Entire command is proxied to real Claude. | Fake proxy test covers --version. |
-w, --worktree |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. |
SDK / Hidden Flag Compatibility
Some SDKs pass flags that are not listed in current claude --help.
| Option(s) | Status | Current handling | Notes |
|---|---|---|---|
--permission-prompt-tool, --permission-prompt-tool stdio |
Partial | stdio is consumed by cctty, not forwarded to interactive Claude. In stream-json mode, cctty watches transcript assistant.tool_use entries and also recognizes real TTY permission forms when Claude has not persisted the transcript yet. It emits SDK-style control_request / can_use_tool, waits for the matching control_response, then drives the interactive permission UI by keyboard. Bash allow confirms the selected row; Bash deny selects menu item 2 and pastes the SDK denial message into Claude's follow-up form when present. File create/write/edit/update forms are mapped to Write/Edit with file_path; allow confirms the selected row, while deny selects the file prompt's 3. No row to avoid accidentally choosing "allow all edits during this session". AskUserQuestion form tool uses are forwarded with their original structured questions input when available; if only the TTY form is visible, cctty parses that form and sends an SDK-shaped fallback request. SDK-returned structured answers are textified and sent through Claude's follow-up prompt, or submitted as the next user message if Claude returns to the main prompt after cancelling the form. If interactive Claude returns to the prompt after a rejected tool without writing a final result, cctty emits a synthetic error result with result: "Permission denied". |
Fake-PTY tests cover transcript-first allow/deny, Bash TTY-form-before-transcript, file Write TTY-form-before-transcript, transcript-vs-TTY description precedence, AskUserQuestion structured form answer round-trip, and TTY-form-before-transcript AskUserQuestion fallback. Live Claude Code 2.1.148 coverage forces Bash(printf:*) approval with project-local settings and verifies both allow and deny; live AskUserQuestion smoke verifies TTY fallback, answer textification, main-prompt answer injection, and final result. Live Python and TypeScript SDK game tests exercise Write approval through real file-creation TTY forms. Still partial: broader Edit/MultiEdit TTY variants, exact permission_suggestions, and exact blocked_path parity are not complete. |
--permission-prompt-tool <name> |
Pass-through | Non-stdio values are forwarded to interactive Claude. cctty does not emulate custom permission prompt tools itself. |
Parser coverage only. |
--max-turns, --task-budget, --max-thinking-tokens, --thinking, --thinking-display |
Pass-through | Forwarded to interactive Claude. These are emitted by official SDK thinking, budget, and turn-limit options. | Parser coverage only. Print-mode parity still belongs to real Claude. |
--system-prompt-file, --append-system-prompt-file, --managed-settings, --resume-session-at |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. These are SDK/newer-CLI compatibility entries, not from the captured public help output above. |
--session-mirror, --sdk-url |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. These are hidden SDK transport/session flags; cctty does not implement the remote SDK transport itself. |
--advisor, --channels, --dangerously-load-development-channels, --plan-mode-instructions, --plan-mode-required |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. Hidden/native Claude behavior is not differential-tested. |
--agent-id, --agent-name, --team-name, --agent-color, --agent-type, --parent-session-id, --teammate-mode |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. These hidden teammate/team flags are treated as native Claude-owned semantics. |
--remote, --rc, --teleport, --prefill, --prefill-b64, --rewind-files, --deep-link-cwd-b64, --deep-link-last-fetch, --deep-link-origin, --deep-link-repo, --enable-auth-status, --enable-auto-mode, --init, --init-only, --maintenance, --workload, --cowork, --xaa |
Pass-through | Forwarded to interactive Claude. | Parser coverage only. These are hidden/native flags found in the installed Claude binary; users should prefer documented flags unless an SDK or host app emits them. |
- Permission callbacks now have fake-PTY allow/deny coverage, a live
Bash(printf:*)approval differential for both allow and deny, and live Python/TypeScript SDK coverage for file creation approvals. Permission modesplan,auto,dontAsk,acceptEdits,bypassPermissions, anddefaulthave focused live coverage. Remaining risk is breadth: moreEdit/MultiEditTTY variants,allowedTools/disallowedToolsinteractions, and exact SDK metadata fields still need live coverage. --include-partial-messagesis compatibility-oriented, not true token-level streaming. cctty emits synthetic text deltas once transcript text is persisted; this unblocks SDK wrappers, but does not perfectly match Claude Code's live partial timing.--json-schema,--max-budget-usd, and--fallback-modelneed focused live differentials before being marked supported.- SDK control requests used by popular wrappers are compatibility-acked:
initialize,interrupt,set_model,set_permission_mode,set_max_thinking_tokens,apply_flag_settings, andmcp_status.set_modelandset_permission_modeupdate the stored launch args and restart the idle TTY for the next user turn. Other flag-setting controls are still compatibility acknowledgements unless they already map to launch-time CLI flags.