1345 words Slides

14.3 Headless Mode: Non-Interactive Automation

Course: Claude Code - Enterprise Development Section: 14 - CI/CD & Automation Length: 4-5 minutes Presenter: Daniel Treasure


Opening Hook

"So far we've shown Claude in interactive mode—you type, Claude responds, you approve actions. But in CI/CD, there's no human watching. Headless mode is Claude running with predefined permissions, outputting structured results, no waiting for approval. It's the foundation of all automation."


Key Talking Points

What to say:

  • Headless mode = non-interactive, runs from a single prompt, produces output, exits
  • Use the -p flag to provide a prompt, Claude processes it, prints result, no chat loop
  • Permission modes control what Claude can do without asking:
  • dontAsk: Auto-denies anything not explicitly whitelisted (safest for automation)
  • bypassPermissions: Auto-approves everything (only use in sandboxed environments)
  • acceptEdits: Auto-approves file edits but asks about bash (good for scripts with side effects)
  • Pair dontAsk with --allowedTools to whitelist exactly what Claude can do
  • Structured output with --output-format json makes automation easier downstream
  • Cost control with --max-turns and --max-budget-usd prevents runaway bills
  • Ephemeral runs with --no-session-persistence leave no trace on disk—useful for CI/CD isolation

What to show on screen:

  1. Terminal with a simple headless command: claude -p "analyze this file for bugs"
  2. Output appearing instantly, no prompt
  3. Example with --permission-mode dontAsk --allowedTools "Read" "Grep"
  4. Show --output-format json producing machine-readable output
  5. Compare with interactive mode (Chat loop) vs headless mode (one prompt → output)
  6. Demo cost control: --max-turns 3 --max-budget-usd 0.50

Demo Plan (Timed)

Time: 0:00-0:45 - Open a terminal - Show difference: interactive session (claude) vs headless (claude -p "...") - Run a simple headless command: claude -p "list all functions in this Python file" piping a file content - Show output—direct, clean, no back-and-forth

Time: 0:45-1:45 - Explain the 6 permission modes with a reference table on screen - Highlight dontAsk as the automation workhorse - Show the default mode: "Each action requires approval" - Show dontAsk mode: "Claude only uses whitelisted tools"

Time: 1:45-2:45 - Demo --allowedTools in action: bash claude \ --permission-mode dontAsk \ --allowedTools "Bash(npm test)" "Read" "Grep" \ -p "Run tests and report pass/fail rate" - Explain: Claude can call Bash (npm test only), Read files, and Grep—nothing else - Show Claude refusing to call any tool outside the whitelist

Time: 2:45-3:45 - Show --output-format json with --json-schema for structured output - Example: Claude outputs JSON that a downstream tool can parse - Demo piping: claude -p "..." --output-format json | jq .issues | wc -l - Mention --max-turns 3 to limit loops in complex tasks

Time: 3:45-4:30+ - Cost control: --max-budget-usd 0.50 cap - Session persistence: --no-session-persistence for ephemeral runs - Recap: headless is the backbone of CI/CD - Preview next: Unix utility (piping, chaining)


Code Examples & Commands

Basic Headless Command

# Simple analysis, no interaction
claude -p "Check this file for SQL injection vulnerabilities" < myfile.sql

dontAsk Mode with Whitelisting

claude \
  --permission-mode dontAsk \
  --allowedTools "Bash(npm:*)" "Read" "Grep" \
  -p "Install dependencies and run the test suite, report results"

Structured JSON Output

claude \
  --output-format json \
  --json-schema '{
    "type": "object",
    "properties": {
      "issues": {
        "type": "array",
        "items": {"type": "string"}
      },
      "severity": {
        "type": "string",
        "enum": ["low", "medium", "high"]
      }
    }
  }' \
  -p "Analyze code for security issues. Return JSON."

Cost Control & Budget Limits

claude \
  --max-turns 5 \
  --max-budget-usd 0.25 \
  -p "Refactor this function for performance"

Piping Input from Other Commands

# Pipe file content
cat myapp.py | claude -p "Suggest optimizations"

# Pipe git diff
git diff HEAD~1 | claude -p "Review changes for bugs"

# Piping from curl
curl https://example.com/data.json | claude -p "Extract and summarize users"

Chaining Claude Commands

# First command lists bugs, second command fixes the first bug
claude -p "List all bugs in this codebase" > bugs.txt
head -1 bugs.txt | xargs -I {} claude -p "Fix: {}"

