Claude Code Harness¶
Claude Code is the most full-featured harness, supporting all capabilities including hooks, custom tools, and stateful sessions. It is the recommended choice for complex autonomous coding tasks.
SDK vs Legacy (v0.24+)
Cub now offers two Claude backends:
claude(default): Uses Claude Agent SDK for full hook supportclaude-cli: Uses shell-out mode for compatibility
The SDK backend is recommended for new projects.
Capabilities¶
| Capability | SDK (claude) | CLI (claude-cli) |
|---|---|---|
| streaming | ||
| token_reporting | ||
| system_prompt | ||
| auto_mode | ||
| json_output | ||
| model_selection | ||
| hooks | ||
| custom_tools | ||
| sessions |
Installation¶
Install Claude Code from the official repository:
# Via npm (recommended)
npm install -g @anthropic-ai/claude-code
# Verify installation
claude --version
For detailed installation instructions, see the Claude Code documentation.
SDK Dependencies (Optional)¶
For SDK features (hooks, custom tools), install the Python SDK:
If the SDK is not installed, cub automatically falls back to legacy mode.
Features¶
Streaming Output¶
Claude Code supports real-time streaming via --output-format stream-json. When running with streaming enabled, you see output as it's generated:
Token Reporting¶
Claude provides accurate token usage including:
- Input tokens
- Output tokens
- Cache read tokens (for prompt caching)
- Cache creation tokens
- Cost in USD
This enables precise budget tracking with --budget flags.
System Prompt Support¶
Claude Code supports separate system prompts via --append-system-prompt. This keeps your task instructions distinct from system-level guidance in PROMPT.md.
Model Selection¶
Select models at runtime with the --model flag:
haiku- Fast, cost-effective for simple taskssonnet- Balanced performance and costopus- Most capable for complex tasks
Use task labels to select models per task:
Example Invocation¶
Here's how cub invokes Claude Code:
echo "$task" | claude -p \
--append-system-prompt "$system" \
--dangerously-skip-permissions \
--output-format stream-json \
--model sonnet
Flags Used¶
| Flag | Purpose |
|---|---|
-p | Pipe mode (read task from stdin) |
--append-system-prompt | Add system instructions |
--dangerously-skip-permissions | Enable auto mode |
--output-format | JSON or stream-json output |
--model | Select model (haiku, sonnet, opus) |
Environment Variables¶
CLAUDE_FLAGS¶
Pass additional flags to the Claude CLI:
CUB_MODEL¶
Override the model for all tasks:
This is equivalent to adding --model opus to every invocation. Task labels with model: take precedence.
Token Usage¶
Claude reports detailed token usage in its JSON output:
{
"result": "Task completed successfully...",
"usage": {
"input_tokens": 1500,
"output_tokens": 800,
"cache_read_input_tokens": 500,
"cache_creation_input_tokens": 200
},
"cost_usd": 0.0045
}
Cub uses this data for:
- Budget tracking (
--budget,--iteration-budget) - Cost reporting in
cub status - Iteration summaries in logs
Tips and Best Practices¶
Use Sonnet for Most Tasks¶
Sonnet offers the best balance of capability and cost. Reserve opus for complex architectural decisions.
# Default to sonnet
export CUB_MODEL=sonnet
# Use opus for specific tasks
bd label cub-abc123 model:opus
Enable Streaming for Visibility¶
Streaming provides real-time feedback on what the AI is doing:
Leverage Prompt Caching¶
Claude's prompt caching reduces costs for repeated similar prompts. Structure your PROMPT.md to maximize cache hits by putting stable content first.
Set Reasonable Budgets¶
Use budget flags to prevent runaway costs:
# Limit total session cost
cub run --budget 5.00
# Limit per-iteration cost
cub run --iteration-budget 0.50
Troubleshooting¶
"claude: command not found"¶
Ensure Claude Code is installed and in your PATH:
If not found, reinstall or add to PATH:
Rate Limit Errors¶
Claude may hit rate limits during intensive sessions. Cub automatically retries with backoff. To reduce rate limit issues:
- Use
--delayto add pauses between iterations - Consider sonnet instead of opus for routine tasks
High Token Usage¶
If token usage seems high:
- Check PROMPT.md - large system prompts increase every invocation
- Review task descriptions - overly verbose tasks consume more tokens
- Use streaming to monitor what the AI is doing
Hooks System (SDK Only)¶
The SDK backend (claude) supports hooks for intercepting and controlling AI behavior. Hooks enable:
- Guardrails: Block dangerous commands before execution
- Logging: Track tool usage and decisions
- Circuit breakers: Stop runaway loops
- Custom behavior: Modify prompts or inject context
Hook Events¶
| Event | When Fired | Use Case |
|---|---|---|
PRE_TASK | Before task starts | Validate inputs, inject context |
POST_TASK | After task completes | Log results, cleanup |
PRE_TOOL_USE | Before tool execution | Block dangerous commands |
POST_TOOL_USE | After tool execution | Log tool results |
ON_ERROR | When error occurs | Custom error handling |
ON_MESSAGE | On each AI message | Real-time monitoring |
Example: Blocking Dangerous Commands¶
from cub.core.harness import HookEvent, HookContext, HookResult
def block_dangerous_commands(context: HookContext) -> HookResult:
"""Block rm -rf and other dangerous commands."""
if context.event == HookEvent.PRE_TOOL_USE:
if context.tool_name == "bash":
command = context.tool_input.get("command", "")
if "rm -rf" in command or "sudo" in command:
return HookResult(
block=True,
message="Blocked dangerous command"
)
return HookResult(block=False)
# Register the hook
backend.register_hook(HookEvent.PRE_TOOL_USE, block_dangerous_commands)
Configuring Hooks¶
Hooks can be configured in .cub.json:
{
"harness": {
"hooks": {
"block_patterns": ["rm -rf", "sudo", "curl | sh"],
"log_tool_usage": true,
"max_iterations": 50
}
}
}
For more details, see the Hooks System guide.
CLI Backend¶
The CLI backend (claude-cli) uses shell-out mode, invoking Claude Code as a subprocess. Use this for:
- Compatibility with older environments
- Troubleshooting SDK integration issues
- Simpler deployments without SDK dependencies
Selecting CLI Mode¶
# Via CLI flag
cub run --harness claude-cli
# Via environment variable
HARNESS=claude-cli cub run
# Via config
# .cub.json
{
"harness": {
"default": "claude-cli"
}
}
Differences from SDK¶
| Feature | SDK | Legacy |
|---|---|---|
| Hooks | Full support | No-op (silent) |
| Custom tools | Supported | Not available |
| Sessions | Supported | Not available |
| Execution | In-process async | Subprocess |
| Streaming | Async generator | Line-buffered |
When to use CLI backend
The CLI backend is maintained for compatibility and simpler deployments. Use it when you don't need hooks, custom tools, or session support.