Headless mode is Claude Code with no human attached. No terminal, no approval prompts, no interactive UI. The agent takes a prompt from somewhere (a script, a cron job, a webhook), does its work, and writes its output somewhere. That's it. Headless is the prerequisite for running an agent on a schedule, inside a CI pipeline, or as part of a larger system. It's the first real step toward autonomy.
When you run claude normally, you get an interactive terminal session. You type things. The agent asks you for approvals. It waits when it's unsure. There's a human in the loop at every risky step.
When you run claude headless, all of that is gone. There's no terminal to type into, no human to ask. The agent gets its prompt from stdin (or a file), runs, and emits output to stdout. Approval prompts don't happen - they either pre-approve automatically (because you set up a tight allow list) or the action is denied (because nobody's there to say yes).
This is the mode you need when the agent is supposed to run when you're not at the computer.
The common thread: no human pressing "go." Each of these situations needs the agent to operate on its own, then hand back whatever it produced.
Claude Code's CLI supports headless mode with a few flags:
echo "Analyze yesterday's error logs and write a summary" \
| claude --headless --print --max-turns 50 --permission-mode auto
Breaking down the flags:
--headless, disable the interactive UI, read the prompt from stdin--print, write the final response to stdout and exit (don't hang)--max-turns N, hard cap on agent turns - this is your cost cap. Always set it.--permission-mode auto, use the allow/deny lists; don't prompt. Unknown actions get denied.--no-input, never ask the user for anything. Fail loudly instead.Three things shift when there's no human in the loop. If your agent was designed for interactive use, these will bite you.
This is where most headless agents go wrong. The permission list that worked great interactively might leave huge gaps in headless. Two things to check before you go unattended:
The rule: if you're not 100% sure what the agent might try, don't run it headless yet. Watch it interactively until the behavior is predictable, then graduate.
A shell script (or cron entry) pipes a fixed prompt into Claude:
#!/bin/bash
claude --headless --print --max-turns 50 << 'EOF'
Check yesterday's server logs for 5xx errors. Summarize
the top 3 into a markdown report. Post to Slack #alerts.
EOF
Simple. Runs wherever cron runs. Output goes where you redirect it. This is the pattern for most scheduled agents.
A web server accepts incoming webhooks (from Stripe, GitHub, Linear, whatever), formulates a prompt for the agent, runs it headless, and returns the response. The agent becomes an on-demand service other systems can trigger.
Inside a GitHub Action, after test failures, invoke Claude headless to analyze the failures, look for patterns, and open a GitHub issue. The agent becomes a teammate that reviews the build and files bugs. Works the same for any CI platform.
In interactive mode, you see what the agent's doing. In headless mode, if you don't log it, you'll never know. Every headless run should capture:
Logs should go somewhere you can search later - a file, a database, a logging service. The moment something goes wrong, the first thing you'll want is the log from that run. If it's not there, you're reverse-engineering from gut feel.
Each of these has burned somebody. The fixes are simple; just don't skip them.
Don't write an agent in headless mode from day one. Write it interactively. Watch it run on real tasks. Tune the permission list. Fix the weird edge cases you notice. Then graduate the class of task to headless.
The pattern that works: interactive for 50+ real runs without surprises, then headless with aggressive logging for another 50, then schedule it (see Scheduling). Skipping steps here is how agents cause real damage. Don't.
Andrej Karpathy - Let's reproduce GPT-2 (124M)