Ephemeral Runs (No Session Persistence)

claude \
  --no-session-persistence \
  --permission-mode dontAsk \
  --allowedTools "Read" \
  -p "Quick analysis"

All 6 Permission Modes Comparison

# 1. Default (asks for each action)
claude -p "Check the code"

# 2. acceptEdits (auto-approve file edits, ask for bash)
claude --permission-mode acceptEdits -p "Refactor this file"

# 3. plan (read-only, no changes)
claude --permission-mode plan -p "Suggest improvements"

# 4. dontAsk (auto-deny unless whitelisted)
claude --permission-mode dontAsk --allowedTools "Read" -p "Analyze"

# 5. bypassPermissions (auto-approve everything—DANGEROUS, use in sandbox only)
claude --permission-mode bypassPermissions -p "Full automation"

# 6. delegate (used by SDK, not CLI)
# (SDK only)

Integration in CI/CD Script

#!/bin/bash
set -e

# Run tests with Claude automation
claude \
  --permission-mode dontAsk \
  --allowedTools "Bash(npm:*)" "Read" "Grep" \
  --max-turns 5 \
  --max-budget-usd 1.00 \
  -p "Run npm test and provide a summary"

# Capture exit code, fail the script if needed
if [ $? -ne 0 ]; then
  echo "Claude automation failed"
  exit 1
fi

echo "CI/CD step completed successfully"

Gotchas & Tips

  • dontAsk Bug #17360: In some versions (Jan 2026), dontAsk mode activated unexpectedly in interactive sessions. If you see "mode changed to dontAsk," it's a known issue. Report it and use a workaround: explicit --permission-mode flag.
  • Sub-agent Limits (Bug #11934): Sub-agents respect dontAsk even with --dangerously-skip-permissions. Plan for this if you're using sub-agents in automation.
  • Tool Patterns: --allowedTools "Bash(npm test:*)" means any npm test command. Bash(npm:*) means any npm command. Be specific to prevent unwanted access.
  • Max-turns Impact: --max-turns 3 limits reasoning loops. For simple tasks (analysis, review), 1-2 turns suffice. Complex refactoring may need 5+.
  • Budget Cap: --max-budget-usd 0.50 stops execution when the cap is hit mid-task. Don't set it too low; monitor costs first.
  • JSON Escaping: When passing --json-schema in bash scripts, escape or use a heredoc to avoid shell interpretation.
  • Output Capture: Use > output.txt or | jq to capture headless output for downstream processing.
  • Timeout: If running in CI/CD, set a timeout wrapper (e.g., timeout 10m claude ...) to prevent hanging.

Lead-out

"Headless mode is the engine of automation. With the right permission controls and output formatting, Claude runs reliably in any CI/CD system. But headless mode shines even more when you treat Claude as a Unix utility—piping, chaining, and composing with other tools. That's next."


Reference URLs


Prep Reading

  • Deep dive: Permissions Documentation — understand all 6 modes
  • Review: Both bug reports #17360 and #11934 to know the edge cases
  • Test: Run claude -p "hello" in headless mode—verify it works on your setup
  • Experiment: Create a .claude config file with default permission settings, test overrides
  • Verify: --output-format json --json-schema produces valid JSON for downstream tools

Notes for Daniel

  • Conceptual Shift: This video pivots from "Interactive" to "Automation." Tone: technical, matter-of-fact. Viewers are engineers building pipelines.
  • Pacing: Permission modes are dense. Use a visual table on screen. Give each mode 15-20 seconds.
  • dontAsk Deep Dive: Spend 60 seconds on dontAsk + --allowedTools. This is the magic that makes automation safe.
  • Live Demo Risk: Headless commands are fast and deterministic. Safe to demo live.
  • Bug Framing: Mention #17360 and #11934 neutrally—"There are known issues we're tracking." Not a weakness, just reality of beta software.
  • Smile Point: Show the piping example where git diff flows into Claude, Claude outputs JSON, jq parses it. That chain is elegant.
  • Common Q: "Is dontAsk slower?" Answer: Slightly faster—no permission UI. "Can I use dontAsk in interactive mode?" Answer: Not recommended; it disables human oversight.
  • Segue: "Now you have Claude running non-interactively. Let's treat it like a Unix tool—pipe, compose, integrate."