using-claude-code-cli

Invoke Claude Code CLI from Python orchestrators and shell scripts. Use when asked to "spawn claude as subprocess", "automate claude cli", "run claude headless", "configure --allowedTools", "set up cl

SKILL.md

GitHub

Using Claude Code CLI

Patterns for programmatically invoking Claude Code CLI from orchestrators, scripts, and automation pipelines.

Contents

Quick Start Checklist

Copy and track as you work:

CLI Automation Setup:
- [ ] 1. Identify required tools, add to --allowedTools
- [ ] 2. List directories Claude needs, add to --add-dir
- [ ] 3. Choose pattern: sync, async, or parallel (see references/)
- [ ] 4. Configure hooks if logging/monitoring needed
- [ ] 5. Enable sandbox mode for untrusted operations
- [ ] 6. Add fallback strategy if using OpenCode backup
- [ ] 7. Test with simple prompt before full automation
- [ ] 8. Validate setup (see Validation section)

Essential Commands

Minimal automation:

claude -p "Your prompt" --allowedTools Write Read Edit --max-turns 5

Full automation:

claude \
  --model sonnet \
  --add-dir /path/to/skills \
  --add-dir /path/to/templates \
  --allowedTools Write Read Edit Bash Task \
  --output-format json \
  -p "Your automation prompt"

With settings JSON:

claude --settings '{"hooks":{},"sandbox":{"enabled":true}}' -p "prompt"

Core CLI Flags

Flag Purpose Example
-p Non-interactive mode (required) claude -p "query"
--allowedTools Pre-approve tools --allowedTools Write Read Bash
--add-dir Grant directory access --add-dir ../lib
--settings Pass hooks/permissions JSON --settings ./settings.json
--model Select model --model sonnet
--output-format Output: text, json, stream-json --output-format json
--max-turns Limit agentic turns --max-turns 5

Recommended tools for automation:

  • Core: Write, Read, Edit, Glob, Grep, LS
  • Automation: Bash, Task, Skill
  • Web: WebFetch, WebSearch

MCP tools require full path:

--allowedTools "mcp__perplexity-ask__perplexity_ask"
--allowedTools "mcp__context7__get-library-docs"

See references/cli-reference.md for complete flag documentation.

Sandbox Mode

Enable sandbox for safe file operations:

Via settings JSON:

claude --settings '{"sandbox":{"enabled":true,"autoAllowBashIfSandboxed":true}}' -p "prompt"

Via stdin (pass /sandbox before prompt):

stdin_content = "/sandbox\nYour actual prompt"
subprocess.run(["claude", "-p"], input=stdin_content, text=True)

See references/hooks-examples.md for full sandbox options.

Validation

Before full automation, verify setup works:

# 1. Test tool pre-approval (should complete without prompts)
claude -p "Create file test.txt with 'hello'" --allowedTools Write

# 2. Test directory access
claude -p "List files in /path/to/dir" --add-dir /path/to/dir --allowedTools LS

# 3. Test JSON output
claude -p "Return {\"status\": \"ok\"}" --output-format json | jq .

# 4. Test hooks (check log file after)
claude --settings '{"hooks":{...}}' -p "Simple task" --allowedTools Read

If any step fails, see Troubleshooting.

Troubleshooting

Problem Solution
Permission prompts appearing Verify tool names match exactly (case-sensitive); MCP tools need full path
Hooks not firing Check script is executable (chmod +x), has shebang, timeout not exceeded
Subprocess hangs Add timeout; check if waiting for permission (missing --allowedTools)
Working directory issues Use absolute paths in --add-dir; set cwd in subprocess
JSON parse errors Use --output-format json; see json-extraction.md

When Not to Use

This skill is for subprocess invocation. Do not use for:

  • Interactive Claude sessions (use Claude directly)
  • API integration (use Claude SDK/API)
  • MCP server setup (use claude mcp command)

Reference Files

File Contents
cli-reference.md Complete CLI commands and flags
subprocess-patterns.md Python sync/async/parallel patterns
hooks-examples.md Hook scripts and settings JSON
json-extraction.md Parsing JSON from CLI output
orchestrator_example.py Complete Python orchestrator class

OpenCode CLI Fallback

When using OpenCode as fallback, note key differences:

Feature Claude CLI OpenCode CLI
Headless claude -p "prompt" opencode run "prompt"
Model --model sonnet --model provider/model
Settings --settings JSON Not supported
Add dirs --add-dir /path Not supported

Try-Claude-then-OpenCode pattern:

import subprocess

def invoke_with_fallback(prompt: str, timeout: int = 300) -> str:
    """Try Claude CLI first, fall back to OpenCode on failure."""
    try:
        result = subprocess.run(
            ["claude", "-p", prompt, "--allowedTools", "Write", "Read"],
            capture_output=True, text=True, timeout=timeout
        )
        if result.returncode == 0:
            return result.stdout
    except (subprocess.TimeoutExpired, FileNotFoundError):
        pass  # Fall through to OpenCode

    result = subprocess.run(
        ["opencode", "run", prompt],
        capture_output=True, text=True, timeout=timeout
    )
    return result.stdout

See subprocess-patterns.md for advanced patterns.