Claude Code headless mode runs the agent non-interactively: you pass the -p (or --print) flag with a prompt, Claude runs to completion, prints the result, and exits — no REPL, no keyboard, no one waiting at a terminal. That single flag turns an interactive coding assistant into a Unix-friendly command-line tool you can pipe into, wrap in a script, schedule with cron, or drop into a CI/CD pipeline. This guide covers how headless mode works in 2026, the flags that actually matter, how to get parseable JSON out of it, the permission and auth traps that quietly break unattended runs, and the lessons from running a headless Claude Code pipeline in production.
What is Claude Code headless mode?
Headless mode is Claude Code running without its interactive terminal UI. Add -p (short for --print) to any claude command and instead of opening the REPL, Claude reads the prompt, runs the full agent loop (reading files, running tools, editing code), then prints the final result and exits with a status code. It is the same agent that powers interactive Claude Code, just driven by a script instead of a human. As of 2026 the feature lives under the Agent SDK, which also ships as Python and TypeScript packages if you want callbacks and native message objects instead of shelling out.
claude -p "What does the auth module do?"
Because non-interactive mode reads from stdin, it composes like any other CLI tool. You can pipe a build log straight in and redirect the answer out:
cat build-error.txt | claude -p "concisely explain the root cause of this build error" > cause.txt
That composability (stdin in, text or JSON out, an exit code you can branch on) is the whole reason headless mode exists.
How to get structured output you can parse
Plain text is fine for a human reading a log, but automation needs structure. The --output-format flag accepts exactly three values: text (the default), json, and stream-json. The json format is the workhorse: it returns the answer plus session metadata in one object.
claude -p "Summarize this project" --output-format json | jq -r '.result'
The JSON payload includes result (the text), session_id, num_turns, is_error, duration_ms, and, critically for anyone running this at scale, total_cost_usd, a per-invocation cost figure so you can track spend without opening the dashboard. For machine-readable answers that conform to a shape you define, pair --output-format json with --json-schema '{...}'; the validated object comes back in a structured_output field. Use stream-json with --verbose when you want to render tokens as they arrive. Parse any of it with jq and you have a reliable programmatic interface.
Permissions: the part that trips everyone up
An interactive session asks before it runs a shell command or edits a file. A headless run has no one to ask, so by default it will refuse the action and can stall your pipeline. You have to grant permission up front. The cleanest tool is --allowedTools, a comma-separated allowlist:
claude -p "Run the test suite and fix any failures" --allowedTools "Bash,Read,Edit"
For finer control the flag uses permission rule syntax, so --allowedTools "Bash(git diff *)" allows only commands starting with git diff. To set a baseline for the whole run instead of listing tools, pass a --permission-mode: acceptEdits lets Claude write files and run common filesystem commands without prompting, while dontAsk denies anything not explicitly allowed, which is the right choice for a locked-down CI job. The blunt instrument, --dangerously-skip-permissions, approves everything and should only touch a throwaway sandbox or container, never a machine with credentials or production access.
Authentication: API key vs OAuth token
Headless runs need credentials that don't involve a browser login, and there are two honest paths. The first is ANTHROPIC_API_KEY, a key from the Anthropic Console billed per token, the natural fit for CI runners and pay-as-you-go automation. The second lets you reuse an existing subscription: run claude setup-token once, complete the OAuth flow in a browser, and it prints a one-year token you export as CLAUDE_CODE_OAUTH_TOKEN. That token is tied to a Pro, Max, Team, or Enterprise plan and scoped to inference only. Pick by billing model: metered API usage for burst CI workloads, the subscription token for a steady always-on agent. One caveat for scripted calls: --bare mode (which skips auto-discovery of hooks, skills, and MCP servers for reproducible runs) also skips OAuth, so under --bare you must supply ANTHROPIC_API_KEY.
Running Claude Code in CI/CD and on cron
Once a single command works non-interactively, scheduling it is ordinary DevOps. A cron entry that runs claude -p on a VPS turns the agent into a task that fires on its own: triaging logs at 2 a.m., drafting a changelog, or fixing lint on a schedule. In a pipeline, wrap the call in a script that pipes a diff in and branches on the exit code; Anthropic ships first-party GitHub Actions and GitLab CI/CD integrations for exactly this. Two flags matter for unattended reliability. Add --bare so runs don't silently inherit whatever hooks or MCP servers happen to sit in a teammate's ~/.claude, so you get the same result on every machine. And use --continue or --resume <session_id> when a job needs several turns that build on each other, capturing the session ID from the JSON output of the first call. If you are standing up the box yourself, our guide to self-hosting apps on a VPS covers the cron and hardening basics that keep a scheduled agent healthy.
| Flag | What it does | When you need it |
|---|---|---|
-p / --print | Run non-interactively, print result, exit | Every headless run |
--output-format json | Structured result with cost + session metadata | Any scripted caller |
--json-schema | Force output into a schema (structured_output) | Machine-readable extraction |
--allowedTools | Pre-approve specific tools | Stop the run stalling on prompts |
--permission-mode | Session-wide baseline (acceptEdits, dontAsk) | Locked-down CI |
--bare | Skip auto-discovery for reproducible runs | CI and SDK calls |
--continue / --resume | Multi-turn conversations across calls | Stateful jobs |
What we learned running a headless content engine
We use Claude Code headless in production ourselves: the pipeline that researches, writes, and publishes articles here at TechRiseUps runs as a scheduled claude -p job on our own WaseerHost infrastructure, driven by a custom skill rather than a person at the keyboard. A few lessons held up that the docs only hint at.
Permissions are the number one cause of a "stuck" run: a job that seems to hang is almost always Claude waiting for an approval that will never come, so pre-approve every tool the task genuinely needs and nothing more. Read total_cost_usd from the JSON on every invocation and log it; unattended agents have no natural cost ceiling, and the per-run figure is the only cheap way to catch a task that spiralled. Make each run idempotent, because a cron job will eventually fire twice or resume mid-way, and an agent that appends blindly makes a mess. And for long-running jobs that fan out with background subagents, raise the process file-descriptor limit, because a headless agent opening many files and sockets can silently hit the default ulimit and stall with no obvious error. None of these are exotic; they are the boring operational hygiene that separates a demo from a pipeline you trust to run while you sleep.
Frequently asked questions
What is headless mode in Claude Code?
It is Claude Code running non-interactively via the -p / --print flag. Claude reads a prompt, runs the full agent loop, prints the final result, and exits, with no interactive terminal. It is meant for scripts, pipes, cron jobs, and CI/CD rather than hands-on coding.
How do I run Claude Code headless without paying for API keys?
Generate a subscription-backed token with claude setup-token, then export it as CLAUDE_CODE_OAUTH_TOKEN. It authenticates against a Pro, Max, Team, or Enterprise plan instead of metered API billing. Note that --bare mode bypasses OAuth and still requires ANTHROPIC_API_KEY.
How do I stop Claude Code from asking for permission in headless mode?
Pre-approve tools with --allowedTools "Bash,Read,Edit", or set a session baseline with --permission-mode acceptEdits (or dontAsk for locked-down CI). Only use --dangerously-skip-permissions inside a disposable sandbox, never on a machine with real credentials.
Can I run Claude Code headless from Python?
Yes. Headless mode is part of the Agent SDK, which ships as Python and TypeScript packages in addition to the claude -p CLI. Use the SDK packages when you want tool-approval callbacks, native message objects, and structured outputs without parsing stdout.
Is headless mode the same as the Claude Agent SDK?
They are two front doors to the same engine. claude -p is the CLI form of the Agent SDK — same tools, agent loop, and context management. The Python and TypeScript SDK packages give you fuller programmatic control for building agents into applications.
Sources
- Claude Code Docs — Run Claude Code programmatically (headless): the
-p/--printflag,--output-format,--bare, permissions,--continue/--resume, and JSON result fields. - Claude Code Docs — Authentication:
claude setup-token,CLAUDE_CODE_OAUTH_TOKEN, and how subscription tokens differ fromANTHROPIC_API_KEY. - Claude Code Docs — GitHub Actions: first-party CI integration for running the agent in pipelines.
Some links may earn us a commission at no extra cost to you.
Waqas Ahmed Waseer
Waqas Ahmed Waseer is a developer and automation builder with 8+ years shipping production systems used by 100k+ people. He builds custom multi-tenant SaaS, AI automation (n8n, LLM workflows, WhatsApp bots) and hosting infrastructure (WHM/cPanel, CloudLinux) — and is the maker of WaSphere, FlowMaticX, and the WaseerHost hosting brand. 100+ projects delivered for SMBs, agencies and funded startups.



