Run the Claude Code CLI as a headless AI backend from any language. No API key required. Works with any Claude subscription.
Claude Bridge is a pattern for calling the Claude Code CLI as a subprocess from any program — Python, Node.js, Bash, Go — without a human at the terminal.
Instead of managing API keys, HTTP clients, or rate limit headers, you spawn claude as a child process, send your prompt via stdin, and read the response. Claude handles authentication, model selection, tool execution, and multi-turn reasoning.
echo "Analyze this codebase and list the main improvement areas." | claude \
--dangerously-skip-permissions \
--allowedTools "Read Glob Grep" \
--max-turns 10Claude reads files, edits code, runs shell commands, and calls web APIs depending on which tools you allow. The only requirement is a working Claude Code installation.
| Mode A - Metered | Mode B - Subscription | |
|---|---|---|
| Flag | --print - |
(omit --print) |
| Output format | JSON-Lines stream | Raw text (ANSI cleanup needed) |
| Cost per call | total_cost_usd returned |
Not tracked |
| Token counts | input_tokens / output_tokens |
Not tracked |
| Session resume | --resume <session_id> |
Not available |
| Best for | Cost attribution per call | High-volume automated pipelines |
import os, re, subprocess
def claude_invoke(prompt, cwd=".", tools=None, max_turns=10, timeout=900):
env = {k: v for k, v in os.environ.items()
if k not in {"CLAUDECODE", "CLAUDE_CODE_SESSION",
"CLAUDE_CODE_ENTRYPOINT", "CLAUDE_CODE_PARENT_SESSION"}}
result = subprocess.run(
["claude", "--dangerously-skip-permissions",
"--allowedTools", " ".join(tools or ["Read", "Glob", "Grep"]),
"--max-turns", str(max_turns)],
input=prompt, capture_output=True, text=True,
cwd=cwd, env=env, timeout=timeout,
)
raw = result.stdout + result.stderr
return re.sub(r'\x1b\[[0-9;]*[a-zA-Z]', '', raw).strip()
response = claude_invoke("Summarize the main purpose of this project.")
print(response)import json, os, subprocess
def claude_invoke_metered(prompt, cwd=".", tools=None, max_turns=10):
env = {k: v for k, v in os.environ.items()
if k not in {"CLAUDECODE", "CLAUDE_CODE_SESSION",
"CLAUDE_CODE_ENTRYPOINT", "CLAUDE_CODE_PARENT_SESSION"}}
result = subprocess.run(
["claude", "--print", "-", "--output-format", "stream-json", "--verbose",
"--dangerously-skip-permissions",
"--allowedTools", " ".join(tools or ["Read", "Glob", "Grep"]),
"--max-turns", str(max_turns)],
input=prompt, capture_output=True, text=True,
cwd=cwd, env=env, timeout=300,
)
texts, cost = [], 0.0
for line in result.stdout.splitlines():
try:
e = json.loads(line)
if e.get("type") == "assistant":
for b in e.get("message", {}).get("content", []):
if b.get("type") == "text":
texts.append(b["text"])
elif e.get("type") == "result":
cost = e.get("total_cost_usd", 0.0)
except json.JSONDecodeError:
pass
return {"content": "\n\n".join(texts), "cost_usd": cost}const { invokeModeA, invokeModeB } = require('./examples/node/bridge.js');
// Mode B
const text = await invokeModeB('Explain what this file does.', {
allowedTools: ['Read'],
maxTurns: 5,
});
// Mode A with cost tracking
const { content, costUsd } = await invokeModeA('Write unit tests for auth.py', {
allowedTools: ['Read', 'Glob', 'Edit', 'Write', 'Bash'],
maxTurns: 20,
});# Mode B (default)
./examples/bash/bridge.sh "List all Python files and their purpose"
# Mode A
./examples/bash/bridge.sh "Generate a test suite for this module" --mode-aWhen your program runs inside a Claude session, certain environment variables are set. Strip them before spawning the child process, otherwise the child claude process may refuse to start:
GUARDS = [
"CLAUDECODE", "CLAUDE_CODE_ENTRYPOINT",
"CLAUDE_CODE_SESSION", "CLAUDE_CODE_PARENT_SESSION",
]
env = {k: v for k, v in os.environ.items() if k not in GUARDS}Never give an agent more capability than it needs for the task:
| Role | --allowedTools |
|---|---|
| Read-only analysis | Read Glob Grep |
| Code writer | Edit Write Read Glob Grep Bash MultiEdit |
| Test runner | Bash Read |
| Full agent | Edit Write Read Glob Grep Bash MultiEdit WebFetch |
Prevents runaway agent loops. Use 5-10 for simple tasks, 20-40 for complex multi-file work.
So Edit, Write, and Bash tools affect the right files:
subprocess.run([...], cwd="/path/to/target-project", ...)Mode B has 10-30 seconds of startup overhead from the welcome banner. Use at least 2x the Mode A timeout as a baseline:
# Mode A: timeout=300
# Mode B: timeout=900 minimumBoth modes automatically load CLAUDE.md from the working directory during process initialization, before the first prompt is read. Place a CLAUDE.md at the root of your target project to give Claude persistent context:
# MyProject
FastAPI service. Test command: uv run pytest tests/.
Database: PostgreSQL at localhost:5432. Never commit .env files.Reducing input tokens produces faster responses and lower cost in Mode A. Three techniques that compose cleanly:
RTK intercepts command output before it enters Claude's context window. A 200-test pytest failure produces around 15,000 tokens of raw output. RTK filters it to the failed tests and tracebacks only, around 800 tokens.
Instruct agents via system prompt:
Use rtk to filter verbose command output:
rtk pytest tests/ -v
rtk git diff main..HEAD
RTK preserves failures and tracebacks. It removes passing test lines and progress bars.
Install: npm i -g @rtk-ai/rtk
TOON (Token-Oriented Object Notation) encodes the same information as JSON in approximately 40% fewer tokens, losslessly. Claude reads it natively.
Apply to structured data sent in prompts (task lists, configuration, metadata):
# JSON
[{"task": "Write tests", "agent": "coder", "priority": "high"}]
# TOON (~33% fewer tokens)
tasks
- task: Write tests
agent: coder
priority: high
For agents that write content rather than reading it, trim the input context:
BODY_LIMIT = 2500
issue_body = issue_body[:BODY_LIMIT]Add to your project's CLAUDE.md:
## Agent backend
Use the Claude Bridge pattern from github.com/Dixter999/claude-bridge
when building any headless AI agent in this project.Or copy CLAUDE.md from this repository into your project's .claude/commands/ folder.
- Claude Code installed and authenticated
--dangerously-skip-permissionsavailable on the target machine- Python 3.8+ / Node.js 18+ / Bash 4+
claude-bridge/
├── examples/
│ ├── python/
│ │ ├── bridge_mode_a.py Mode A - stream-json output with cost tracking
│ │ └── bridge_mode_b.py Mode B - stdin-pipe, no cost tracking
│ ├── node/
│ │ └── bridge.js Node.js implementation, both modes
│ └── bash/
│ └── bridge.sh Bash wrapper
├── docs/
│ ├── mode-a.md Mode A reference
│ ├── mode-b.md Mode B reference
│ └── token-reduction.md RTK, TOON, truncation details
├── assets/
│ └── diagram.svg Architecture diagram
└── CLAUDE.md Skill instructions for Claude Code