Skip to content

Headless Mode ​

Run CodeBuddy Code programmatically without an interactive UI

Overview ​

Headless mode allows you to run CodeBuddy Code programmatically through command-line scripts and automation tools without any interactive UI.

Headless mode also supports scheduled task capabilities. In script, SDK, or server-side integration scenarios, you can use tools such as CronCreate, CronList, and CronDelete to create, view, and cancel scheduled tasks.

⚠️ Important Note: -y (or --dangerously-skip-permissions) is a required parameter for non-interactive mode. When using the -p/--print parameter for non-interactive execution, this parameter must be added to perform operations that require authorization (file read/write, command execution, network requests, etc.), otherwise these operations will be blocked. Only use this parameter in trusted environments and explicit task scenarios. See CLI Reference for details.

Basic Usage ​

The primary command-line interface for CodeBuddy Code is the codebuddy (or cbc) command. Use the --print (or -p) flag to run in non-interactive mode and print the final result:

bash
codebuddy -p "Stage my changes and write a set of commits for them" \
  --allowedTools "Bash,Read" \
  --permission-mode acceptEdits

Configuration Options ​

Headless mode leverages all available CLI options in CodeBuddy Code. Here are key options for automation and scripting:

FlagDescriptionExample
--print, -pRun in non-interactive modecodebuddy -p "query"
--output-formatSpecify output format (text, json, stream-json)codebuddy -p --output-format json
--resume, -rResume a conversation by session IDcodebuddy --resume abc123
--continue, -cContinue the most recent conversationcodebuddy --continue
--verboseEnable verbose loggingcodebuddy --verbose
--append-system-promptAppend to system prompt (only works with --print)codebuddy --append-system-prompt "Custom instructions"
--allowedToolsList of allowed tools, space-separated or

comma-separated string
codebuddy --allowedTools mcp__slack mcp__filesystem

codebuddy --allowedTools "Bash(npm install),mcp__filesystem"
--disallowedToolsList of disallowed tools, space-separated or

comma-separated string
codebuddy --disallowedTools mcp__splunk mcp__github

codebuddy --disallowedTools "Bash(git commit),mcp__github"
--settingsLoad additional settings configuration from a JSON file or JSON stringcodebuddy -p --settings '{"model":"gpt-5"}' "query"
--setting-sourcesSpecify which settings sources to load (options: user, project, local)codebuddy -p --setting-sources project,local "query"
--mcp-configLoad MCP servers from a JSON filecodebuddy --mcp-config servers.json
--permission-prompt-toolMCP tool for handling permission prompts (only works with --print)❌ Not supported

Note: The --permission-prompt-tool feature is currently not supported.

For a complete list of CLI options and features, please refer to the CLI Reference documentation.

Multi-turn Conversations ​

For multi-turn conversations, you can resume a conversation or continue from the most recent session:

bash
# Continue the most recent conversation
codebuddy --continue "Now refactor for better performance"

# Resume a specific conversation by session ID
codebuddy --resume 550e8400-e29b-41d4-a716-446655440000 "Update tests"

# Resume in non-interactive mode
codebuddy --resume 550e8400-e29b-41d4-a716-446655440000 "Fix all linting issues" -p

Output Formats ​

Text Output (Default) ​

bash
codebuddy -p "Explain the file src/components/Header.tsx"
# Output: This is a React component that displays...

JSON Output ​

Returns structured data with metadata:

bash
codebuddy -p "How does the data layer work?" --output-format json

Response format:

json
{
 ...
}

Stream JSON Output ​

Streams as each message is received:

bash
codebuddy -p "Build an application" --output-format stream-json

Each conversation begins with an initial init system message, followed by a list of user and assistant messages, and ends with a final result system message containing statistics. Each message is emitted as a separate JSON object.

Background Task Events (Async) ​

When the model launches a background command (Bash / PowerShell), background workflow, or background Agent sub-task with run_in_background: true, the CLI emits a separate system event on the stream-json output stream for each task, carrying a unique task_id (used to distinguish concurrent tasks), with tool_use_id linking back to the tool_use that initiated the task:

  • Task started β†’ system / subtype: "task_started"
  • Task progress (emitted per completed tool_use, sub-agent/workflow only) β†’ system / subtype: "task_progress" (with usage)
  • Task status change β†’ system / subtype: "task_updated" (with patch)
  • Task completed/failed/stopped β†’ system / subtype: "task_notification"
