Claude Code --bare: the flag the docs want to be the default
There's a note in the Claude Code headless-mode docs that is going to quietly reshape every CI pipeline using claude -p:
--bareis the recommended mode for scripted and SDK calls, and will become the default for-pin a future release.
Translation: if you run Claude Code in CI today, you probably don't want the default. You want bare. Here's what that means and why.
What bare mode actually turns off
When you run claude -p "do a thing" without --bare, Claude Code loads the same context an interactive session would, including anything in the working directory or ~/.claude. That means:
- Hooks, skills, and plugins from
~/.claude - MCP servers from
.mcp.json - Auto memory
CLAUDE.mdauto-discovery walking up from the cwd- OAuth and keychain lookups for authentication
Add --bare and none of that runs. No hooks. No skills. No MCP. No memory. No CLAUDE.md. No keychain. The CLI becomes a reproducible black box: the only inputs are the flags you explicitly passed.
claude --bare -p "Summarize this file" --allowedTools "Read"Why CI wants this
Because the scariest thing in a production automation is hidden state. You SSH into the box at 2am, run the command that's been green for months, and it fails. Why? Because a teammate added a hook to their global ~/.claudethat your CI image happens to have mounted, or an MCP server in the project's .mcp.json is down, or CLAUDE.md picked up a stray instruction from a parent directory nobody remembered.
Bare mode is the promise that the same command, run against the same commit, produces the same agent setup. No environmental drift. No spooky action from files nobody knew were there.
Passing context back in explicitly
The cost of bare mode is that you give up the convenience of auto-discovery. If your CI job genuinely needs an MCP server, a system prompt addition, or a custom agent, bare mode doesn't load them — you pass them in with flags. The docs give the mapping:
| To load | Use |
|---|---|
| System prompt additions | --append-system-prompt, --append-system-prompt-file |
| Settings | --settings <file-or-json> |
| MCP servers | --mcp-config <file-or-json> |
| Custom agents | --agents <json> |
| A plugin directory | --plugin-dir <path> |
Every one of these is a file or JSON object that lives in your repo and gets versioned with your code. That's the shift: context goes from “whatever was in the environment” to “whatever you committed.”
Auth in bare mode
Bare mode skips OAuth and keychain reads, which sounds breaking and mostly isn't. Anthropic authentication has to come from an environment variable (ANTHROPIC_API_KEY) or an apiKeyHelper in the JSON you pass to --settings. Bedrock, Vertex, and Foundry continue to use their usual provider credentials. CI already wants API keys from secrets, not from a keychain that doesn't exist on the runner, so the constraint aligns with reality.
A bare-mode CI invocation
# GitHub Actions step — fully reproducible
- name: Run Claude Code security sweep
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
claude --bare -p "$(cat .claude-prompts/security-sweep.md)" \
--allowedTools "Bash(git:*),Bash(npm audit),Read,Grep" \
--max-turns 60 \
--max-budget-usd 3 \
--output-format json \
--append-system-prompt-file .claude-prompts/sweep-persona.md \
> sweep-result.jsonEverything this run depends on is either a flag, a file in the repo, or a secret. Swap in a different Claude version, different machine, different month — same inputs, same shape of output.
Where bare mode stops being enough
Bare mode makes one claude -pcall deterministic. It does nothing for the layer above: scheduling runs, assigning work, tracking state across invocations, approving destructive edits mid-run, streaming progress to a human. Those are agent concerns, and once you've tasted the reproducibility of bare mode you're going to want the same discipline around the whole loop.
That's where background agents on Linear come in: same bare-mode runs underneath, with webhooks, worktrees, and streaming events on top.
Takeaways
--baremakesclaude -preproducible by skipping hooks, skills, plugins, MCP servers, auto memory, CLAUDE.md discovery, OAuth, and the keychain.- Anything you need in a bare run, you pass explicitly: system-prompt file, settings JSON, MCP config, agents, plugin directory.
- Auth must come from
ANTHROPIC_API_KEYor anapiKeyHelperin--settings. - The docs call it the recommended mode for scripted and SDK calls, and say it'll become the default for
-pin a future release. Use it now, save yourself the migration.
Bare runs are the floor. Cyrus is the ceiling.
Cyrus runs Claude Code in isolated git worktrees per Linear issue, with BYOK across Claude / Codex / Cursor / Gemini, streaming activity back to the issue as it happens. Community self-hosted is free forever.
Try Cyrus free →