Most people interact with Claude Code through its interactive terminal, typing prompts and approving actions one at a time. That’s great for exploration, but once you know what you want Claude to do, there’s a more powerful way to use it: headless. No interactive session, no permission prompts, just a command that runs and produces output. This is what makes Claude Code useful in scripts, CI pipelines and automation workflows.
Print mode
The -p (or --print) flag is the foundation. It turns Claude Code into a non-interactive tool that processes a prompt and exits. No conversation, no back-and-forth:
1claude -p "explain the authentication flow in this project"
You can pipe content into it:
1cat src/auth/session.ts | claude -p "find potential security issues"
And you can control the output format, which is where it gets interesting for automation:
1claude -p "list all TODO comments" --output-format json
The json and stream-json output formats let you parse Claude’s responses programmatically. Combined with --max-turns to limit how many agentic steps it takes and --max-budget-usd to cap spending, you have decent control over what the process does and what it costs.
Continuing conversations in print mode
Print mode isn’t limited to one-shot prompts. You can continue a previous conversation with
-c -p, which is useful when you need to run a multi-step workflow where each step builds on the previous one. Session IDs let you target a specific conversation if you’re managing several in parallel.
Dangerous mode
Here’s where things get interesting - and where you need to be careful. By default, Claude Code asks for permission before running commands, editing files or doing anything that could have side effects. In print mode, this means it’ll just stop and wait for approval that nobody’s there to give.
The --dangerously-skip-permissions flag does exactly what it says: it skips all permission prompts. Claude Code will execute whatever it decides is necessary without asking. This is the flag that makes fully autonomous operation possible, and it’s also the flag that can ruin your day if you’re not careful about where you use it.
1claude -p --dangerously-skip-permissions "refactor the payment module to use the new API"
There’s a more nuanced option too: --allow-dangerously-skip-permissions enables the capability without immediately activating it. You can combine this with --permission-mode to start in a restricted mode (like plan, which only allows read operations) while still having the option to escalate:
1claude --permission-mode plan --allow-dangerously-skip-permissions
You can also selectively allow specific tools without going full dangerous mode. The --allowedTools flag lets you whitelist exactly what Claude can do:
1claude -p --allowedTools "Bash(git log *)" "Bash(git diff *)" "Read" "explain this PR"
This is the middle ground that makes the most sense for CI pipelines: give Claude Code read access and specific safe commands, without handing it the keys to the kingdom.
The sandbox flag
If you’ve read the sandboxing post, you know about the interactive /sandbox command. But in headless mode, you configure it through settings. You can pass a settings file directly:
1claude -p --settings ./ci-settings.json "run the test suite and fix failures"
Where ci-settings.json contains your sandbox configuration:
1{
2 "sandbox": {
3 "enabled": true,
4 "autoAllow": true,
5 "filesystem": {
6 "allowWrite": ["//tmp/test-output"]
7 },
8 "allowedDomains": ["registry.npmjs.org", "github.com"]
9 }
10}
This gives you the best of both worlds for automation: Claude Code can run commands autonomously within the sandbox boundaries (no permission prompts needed), and the OS-level isolation prevents it from doing anything outside those boundaries. You don’t need --dangerously-skip-permissions at all if the sandbox covers your use case - sandboxed commands are auto-approved when autoAllow is enabled.
Putting it together
A realistic CI example might look something like this:
1claude -p \
2 --model sonnet \
3 --output-format json \
4 --max-turns 10 \
5 --max-budget-usd 2.00 \
6 --settings ./ci-settings.json \
7 "run the tests, if any fail, fix them and run again"
This runs Sonnet (faster, cheaper), caps the operation at 10 turns and $2, sandboxes all commands through the settings file, and returns structured JSON you can parse in your pipeline.
The combination of print mode, selective permissions and sandboxing means you can integrate Claude Code into automation with a level of control that would have been difficult to achieve even six months ago. The key is being deliberate about which combination you use: sandbox for most CI work, --allowedTools when you need specific capabilities outside the sandbox, and --dangerously-skip-permissions only when you truly understand the implications and have other safety nets in place.