jsonc
// Task started (pushed immediately when entering running state)
{"type":"system","subtype":"task_started","task_id":"agent-00f6","tool_use_id":"toolu_01","description":"bg agent","task_type":"Agent","uuid":"...","session_id":"..."}
// Progress (per completed tool_use, carries cumulative usage + last tool name; shell tasks do not emit)
{"type":"system","subtype":"task_progress","task_id":"agent-00f6","description":"bg agent","usage":{"total_tokens":320,"tool_uses":2,"duration_ms":157},"last_tool_name":"Bash","uuid":"...","session_id":"..."}
// Status change (patch carries changed fields; terminal state adds end_time)
{"type":"system","subtype":"task_updated","task_id":"agent-00f6","patch":{"status":"completed","end_time":1783945615966},"status":"completed","uuid":"...","session_id":"..."}
// Task completed (may arrive after the triggering turn's result; sub-agent carries usage)
{"type":"system","subtype":"task_notification","task_id":"agent-00f6","tool_use_id":"toolu_01","status":"completed","summary":"Background agent \"bg agent\" completed","output_file":"/.../bg-tasks/agent-00f6.stdout.log","usage":{"total_tokens":480,"tool_uses":2,"duration_ms":250},"session_id":"..."}

Field descriptions:

FieldEventDescription
task_idAllUnique ID for the background task, persists across started β†’ progress β†’ updated β†’ notification; used to distinguish concurrent tasks and route to TaskOutput
tool_use_idMost (optional)Links back to the model's tool_use
description / task_typestarted / progressTask command description / tool type (Bash / PowerShell / Workflow / Agent)
usageprogress (always present) / notification (present for sub-agent, omitted for shell){ total_tokens, tool_uses, duration_ms } (aligns with CC's TaskUsage)
last_tool_nameprogress (optional)Name of the most recently executed tool
patch / statusupdatedChanged fields in this update (at least status; terminal state adds end_time)
statusnotificationcompleted / failed / stopped (killed/cancelled normalized to stopped)
summarynotificationHuman-readable completion summary
output_file / output_stderr_filenotification (optional)On-disk output path for the background task (file mode); use this to read the full output

Progress events (task_progress) are event-driven (one emitted per completed tool_use), not polled on a timer; background shell tasks (Bash/PowerShell) do not emit progressβ€”only sub-agent / workflow tasks do.

Terminal state may arrive only via task_updated: Some background tasks reach their terminal state solely through task_updated (patch.status set to a terminal value) without a corresponding task_notification. Consumers tracking "active tasks" should treat the terminal status (completed / failed / stopped / killed) from both events equally when cleaning up.

Important (stdio long-lived connection scenario): Background tasks may complete after the result of the turn that triggered them. When using --input-format stream-json --output-format stream-json (a long-lived connection with stdin kept open), the CLI proactively pushes task_notification back to the same output stream after the task truly finishesβ€”no need to send new input. Consumers should therefore keep reading the output stream and must not stop after receiving the first result, or they will miss background completion events. Pure -p single-shot mode (process exits after the first result) does not support background tasks and returns an explicit error.

Disabling background tasks: In scenarios that do not support or need background tasks, set the environment variable CODEBUDDY_CODE_DISABLE_BACKGROUND_TASKS=1 to disable themβ€”the run_in_background parameter for Bash / PowerShell / Agent is hidden from the tool schema, and even if the model still sends it, it will be ignored/degraded to foreground execution, producing no background task events and no cross-turn push-back. The SDK's query() single-shot usage automatically injects this variable (since query() stops at the first result and cannot receive cross-turn push-back events); continuously-reading SDK usage (JS unstable_v2_createSession / Python CodeBuddySDKClient) is unaffected.

Structured JSON Output ​

To get output that conforms to a specific schema, use --output-format json with --json-schema and a JSON Schema definition. The response includes metadata about the request (session ID, usage, etc.), with the structured output in the structured_output field.

This example extracts function names from auth.py and returns them as an array of strings:

bash
codebuddy -p "Extract the main function names from auth.py" \
  --output-format json \
  --json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}'

Tip: Use tools like jq to parse the response and extract specific fields:

bash
# Extract text result
codebuddy -p "Summarize this project" --output-format json | jq -r '.result'

