Documentation
¶
Overview ¶
Package adapters defines the HarnessAdapter interface and shared types for harness-specific agent protocol implementations.
Adapters live in internal/adapters/<harness>/. The boid core references only this package (the interface and Usage type); harness details stay inside each sub-package.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type BindMount ¶
type BindMount struct {
// Source is the absolute host path to mount in.
Source string
// Target is the absolute sandbox path. Empty means "same as Source".
Target string
// Mode is "rw" for read-write, "" (default) for read-only.
Mode string
// IsFile flips the mount to file-bind (touch target first) instead of
// directory-bind. Used by the claude binding for ~/.claude.json.
IsFile bool
// Optional makes a missing Source on the host skip the mount instead of
// failing dispatch. Dispatcher converts this to a shell-level if-guard.
Optional bool
}
BindMount is the adapter-facing DTO for a host bind-mount request.
It is shape-compatible with orchestrator.BindMount and sandbox.BindMount on purpose — the dispatcher converts adapter-declared BindMounts straight into the same sandbox.Mount entries the kit-declared additional_bindings produce — but is defined here so the adapters package stays free of orchestrator and sandbox imports. orchestrator depends on adapters (HarnessAdapter is held on JobSpec.Adapter); the reverse import would close that cycle.
type HarnessAdapter ¶
type HarnessAdapter interface {
// Run forks the agent process, manages its signal lifecycle, and returns
// the captured payload patch and usage. See RunContext / Result for the
// I/O contract.
Run(ctx context.Context, rc RunContext) (Result, error)
// Usage returns token consumption metrics for the job identified by jobID.
// Returns a zero Usage and a nil error when metrics are not yet available.
Usage(ctx context.Context, jobID string) (Usage, error)
// Bindings declares the host bind-mounts this harness needs inside the
// sandbox. The dispatcher prepends this set to the kit-declared
// additional_bindings (if any) and lets the standard buildPATH / mount
// pipeline turn them into sandbox.Mount entries — so a binding whose
// Source ends in "/bin" automatically lands on PATH inside the sandbox.
//
// homeDir is the host home of the user the daemon runs as ($HOME, not the
// sandbox-internal HOME); adapters compose Source paths against it. The
// dispatcher fills it from os/user so the call is pure (testable without
// touching the environment).
//
// Returned BindMounts should typically set Optional=true so a missing
// source dir is silently skipped (the dispatcher converts Optional →
// shell-level if-guard). The recipe an adapter normally follows:
//
// 1. its private state dir (e.g. ~/.claude) — Mode "rw", Optional
// 2. the resolved CLI binary's parent dir found via exec.LookPath +
// filepath.EvalSymlinks — Mode "" (ro), Optional
// 3. any runtime shim tree the CLI needs at exec time (e.g. ~/.volta for
// volta-shimmed installs) — Mode "" (ro), Optional
//
// Adapters return nil when they have nothing to declare. claude.Adapter
// ships a non-trivial set (Phase 3-e absorbed it from the retired
// boid-kits claude-code kit); other adapters typically return nil for
// now.
Bindings(homeDir string) []BindMount
}
HarnessAdapter abstracts harness-specific agent protocol from boid core. Each supported harness (claude, codex, opencode, …) provides one implementation. The boid core calls these methods without knowing which harness is in use.
Phase 3-b shrank the interface to two members: Run() owns the entire agent process lifecycle (session resolve, fork, signal handling, payload capture, exit normalisation), and Usage() exposes post-run token metrics. Signal stop is delivered out-of-band via api.JobLifecycle.SignalJobRuntime so the daemon does not need to round-trip through the adapter to nudge a running agent.
type Result ¶
type Result struct {
// ExitCode is the child process's exit code, normalised for stop signals
// (a daemon-initiated SIGTERM is mapped to 0 via StoppedByDaemon).
ExitCode int
// PayloadPatch holds the contents of payload_patch.json after the agent
// exits. May be nil if the file was never written.
PayloadPatch json.RawMessage
// Usage carries token / cost metrics for the run when available. May be
// the zero value when the harness does not expose post-run metrics or
// the read path is not wired yet.
Usage Usage
// StoppedByDaemon is true when Run intercepted the daemon's stop signal
// (SIGUSR1) and translated the child's SIGTERM-induced exit into 0.
// Daemon callers use this to distinguish Q&A pauses from real failures.
StoppedByDaemon bool
}
Result is the output of HarnessAdapter.Run.
type RunContext ¶
type RunContext struct {
// JobID is the broker job_done key and transcript correlation id.
JobID string
// TaskID is the task id of the hook job, or "" for session/exec jobs.
TaskID string
// UserAnswer carries the bootstrap text the adapter delivers to the agent
// as the first user turn. Used by user-initiated session jobs to plumb the
// `boid agent <harness> --instruction` flag through to the agent's first
// turn; hook jobs leave it empty (the agent receives the harness' default
// bootstrap skill instead).
UserAnswer string
// InvokedBehavior is the canonical behaviour name ("executor" /
// "supervisor" / a free-naming behaviour) used to pick the bootstrap
// skill prompt for a fresh session.
InvokedBehavior string
// InvokedName is the behaviour-instance name (e.g. verifier suffix)
// used when resolving / persisting session entries in the payload.
InvokedName string
// Model overrides the agent's default model (e.g. "claude-opus-4-8").
// Empty leaves model selection to the harness binary.
Model string
// Workspace is the child process's cwd.
Workspace string
// PayloadPath points at the payload.json the adapter reads to recover
// prior session entries. Defaults to ~/.boid/context/payload.json when
// empty (resolved by the adapter, not the caller).
PayloadPath string
// OutputDir is where payload_patch.json is written. Defaults to
// ~/.boid/output when empty.
OutputDir string
// Stdin / Stdout / Stderr are passed verbatim to the child. The caller
// is responsible for PTY allocation; the adapter only forwards fds.
Stdin io.Reader
Stdout io.Writer
Stderr io.Writer
// Env contains environment variables to inject into the child on top
// of the parent's environment. The adapter may add harness-specific
// entries (e.g. IS_SANDBOX=1 for Claude CLI 2.1.181+ uid 0 bypass).
Env map[string]string
// SkillsDir is the absolute path of the directory where harness-visible
// skills are exposed (~/.claude/skills for Claude). Reserved for future
// use; PR1 does not act on it (skill bind-mounts are wired in the
// dispatcher under Phase 3-b PR2).
SkillsDir string
// Argv is the literal program + arguments to exec. Only the shell adapter
// consumes this field — claude / codex / opencode build their own argv
// from their CLI conventions and ignore Argv entirely. Phase 3-d added
// Argv so non-agent hooks and `boid exec` can flow through the same
// adapter pipeline as agent jobs instead of branching to a separate
// runExecArgv path in the runner-inner-child.
Argv []string
// StdinBytes, when non-empty, is piped into the child's stdin instead of
// Stdin. Shell adapter only — agent adapters allocate a PTY and route
// through Stdin. Used by hook scripts that read a JSON payload on stdin.
StdinBytes []byte
// StdoutCaptureFile, when non-empty, makes the shell adapter redirect the
// child's stdout to this host-side path (instead of writing to Stdout).
// Doubles as the broker job-done output fallback when no payload patch
// exists.
StdoutCaptureFile string
}
RunContext is the input to HarnessAdapter.Run. It bundles everything the adapter needs to fork the agent process, manage its lifecycle, and return the captured payload. Phase 3-b draft; see docs/plans/agent-aware-boid.md "Phase 3-b" section.
Run() owns the following responsibilities internally:
- signal.Notify(SIGUSR1) → child SIGTERM (Go signal.Notify auto-bypasses inherited sigprocmask block / SIG_IGN — verified by Phase 3-b PoC).
- signal.Notify(SIGWINCH) → forward to child.
- cmd.SysProcAttr.Setsid = true so child sits in its own session/pgrp (Python start_new_session=True equivalent).
- Exit code normalisation (stop signal terminations are reported as 0 via Result.StoppedByDaemon).
- Persisting a freshly-generated session id to payload_patch.json so the jsonl transcript path is recorded in the task's artifact even when the child terminates abnormally (SIGKILL, OOM).
type Usage ¶
type Usage struct {
// Model is the model identifier used for this job (e.g. "claude-opus-4-8").
Model string `json:"model,omitempty"`
// InputTokens is the number of uncached input tokens consumed.
InputTokens int64 `json:"input_tokens"`
// OutputTokens is the number of generated output tokens.
OutputTokens int64 `json:"output_tokens"`
// CacheCreationTokens is the number of tokens written to the prompt cache.
// Zero for harnesses that do not support prompt caching.
CacheCreationTokens int64 `json:"cache_creation_tokens,omitempty"`
// CacheReadTokens is the number of tokens served from the prompt cache.
// Zero for harnesses that do not support prompt caching.
CacheReadTokens int64 `json:"cache_read_tokens,omitempty"`
// Extra holds harness-specific data not captured by the fixed fields above.
// Nil when no additional data is available.
Extra json.RawMessage `json:"extra,omitempty"`
}
Usage holds token consumption metrics for a completed job. Fixed fields cover the common denominator across harnesses; Extra stores harness-specific data without requiring schema migrations.
Directories
¶
| Path | Synopsis |
|---|---|
|
Package claude implements adapters.HarnessAdapter for Claude Code.
|
Package claude implements adapters.HarnessAdapter for Claude Code. |
|
Package codex implements adapters.HarnessAdapter for the Codex CLI.
|
Package codex implements adapters.HarnessAdapter for the Codex CLI. |
|
Package opencode implements adapters.HarnessAdapter for the opencode CLI.
|
Package opencode implements adapters.HarnessAdapter for the opencode CLI. |
|
Package registry maps sandbox.HarnessType to a HarnessAdapter implementation.
|
Package registry maps sandbox.HarnessType to a HarnessAdapter implementation. |
|
Package shell implements adapters.HarnessAdapter for plain shell / exec jobs that do not embed an agent harness.
|
Package shell implements adapters.HarnessAdapter for plain shell / exec jobs that do not embed an agent harness. |
|
Package sigutil hosts the small signal-forwarding loop every harness adapter runs while its child process is alive.
|
Package sigutil hosts the small signal-forwarding loop every harness adapter runs while its child process is alive. |