Skip to main content
The Claude Code agent plugin integrates Anthropic’s Claude CLI into the Agent Orchestrator, providing post-launch prompt delivery, automatic PR metadata updates, and cost tracking via JSONL session introspection.

Overview

Claude Code is Anthropic’s official CLI for AI-assisted coding. The plugin:
  • Launches Claude in interactive mode (not one-shot)
  • Delivers prompts post-launch via sendMessage() to keep Claude in conversation mode
  • Automatically updates session metadata on PR creation and git operations via PostToolUse hooks
  • Extracts cost, token usage, and summaries from Claude’s JSONL session files
  • Detects activity state by monitoring JSONL file modifications
This plugin requires Claude Code CLI to be installed. Get it from Anthropic’s website.

Installation

# Install Claude Code CLI
npm install -g @anthropic-ai/claude-code

# Verify installation
which claude

Configuration

Configure in agent-orchestrator.yaml:
plugins:
  agent: claude-code

projects:
  - name: my-project
    path: ~/code/my-project
    agentConfig:
      model: claude-sonnet-4.5
      permissions: suggest
      systemPrompt: |
        You are a senior engineer working on a production codebase.
        Always write tests for new features.

Configuration Options

model
string
Claude model to use (e.g., claude-sonnet-4.5, claude-opus-4)
permissions
enum
Permission mode:
  • skip: Auto-approve all operations (--dangerously-skip-permissions)
  • suggest: Prompt for untrusted operations (default)
  • ask: Always prompt
systemPrompt
string
Additional instructions appended to Claude’s system prompt
systemPromptFile
string
Path to a file containing system prompt (preferred for long prompts)

Automatic Metadata Updates

The plugin installs a PostToolUse hook script (.claude/metadata-updater.sh) that automatically updates session metadata when agents run specific commands:

Tracked Commands

CommandMetadata Updated
gh pr createpr (URL), status (pr_open)
git checkout -b <branch>branch
git switch -c <branch>branch
gh pr mergestatus (merged)
  1. Claude Code invokes PostToolUse hooks after each Bash tool call
  2. Hook script receives JSON with tool name, command, and output
  3. Script parses output for PR URLs or branch names
  4. Updates ~/.ao-sessions/<project>/<session-id> via update_metadata_key()
  5. Orchestrator reads updated metadata on next refresh
The hook is automatically installed on agent launch via postLaunchSetup().

Manual Metadata Updates

If hooks fail or you need custom metadata:
# In the agent's workspace, source the helper
source .claude/metadata-updater.sh

# Update any key
update_metadata_key custom_field "value"

Session Introspection

The plugin reads Claude’s JSONL session files from ~/.claude/projects/{encoded-path}/ to extract:

Cost Tracking

Token usage and estimated costs from usage events:
// Aggregates all token_count events in the session
const cost: CostEstimate = {
  inputTokens: 125000,
  outputTokens: 15000,
  estimatedCostUsd: 0.60  // Based on Sonnet 4.5 pricing
};
Cost estimates use Sonnet 4.5 pricing (3/1Minput,3/1M input, 15/1M output) as a baseline. Actual costs may vary for Opus or Haiku models.

Session Summaries

Auto-generated summaries from Claude’s summary events:
{
  "summary": "Implemented user authentication with JWT tokens",
  "isFallback": false
}
If no summary exists, falls back to the first user message (truncated to 120 chars).

Activity Detection

The plugin monitors JSONL file modifications to detect agent state:
Last JSONL EventAgent StateCondition
user, tool_use, progressactiveRecent (< threshold)
assistant, result, summaryreadyRecent (< threshold)
permission_requestwaiting_inputAny time
errorblockedAny time
Any eventidleStale (> threshold)
No processexitedProcess not running
readyThresholdMs
number
default:"30000"
Time in milliseconds before an agent is considered idle

Usage Examples

Spawn an Agent

ao spawn my-project "Fix type errors in src/index.ts"
The orchestrator:
  1. Creates a workspace (git worktree or clone)
  2. Launches Claude with the prompt delivered post-launch
  3. Installs the metadata updater hook
  4. Monitors JSONL for activity and cost

Resume a Session

