nextv2.0.0

Agent harnesses

Which agent CLIs Kraft runs, what each supports, and how a task picks one.

A harness is one agent runtime, described as data: a fact about a CLI, not code. This page compares the seven Kraft ships.

How a task picks a harness

An agent task in library.yaml names a harness profile in its harness: field:

config/library.yaml
spec_author: { kind: agent, harness: claude, prompt: "...", produces: spec }

That name is a key in harnesses.yaml. The entry's provider says which of the harnesses below the harness profile runs:

config/harnesses.yaml
harnesses:
  claude:
    provider: claude
    enabled: true
    executable: claude
    defaults:
      model: sonnet

Kraft ships two harness profiles, claude and codex, and every agent task it ships names claude. The other five harnesses, cursor, opencode, antigravity, gemini and amp, are ready to use but need a harness profile of your own. Switch a task to another harness adds one and moves a task onto it.

Compare the harnesses

In the Resume and Fallback columns, a tick means the harness declares the capability and a dash means it does not.

HarnessModel, effortTool listsCostContextResumeFallback
claudebothGateYesSystem prompt✓✓
codexbothGateTokensSystem prompt✓✓
cursormodelGateTokensPrompt✓–
opencodemodelRulesYesPrompt✓✓
antigravitybothRefusedTokensPrompt✓✓
geminimodelRefusedAgent-writtenPrompt––
ampeffortRulesTokensPrompt✓–

What the columns mean:

  • Model, effort: which of model and effort the harness takes. amp takes no model, because Amp picks it, and its effort is Amp's mode. cursor, opencode and gemini take no effort.
  • Tool lists: how Kraft enforces deny_tools and allowed_tools on an unattended worker. Gate: the permission gate answers each call. Rules: the CLI enforces rules Kraft wrote for the launch. Refused: a task with a tool list does not launch. See Unattended runs.
  • Cost: Yes means the harness reports a dollar cost. Tokens means it reports tokens only, and Kraft estimates the cost. Agent-written means the agent writes its own counts into the result file. See Cost reporting.
  • Context: how Kraft passes its context to the agent. System prompt is out of band. Prompt is in band, folded into the task's prompt.
  • Resume: the harness declares resume, so Kraft can continue an earlier session by id.
  • Fallback: a rate limit on this harness can trigger a switch to the next entry of a fallback: list.

Only claude declares restrict_tools, approval_channel, autocompact and mcp_config, and only codex declares writable_dirs. A task or harness profile that sets an option whose capability its harness lacks is rejected at load. Harness definition files lists every capability.

The harnesses in detail

Each table starts with the command Kraft runs and the variable that carries an API key to a worker, then lists what the comparison leaves out for that harness.

A worker can use the CLI's own stored login instead where it has one; Give a worker its login has each login.

claude has no table: it runs claude, takes its API key in ANTHROPIC_API_KEY, and the columns above say the rest.

Codex details

TopicWhat to know
Commandcodex exec.
API keyCODEX_API_KEY.
Config keysIts context, effort, permission mode and writable-roots options are -c config keys.
Tool listsEnforced through a PreToolUse hook. See Codex.
Read from its logTokens, the thread id and a usage-limit stop, off its --json log. The log gives no reset time for a limit.

Cursor details

TopicWhat to know
Commandagent -p --trust. -p is print mode, and --trust skips the workspace-trust prompt that every new worktree would raise. The prompt follows --.
API keyCURSOR_API_KEY.
EffortNo effort. A model id can carry one, such as 'name[effort=high]'.
Tool listsA preToolUse hook Kraft installs in the worktree. See Cursor.
Read from its logTokens and the chat id resume takes, off its stream-json log. Tokens come off the closing result line, one per run: uncached input, output, and cache reads and writes.
Config directoryEvery launch sets CURSOR_CONFIG_DIR to $KRAFT_HOME/run/harness-config/cursor/, a directory Kraft owns. Your own ~/.cursor is never read or changed.
Commit attributionBefore each launch Kraft writes cli-config.json there with commit attribution off, because with it on Cursor adds a Co-authored-by: Cursor trailer to every commit and the classifier refused those commits. The file adds no permission rule.
Shared directoryAll launches share the directory, not one per launch, because --resume has to find the chat an earlier launch wrote. A sandboxed item gets one of its own, inside its sandbox home.
Sign-inThe login lives in the OS keychain, not the config directory. A sandboxed worker has no keychain, so it needs CURSOR_API_KEY, named in the repo's env_passthrough.

OpenCode details

TopicWhat to know
Commandopencode run. The prompt follows --.
API keyThe provider's own key.
NeedsOpenCode 2.0.0 or newer, not npm's 1.x opencode-ai. Kraft refuses an older one at launch. See min_version.
LaunchEvery launch passes --auto, since run otherwise rejects every permission request.
Modelmodel is provider/model for any provider OpenCode knows.
EffortThere is no effort. Name a variant in the model id (openai/gpt-5.5#high).
Tool listsWritten into the launch's own OpenCode config, with --standalone, when the task's policy sets either. See OpenCode and Amp.
Read from its logTokens, cost, the session id and a rate-limit stop, off its --format json log.
The last step's usageThat log leaves out the last step's usage, so Kraft reads the session's totals from opencode session export <session id> when the run ends. It falls back to the log's steps if that fails.
Sub-agentsA task sub-agent's tokens are not in the log.

Antigravity details

TopicWhat to know
Commandagy. The prompt follows -p.
API keyNone: sign-in with agy. A GEMINI_API_KEY route exists and is untested: see Give a worker its login.
AccountsGoogle's Antigravity CLI, for an individual Google account. gemini serves a Gemini API key or Gemini Code Assist: see Gemini details.
ControlKraft has no per-action control over an agy worker. See Unattended runs.
Efforteffort is --effort low|medium|high|max, checked by agy against the model.
ModelName the base model (gemini-3.8-flash) and set effort, not a slug with the effort in it (gemini-3.8-flash-low), or Kraft cannot price the session.
Read from its logTokens, the conversation id resume takes and a quota stop, off its stream-json log.
NeedsA prior interactive sign-in (agy once) on the machine, or a Gemini API key. See Give a worker its login.

Gemini details

TopicWhat to know
Commandgemini --skip-trust. The prompt follows -p, and --skip-trust trusts the worktree for the session, since a headless gemini outside a trusted folder refuses to start.
API keyGEMINI_API_KEY.
AccountsGemini CLI stopped serving free, Google AI Pro and Ultra accounts on 2026-06-18. gemini works with a Gemini API key or Gemini Code Assist. For Gemini models on an individual Google account, use antigravity.
ResumeNo resume at all. Gemini's --resume takes an index or "latest", not a session id, so the capability is not declared.

Amp details

TopicWhat to know
Commandamp --no-archive-after-execute. The prompt follows -x.
API keyAMP_API_KEY.
Model and effortNo model: Amp picks it. effort is Amp's mode (-m low|medium|high|ultra). An agent profile cannot select amp, because an agent profile needs a model for the provider. A task on amp sets effort: itself.
Tool listsA settings file of the launch's own (--settings-file), when the task's policy sets either. See OpenCode and Amp.
LaunchBoth command lines pass --no-archive-after-execute, because an archived thread cannot be resumed.
Read from its logTokens and the thread id resume takes, off its --stream-json log. The token counts are the thread's own, message by message, and match amp threads export.
CostAmp's bill (amp threads usage) can count a few requests that are not in the thread. It is the only place Amp reports cost, so Kraft records none.
NeedsCredentials a headless process can use. See Give a worker its login.

In this section

Copyright © 2026