A single-file Python wrapper that lets your code call the Claude Code CLI as a subprocess, capture structured results, and stitch agentic Claude work into your own pipelines.
Claude Code is built to be drivable programmatically — it ships with non-interactive mode (-p), structured JSON output, named session UUIDs, and resumable sessions. That makes it a natural backend for your own orchestrators, batch jobs, and dev-loop tools.
This wrapper is the small piece of glue between your Python code and the CLI: spawn a session with a prompt, wait for the agent to write a result file, and get a parsed dict back. Your orchestrator does the planning and control flow; Claude Code does the agentic work; you don't have to rebuild the subprocess plumbing every time.
Good fit for:
- Prototyping agentic pipelines locally before deciding whether to productionize them on the API
- Dev-loop automation (code review, analysis, doc generation) running against your own subscription
- Batch tasks you want to watch in a real console (
windowed=True) - Hybrid workflows where the orchestrator does setup and the human takes over via
resume=True
Single file, standard library only, drop it in your tools/ and import.
- Drive agentic work from your own code — multi-step research, document analysis, code review, content generation
- Watch agents work — windowed mode opens a real console so you can see the agent reasoning live
- Hand sessions to humans — resume mode opens an existing session in a terminal for the user to take over
- Parallel agents — spawn multiple CC sessions concurrently, each writing to its own result file
- Fire-and-forget tasks — kick off long-running sessions and let the user own the window
- Python 3.10+ (uses
X | Ytype unions) - Claude Code CLI installed and on your
PATH - An authenticated Claude Code session (run
claudeonce interactively to log in) - Windows for windowed/resume modes (piped mode is cross-platform)
No third-party Python dependencies. Just standard library.
Drop claude_code_runner.py into your project's tools/ (or wherever you keep utilities). That's it.
your_project/
├── tools/
│ └── claude_code_runner.py
└── your_orchestrator.py
from tools.claude_code_runner import run_claude_taskfrom pathlib import Path
from claude_code_runner import run_claude_task
result_file = Path("output/analysis.json")
result = run_claude_task(
prompt=f"""
Read data.csv, identify the top 3 outliers in the 'revenue' column,
and write a JSON object to {result_file} with keys:
- outliers: list of {{row_id, revenue, reason}}
- method: string describing your detection approach
""",
result_file=result_file,
timeout=600,
log_dir=Path("output/sessions"),
task_id="outlier_analysis",
)
if result["success"]:
data = result["result"] # Parsed JSON
print(f"Found {len(data['outliers'])} outliers")
print(f"Session took {result['elapsed']:.1f}s")
else:
print(f"Failed: {result['error']}")The pattern is always:
- Tell the agent in the prompt where to write its result
- Hand the same path to
run_claude_taskasresult_file - Get back a parsed dict
See example.py for more patterns.
The subprocess runs headless. Stdout is captured as JSON. Cross-platform.
result = run_claude_task(prompt=..., result_file=...)Best for: production pipelines, batch jobs, tests, anything you don't need to watch.
Opens a real console window. The agent runs in it; you watch the reasoning unfold. Windows-only.
result = run_claude_task(prompt=..., result_file=..., windowed=True)Best for: development, debugging, demos, anything where you want to see what the agent is doing.
Opens an existing session by UUID in a new window. The user takes over. Windows-only.
result = run_claude_task(
session_id="some-uuid-you-saved-earlier",
windowed=True,
resume=True,
)Best for: hybrid workflows where the orchestrator does setup and the human finishes the work interactively.
- Your prompt is written to a temp file (
prompt_<task_id>.txt) inlog_dir. - The runner spawns
claude -p --output-format json --permission-mode <mode>(piped) orstart cmd /k claude @<prompt_file>via a.bat(windowed), passing your prompt and config. - The agent runs. In its prompt, you've instructed it to write its output to a specific file path.
- The runner polls for that file to appear (or, in piped mode, waits for the subprocess to exit), then reads and parses it.
- You get back
{result, session_id, session_log, elapsed, success, error}.
The auto→bypass permission-mode fallback handles the difference between Pro and Max/Team tiers transparently — first piped call probes the mode and the result is cached for the rest of the process.
Every call returns a dict:
| Key | Meaning |
|---|---|
result |
Parsed JSON from result_file, or raw text if parse_json=False, or None on failure / fire-and-forget |
session_id |
Claude Code session UUID — useful for resuming later |
session_log |
Stdout from the CLI (empty in windowed mode — output went to the window) |
elapsed |
Wall-clock seconds |
success |
True if the result file was written and parsed |
error |
Error string, or None on success |
status |
"spawned" if wait_for_result=False or resume=True, otherwise absent |
- The agent has to play along. Your prompt must tell it to write to the result file. If it forgets or writes the wrong format, you get an error back. Be explicit in the prompt about format and path.
- Windowed mode is Windows-only. It generates
.batfiles. Piped mode works everywhere Python andclaudework. - Permission modes vary by tier.
autorequires Max/Team/Enterprise/API and Claude Code v2.1.83+. The runner falls back tobypassPermissionsautomatically ifautois rejected. - No isolation between sessions by default. Concurrent calls share
os.environand the working directory unless you passenv=andcwd=per call. - This is not Anthropic-supported. It's a wrapper around their CLI's subprocess interface. Anything could change in a future CC release. Pin your CC version if you depend on this in production.
MIT — see LICENSE.