ao resume my-project agent-123
The plugin builds a restore command using the session UUID from Claude’s JSONL filename:
claude --resume abc123-def456 --model claude-sonnet-4.5

View Session Info

ao list --verbose
Output includes:
  • Session summary (from JSONL)
  • Estimated cost
  • Token usage
  • Activity state

Advanced Features

JSONL Path Encoding

Claude stores sessions at ~/.claude/projects/{encoded-path}/, where encoded-path is the workspace path with / and . replaced by -:
// /Users/dev/.worktrees/ao → Users-dev--worktrees-ao
function toClaudeProjectPath(workspacePath: string): string {
  return workspacePath.replace(/[/.]/g, "-");
}
If Claude changes this encoding scheme, session introspection will silently fail. Validate by checking if the resulting directory exists.

Long Command Handling

For system prompts exceeding 2000 characters, the plugin uses shell command substitution to avoid tmux truncation:
claude --append-system-prompt "$(cat /path/to/prompt.txt)"

Process Detection

The plugin checks if Claude is running by:
  1. Tmux runtime: Find the pane’s TTY, then search ps output for claude on that TTY
  2. Process runtime: Check if the PID in handle.data.pid is alive via process.kill(pid, 0)

Cache Optimization

The plugin caches ps output for 5 seconds to avoid spawning multiple concurrent ps processes when listing many sessions:
const PS_CACHE_TTL_MS = 5_000;
const psCache: { output: string; timestamp: number } | null;

Troubleshooting

Cause: Hook not installed or AO_SESSION not setSolution:
  1. Check if .claude/metadata-updater.sh exists in workspace
  2. Verify hook is registered in .claude/settings.json:
    {
      "hooks": {
        "PostToolUse": [
          {
            "matcher": "Bash",
            "hooks": [{
              "type": "command",
              "command": "/path/to/.claude/metadata-updater.sh"
            }]
          }
        ]
      }
    }
    
  3. Check if AO_SESSION environment variable is set (should be session ID)
Cause: JSONL file not found or path encoding mismatchSolution:
  1. Check if ~/.claude/projects/ contains a matching directory
  2. Manually encode the workspace path and verify:
    # For /Users/dev/project
    ls ~/.claude/projects/Users-dev-project/
    
  3. Ensure Claude has created at least one session file (*.jsonl)
Cause: Plugin uses Sonnet 4.5 pricing for all modelsSolution: Cost estimates are approximate. For accurate billing:
  • Check Anthropic’s usage dashboard
  • Parse the costUSD field from JSONL if available (newer Claude versions)
  • Adjust pricing in plugin source for other models (requires rebuild)
Cause: readyThresholdMs too long, or permission prompt not detectedSolution:
  1. Adjust threshold in config:
    agentConfig:
      readyThresholdMs: 15000  # 15 seconds
    
  2. Check terminal output for permission prompts (run ao status <session>)
  3. Attach to session to manually approve: tmux attach -t <session-id>
Cause: Using -p flag for prompt deliverySolution: This plugin intentionally avoids -p to keep Claude in interactive mode. Prompts are delivered post-launch via runtime.sendMessage(). Do not modify the launch command to include -p.

Comparison with Other Agents

FeatureClaude CodeCodexAiderOpenCode
ProviderAnthropicOpenAIAider.chatOpenCode
Session FilesJSONLJSONLMarkdownSQLite
Cost Tracking✅ Full✅ Full❌ None❌ None
Auto-metadata✅ PostToolUse hooks✅ PATH wrappers❌ None❌ None
Resume Support✅ Native✅ Native❌ None❌ None
Activity Detection✅ JSONL events✅ File mtime⚠️ Git commits only❌ None

Environment Variables

The plugin sets these environment variables for introspection:
AO_SESSION_ID
string
required
Session identifier for metadata lookups
AO_PROJECT_ID
string
Project identifier (set by caller, not the plugin)
AO_ISSUE_ID
string
Issue/ticket identifier if applicable
CLAUDECODE
string
default:""
Unset to avoid nested agent conflicts
The plugin explicitly unsets CLAUDECODE to prevent nested Claude instances from interfering with each other.

Build docs developers (and LLMs) love