Documentation
¶
Overview ¶
Package claude adapts headless Claude Code to the runner harness.
One Run is one `claude --print` invocation: one turn, one process, one session. The process speaks `--output-format stream-json`, which this adapter parses line by line into bounded harness.Events and one terminal harness.Result. There is no long-lived server as there is for Codex.
Credentials ¶
Headless Claude Code authenticates through ONE environment variable, and this adapter is the only thing that ever sets it. The value is read from a runner-owned 0600 file named by Config.CredentialFile — never from the runner's own environment, which is why blockedEnvKey strips every inherited ANTHROPIC_*/CLAUDE_* variable before the child is started. Two kinds are supported:
oauth-token -> CLAUDE_CODE_OAUTH_TOKEN (produced by `claude setup-token`) api-key -> ANTHROPIC_API_KEY
The value never appears in an event, a blocker, a log line, an error or the capabilities response: every string that leaves this package goes through redact() first.
Isolation: what is enforced by a flag, and what is not ¶
Enforced by flags (verified against `claude --help`, 2.1.273):
--print non-interactive; the workspace trust dialog is skipped
--output-format stream-json machine-readable events instead of prose
--verbose required for stream-json to emit per-turn records
--permission-mode <mode> Config.PermissionMode: acceptEdits (default) lets the
model edit files inside the worktree without asking;
bypassPermissions additionally allows every tool,
including arbitrary shell, and is for sandboxed hosts
--permission-prompts none nobody to ask: anything that would still prompt is
DENIED. Used when Launch.Permissions is nil.
--permission-prompts host somebody CAN be asked, and the request goes to the
--permission-prompt-tool below. The permission mode
still decides everything else; this widens nothing,
it only replaces a silent denial with a question.
--permission-prompt-tool the one-tool MCP server this adapter hosts on
loopback for the child; see permission.go
--allowedTools <list> Config.AllowedTools: tool patterns granted up front
(e.g. "Bash(git *)") so acceptEdits can run tests
--safe-mode disables CLAUDE.md, skills, plugins, hooks, MCP servers,
custom commands/agents, output styles, workflows — i.e.
every project-controlled code and config path. Auth,
model selection, built-in tools and permissions still work.
It is passed ONLY when there is nobody to ask: measured
against 2.1.281, --safe-mode disables --mcp-config
servers too, so it and a permission prompt tool cannot
both exist. See the trade documented on args().
--strict-mcp-config no MCP server but the permission prompt one, and with
no --mcp-config at all, none whatsoever
--disable-slash-commands no skills
--no-chrome no browser integration
--setting-sources "" no user, project or local settings files
--session-id / --resume the session identity is ours, never discovered
Enforced by environment (variable names verified present in the 2.1.273 binary): CLAUDE_CONFIG_DIR pins the config directory to the runner-owned home; DISABLE_AUTOUPDATER, DISABLE_TELEMETRY, DISABLE_ERROR_REPORTING, DISABLE_BUG_COMMAND, DISABLE_COST_WARNINGS and CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC turn off self-update and non-essential network traffic. The IDE integration is opt-in (--ide), so not passing it is the disabled state.
NOT available, and therefore NOT enforced:
- No max-turns flag exists in this release, so a turn is bounded by the runner's own execution limits and by context cancellation, not by the harness.
- No network sandbox. Unlike the Codex adapter's workspace-write sandbox, Claude Code has no flag that disables network access for the turn. Tools that reach the network are reachable unless removed with --restricted, which also removes Bash and would make a coding runner useless.
- No filesystem sandbox beyond the working directory: file tools are confined to the cwd and --add-dir entries (we pass none), but Bash can still reach anything the runner account can.
The privilege boundary for an add-on-managed runner is therefore the dedicated non-root account the agent supervises it under, not this adapter. See docs/edge-harness.md.
Index ¶
Constants ¶
const (
// HarnessName is what the runner advertises in its capabilities response.
HarnessName = "claude-code"
)
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Adapter ¶
type Adapter struct {
// contains filtered or unexported fields
}
Adapter is the Claude Code implementation of harness.Adapter.
func (*Adapter) Probe ¶
Probe checks the executable and its version without making a model call.
It deliberately does NOT check authentication: the credential arrives with each launch, so there is nothing to check here, and a runner that reported itself unready until one showed up would never accept the attempt that carries it. An unusable credential is a per-attempt needs_input outcome.
func (*Adapter) Run ¶
func (a *Adapter) Run(ctx context.Context, launch harness.Launch, emit harness.Emit) (harness.Result, error)
Run executes exactly one headless turn. A Launch that carries a SessionID resumes that session; one that does not starts a new one. The session id is returned in every outcome — including failures — so a caller can always resume rather than silently starting a second conversation.
type Config ¶
type Config struct {
Binary string
// Home is a runner-owned CLAUDE_CONFIG_DIR. It must be dedicated to the
// worker and is created 0700.
Home string
// WorktreeRoot is the managed checkout root; Launch.Workdir must be a task
// directory beneath it. Shares the Codex adapter's rule.
WorktreeRoot string
// Model is passed as --model when set; empty leaves the account default.
Model string
// ExpectedVersion, when set, produces a readiness Reason on mismatch.
ExpectedVersion string
// PermissionMode is what the model may do without asking. Empty means
// PermissionAcceptEdits. A coding runner cannot work under "dontAsk": with
// prompts denied, every file edit is refused and each turn ends with no
// changes.
PermissionMode PermissionMode
// AllowedTools are Claude Code tool patterns granted for the session, e.g.
// "Bash(git *)" or "Bash(npm test)". They matter under PermissionAcceptEdits,
// where shell commands are otherwise denied.
AllowedTools []string
}
Config selects the Claude Code executable and its isolated home. The credential is NOT configuration: it arrives with each launch.
type PermissionMode ¶
type PermissionMode string
PermissionMode names a Claude Code --permission-mode value the runner supports.
const ( // PermissionAcceptEdits auto-approves file edits within the working // directory; anything else that would prompt is denied. PermissionAcceptEdits PermissionMode = "acceptEdits" // PermissionBypass approves every tool call. The dedicated runner account // and the worktree are then the only isolation; Claude Code documents it // as suitable only for sandboxes. PermissionBypass PermissionMode = "bypassPermissions" )