# Extract structured output
codebuddy -p "Extract function names from auth.py" \
  --output-format json \
  --json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}' \
  | jq '.structured_output'

Input Formats ​

Text Input (Default) ​

bash
# Direct argument
codebuddy -p "Explain this code"

# From stdin
echo "Explain this code" | codebuddy -p

Stream JSON Input ​

A stream of messages provided via stdin, where each message represents a user turn. This allows for multi-turn conversations without restarting the codebuddy binary, and allows providing guidance to the model while it processes requests.

Each message is a JSON "user message" object following the same format as the output message schema. Messages are formatted using jsonl format, where each line of input is a complete JSON object. Stream JSON input requires -p and --output-format stream-json.

bash
echo '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"Explain this code"}]}}' | \
  codebuddy -p --output-format=stream-json --input-format=stream-json --verbose

# Single message (with image)
echo '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"Text prompt, such as referring to the text in the following image"},{"type":"image","source":{"type":"base64","media_type":"image/png","data":"raw base64 (without protocol prefix)"}}]}}' \
  | codebuddy -p --input-format stream-json --output-format stream-json

# Multi-turn conversation (multi-line JSON, continuously sent to the same process)
printf '%s\n' \
  '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"First question"}]}}' \
  '{"type":"user","message":{"role":"user","content":[{"type":"text","text":"Second question"}]}}' \
  | codebuddy -p --input-format stream-json --output-format stream-json --verbose

Agent Integration Examples ​

SRE Incident Response Bot ​

bash
#!/bin/bash

# Automated incident response agent
investigate_incident() {
    local incident_description="$1"
    local severity="${2:-medium}"

    codebuddy -p "Incident: $incident_description (Severity: $severity)" \
      --append-system-prompt "You are an SRE expert. Diagnose the issue, assess impact, and provide immediate action items." \
      --output-format json \
      --allowedTools "Bash,Read,WebSearch,mcp__datadog" \
      --mcp-config monitoring-tools.json
}

# Usage
investigate_incident "Payment API returning 500 errors" "high"

Automated Security Review ​

bash
# Security audit agent for PRs
audit_pr() {
    local pr_number="$1"

    gh pr diff "$pr_number" | codebuddy -p \
      --append-system-prompt "You are a security engineer. Review this PR for vulnerabilities, unsafe patterns, and compliance issues." \
      --output-format json \
      --allowedTools "Read,Grep,WebSearch"
}

# Use and save to file
audit_pr 123 > security-report.json
bash
# Legal document review with session persistence
session_id=$(codebuddy -p "Start legal review session" --output-format json | jq -r '.session_id')

# Review contract in multiple steps
codebuddy -p --resume "$session_id" "Review liability clauses in contract.pdf"
codebuddy -p --resume "$session_id" "Check compliance with GDPR requirements"
codebuddy -p --resume "$session_id" "Generate executive summary of risks"

Best Practices ​

  • Use JSON output format for programmatically parsing responses:

    bash
    # Parse JSON response using jq
    result=$(codebuddy -p "Generate code" --output-format json)
    code=$(echo "$result" | jq -r '.result')
    cost=$(echo "$result" | jq -r '.total_cost_usd')
  • Handle errors gracefully - Check exit codes and stderr:

    bash
    if ! codebuddy -p "$prompt" 2>error.log; then
        echo "An error occurred:" >&2
        cat error.log >&2
        exit 1
    fi
  • Use session management to maintain context across multi-turn conversations

  • Consider timeouts for long-running operations:

    bash
    timeout 300 codebuddy -p "$complex_prompt" || echo "Timed out after 5 minutes"
  • Respect rate limits when making multiple requests, by adding delays between calls

  • Use -y to perform operations requiring authorization in non-interactive mode:

    bash
    # Complete example in non-interactive mode
    codebuddy -p "Analyze code and run tests" \
      --output-format json \
      -y \
      --allowedTools "Bash,Read,Grep"

    ⚠️ Important Note: -y (or --dangerously-skip-permissions) is a required parameter for non-interactive mode. When using the -p/--print parameter for non-interactive execution, this parameter must be added to perform operations that require authorization (file read/write, command execution, network requests, etc.), otherwise these operations will be blocked. Only use this parameter in trusted environments and explicit task scenarios. See CLI Reference for details.


Tip: Headless mode is ideal for CI/CD pipelines, automation scripts, and agent integrations. Combine it with MCP servers to extend functionality.