Harness is a Python agent runtime and benchmark harness for tool-using LLMs.
It is built as a uv workspace with a Typer CLI, pluggable model adapters,
durable sessions and tasks, layered runtime defenses, and an execution-backed
eval stack for coding-agent behavior, autonomous research flows, and
feature-level CLI workflows.
At a high level, Harness gives you:
- a resumable agent runtime with tools, approvals, and storage
- a CLI for running, chatting with, and inspecting agents
- structural defenses around the base model/tool loop
- persistent workspace memory, contracts, tips, experience, and resume state
- a behavioral eval harness for defended-vs-bare A/B testing
- a durable research/autonomy layer for vision, rabbit holes, publications, experiments, promotions, and portfolio management
Harness is designed for the part of agent systems that lives outside the model: session management, tool orchestration, approval policy, verification, failure recovery, and evals.
That means the project is useful in two modes:
- As a runtime for real agent tasks in a workspace.
- As an experimentation surface for improving the code around the model, not just swapping the model itself.
The repo currently includes adapters for Codex CLI, OpenAI, OpenRouter, Ollama, and Anthropic, a shared runtime core, storage backends, built-in tools, and a CLI that ties the system together.
This repository is a uv workspace. The root package depends on every
workspace member so uv sync installs the whole stack in editable mode.
packages/
├── adapter-anthropic/ # Anthropic adapter
├── adapter-codex/ # Codex CLI adapter
├── adapter-openai/ # OpenAI adapter
├── adapter-ollama/ # Ollama adapter
├── adapter-openrouter/ # OpenRouter adapter
├── cli/ # Typer + Rich CLI, installs `harness`
├── core/ # Runtime loop, verifiers, critics, contracts, tips
├── storage-memory/ # In-memory storage backend
├── storage-sqlite/ # SQLite storage backend
├── tasks/ # Durable task model and activity log
├── tools-fs/ # Filesystem tools
├── tools-shell/ # Shell execution tools
└── tools-web/ # HTTP/web tools
Supporting benchmark assets live under evals/.
Key internal module boundaries after the reorg:
packages/cli/src/harness/cli/
├── __main__.py # CLI bootstrap and command registration
├── approvals_evidence_commands.py # approvals + evidence command family
├── builtin_tools.py # built-in tool provider registration
├── chat_commands.py # interactive chat / REPL flow
├── common.py # shared CLI helpers
├── config.py # CLI config loading and models
├── evals.py # eval command family
├── experience_commands.py # procedures + curator commands
├── gateway_commands.py # remote gateway + WhatsApp command family
├── gateway_hooks.py # built-in outbound notification hooks
├── introspection.py # providers + tools command family
├── lab_commands.py # multi-agent lab command family
├── lifecycle_commands.py # phase / contracts / tips / resume
├── markdown_render.py # markdown + mermaid rendering
├── plugins.py # plugin discovery and precedence
├── render.py # Rich rendering helpers
├── review_commands.py # diff-aware review entrypoint
├── run_commands.py # one-shot run flow
├── runtime_agent.py # runtime agent assembly
├── runtime_helpers.py # verifier / critic / storage helpers
├── scheduler_commands.py # long-lived scheduler command family
├── sessions_commands.py # session command family
├── tasks_commands.py # task command family
├── tune_commands.py # prompt tuning command family
└── workspace_commands.py # init / goal / memory command family
evals/
├── artifacts.py # artifact persistence helpers
├── calibration.py # judge calibration helpers
├── discovery.py # fixture discovery + metadata loading
├── docs_runner.py # docs-audit domain eval family
├── failure_analyzer.py # artifact-to-adjustment analysis
├── hard_checks.py # semantic hard behavior contracts
├── judge.py # optional LLM-as-judge scoring
├── research_runner.py # research domain eval family
├── review_runner.py # code-review domain eval family
├── runner.py # coding benchmark orchestration entrypoint
├── workflow_runner.py # deterministic feature-workflow eval runner
└── types.py # shared eval schemas
packages/core/src/harness/core/
├── citations.py # publication-to-publication lineage links
├── domain_profiles.py # task/domain policy presets
├── experience.py # public experience compatibility surface
├── experience_curator.py # archival maintenance for procedures
├── experience_providers.py # static + artifact + procedure retrieval
├── experiment_plans.py # experiment planning models
├── experiment_runner.py # bounded experiment execution helpers
├── experiments.py # experiment + result models
├── extensions.py # provider/plugin extension protocols
├── hypotheses.py # competing improvement angles
├── inspiration.py # external/internal idea intake models
├── observations.py # section observations for synthesis
├── opportunities.py # cross-section opportunity objects
├── portfolio.py # promotion/research portfolio snapshots
├── plugin_loader.py # plugin manifest and loader
├── procedural_skill.py # thin compatibility entrypoint
├── pr_generation.py # promotion draft / PR payload generation
├── procedures.py # writable procedure artifacts
├── promotion_candidates.py # refinement outputs ready for promotion
├── publications.py # durable research publication summaries
├── refinement.py # refinement helpers
├── research_archive.py # reject/archive/resurrect flows
├── research_index.py # research search/index helpers
├── research_models.py # vision/theme/unknown/rabbithole/publication
├── research_roles.py # built-in autonomous research roles
├── research_scheduler.py # queue building and rebalance helpers
├── research_store.py # research artifact persistence
├── result_schemas.py # typed machine-readable outputs
├── section_maps.py # deep-dive subsystem maps
├── tool_entry.py # declarative tool entry model
├── tips_mining.py # tip extraction from failures
├── tips_models.py # tip and experience data models
├── tips_providers.py # compatibility shim over experience
├── verification.py # compatibility surface
├── verification_behavioral.py # prompt/diff-sensitive verifiers
├── verification_guards.py # guardrail helpers
├── verification_judges.py # LLM/rule judge verifiers
└── verification_structural.py # deterministic structural verifiers
Harness targets Python 3.11+.
uv syncIf you want the harness command on your path outside uv run, install the
CLI package as an editable tool:
uv tool install --editable packages/cliOtherwise use:
uv run harness --helpTo install local Git hooks:
uv run pre-commit install --hook-type pre-commit --hook-type pre-pushThe configured hooks run format, lint, and type checks before commit/push.
uv run harness run \
--provider openrouter \
--model google/gemma-4-26b-a4b-it \
--yes \
"summarize the repository layout"uv run harness chat \
--provider ollama \
--model gemma4:latestuv run harness initThis creates .harness/harness.db in the current workspace so later commands
can reuse local sessions, memory, tasks, and related state.
uv run harness run \
--provider openrouter \
--model google/gemma-4-26b-a4b-it \
--goal \
--yes \
"refactor the approval flow and update the tests"The main entrypoint is:
uv run harness --helpCurrent top-level commands include:
run: single prompt executionchat: interactive REPLreview: diff-aware read-only code reviewdocs-audit: documentation analysis in a structured docs domaingoal: planner-first executioninit: create workspace-local storagesessions: inspect and resume saved sessionsplugins: inspect discovered plugin providersproviders: inspect provider configurationtools: inspect built-in toolsscheduler: durable scheduled mission/research executiongateway: remote command-and-control transport surface, including WhatsAppvision: update and inspect the current research directionresearch: manage rabbit holes, publications, opportunities, experiments, and promotiontasks: durable task managementapprovals: inspect and resolve queued tool approvalsevidence: inspect the tool-call evidence ledgerlab: planner/worker/reporter multi-agent workflowmemory: persistent workspace memoryexperience: manage writable procedures and curationeval: run and inspect behavioral evalsphase: external phase tracking for multi-step taskstips: procedural skill tipstune: prompt-tuning support for verifiers and criticsresume: cross-session roadmap contractcontracts: environment contracts loaded into runs
The CLI help is the source of truth for exact arguments and subcommands.
Harness runs a tool-using agent loop with durable state around it. The runtime is not just “model + tools”; it also layers policy and verification around the loop.
Important runtime concepts:
- Sessions: saved transcripts and activity that can be resumed later.
- Tasks: durable work items that can be linked to sessions.
- Approvals: per-tool approval policy, with optional durable inboxing.
- Evidence: a ledger of what tools ran and what happened.
- Memory: persistent facts injected into later runs.
- Contracts: hard environment rules loaded from
.harness/contracts/. - Tips: soft procedural hints loaded from
.harness/tips.jsonl. - Experience: artifact-backed lessons recovered from prior eval runs.
- Procedures: reusable writable guidance stored under
.harness/procedures/. - Resume state: a workspace roadmap file injected at run start.
The most important command is harness run.
uv run harness run --helpKey options:
--provider,--model,--base-url: model routing--cwd: tool working directory--session: reuse or create a named session--task: attach the run to a durable task--yes: auto-approve tools--inbox: queue approval requests instead of prompting--max-steps,--max-output-tokens,--max-repair: execution limits--goal: plan first, then execute--domain: task/use-case policy preset such ascodingorcode-review--require-tools: forbid answer-only responses--auto-compact: summarize old history when context is tight--predict: record consequence predictions before tool execution
Harness also supports a read-only review flow over the current git diff.
uv run harness review \
--provider openrouter \
--model google/gemma-4-26b-a4b-it \
--base origin/mainThis command:
- loads the current
git diff - runs the agent in the
code-reviewdomain profile - restricts the tool set to read-oriented inspection tools
- asks for structured review findings instead of a freeform essay
Use --json when you want machine-readable output for CI or downstream tools.
Expected repository configuration:
OPENAI_API_KEY,OPENROUTER_API_KEY, orANTHROPIC_API_KEYin repository secrets- optional
HARNESS_PROVIDERandHARNESS_MODELin repository variables
If you use Codex locally, Harness supports two different paths:
--provider codexdelegates to the installedcodexCLI and works with a normal ChatGPT/Codex login in~/.codex/auth.json--provider openaican also reuse~/.codex/auth.json, but only when that file contains a realOPENAI_API_KEY
A ChatGPT OAuth-only Codex login is not enough for raw OpenAI API calls by
itself, so the CLI reports that state as usable for codex but not for
openai.
The reference workflow intentionally skips forked PRs. Secrets are typically
not available there, and code-review should not silently fall back to an
unauthenticated run.
Harness can run the same model/tool loop with different levels of structural defense.
Current --profile values:
bare: no defense chain, no critic; closest to raw model + toolsadaptive: default; chooses a lighter or stricter path from task shapediagnostic: emphasizes diagnosis-alignment and repair qualityminimal: light structural checksstrict: the full verifier chain
These profiles are what the eval harness compares in defended-vs-bare A/B runs.
Harness can verify whether the agent actually did the work it claims to have done.
Verification modes include:
groundingstateruleshellllmautonone
Example:
uv run harness run \
--provider ollama \
--model gemma4:latest \
--verify auto \
--yes \
"fix the failing test and leave the rest alone"You can also attach a critic:
--critic llm--critic llm+search--critic none
The verifier layer is where much of the harness behavior lives: tests-first, verify-before-done, file-scope checks, diagnosis alignment, prompt-surface revert logic, loop detection, and related safeguards.
Use sessions when you want continuity across invocations.
uv run harness sessions --helpTypical use:
uv run harness run --session fix-auth --yes "start debugging auth failures"
uv run harness sessions list
uv run harness sessions resume --helpTasks are durable work items with their own activity log.
uv run harness tasks --helpThe task CLI supports creation, listing, inspection, updates, linking, and deletion.
Workspace memories are injected into every run.
uv run harness memory save --kind project_fact "use uv, not pip"
uv run harness memory list
uv run harness memory search "uv"Supported memory operations:
savelistsearchrm
Harness separates hard and soft context:
- Contracts are hard rules loaded from
.harness/contracts/and~/.harness/contracts/. - Tips are procedural hints loaded from
.harness/tips.jsonland~/.harness/tips.jsonl. - Experience can also be recovered from saved eval artifacts, where analyzed
harness_adjustments.jsonrecords are turned back into reusable guidance for defended runs. - Resume state is a structured roadmap file at
.harness/resume.json.
These layers are intended to make the outer runtime more informative and more stable without modifying the base model itself.
Useful commands:
uv run harness contracts --help
uv run harness tips --help
uv run harness resume --help
uv run harness experience --helpThe tips CLI currently supports:
listaddtestmine
The experience CLI supports writable procedure artifacts and curation:
procedures addprocedures listcurate
The research CLI supports the autonomous research stack:
vision show,vision updateresearch open,publish,search,show-publication,citeresearch add-theme,list-themes,create-unknown,list-unknownsresearch map-section,add-observation,show-sectionresearch create-opportunity,list-opportunities,relatedresearch hypothesize,plan-experimentresearch experiment run|show|compareresearch refine,list-candidates,candidate show,promote,prresearch archive,reject,list-archive,resurrectresearch roles,portfolio,queue,rebalance
Mission-aware research bridge support includes:
research create-opportunity --mission <mission_id> --feature <feature_id>- mission-linked hypotheses propagated from linked opportunities
research create-candidate --mission <mission_id> --feature <feature_id>- mission-linked promotion candidates rendered through
research show-candidate
The mission CLI supports bounded planning and validation loops:
mission create,show,listmission plan,draft-plan,approve,show-contractmission list-milestones,list-featuresmission execute-next,complete-feature,validate-milestonemission execute-milestone,execute-burst,schedule-oncemission summarize,list-reports,show-reportmission list-runs,show-run,list-handoffs,show-handoff,list-findings
Missions can also declare role-specific execution profiles at creation time:
--planner-model,--worker-model,--validator-model,--reporter-model--planner-brief,--worker-brief,--validator-brief,--reporter-brief
Those profiles are persisted into mission runs, handoffs, and mission reports so later agents can see which role was expected to do what.
For high-level goals, missions can now draft a structured plan before any feature work is dispatched:
uv run harness mission create --title "Checkout revamp" --goal "Ship a safer checkout flow."
uv run harness mission draft-plan --mission <mission_id> --apply --provider openrouter --model google/gemma-4-26b-a4b-itMission-to-research bridge commands include:
mission create-opportunitymission create-candidate
Harness now has a long-lived scheduler plus a transport-neutral gateway layer.
The scheduler CLI supports durable jobs for bounded autonomy:
scheduler add-mission,add-researchscheduler list,list-runsscheduler pause,resume,run-nowscheduler start
Jobs persist under .harness/scheduler/ so local runs can continue outside CI:
jobs/: durable job definitionsruns/: execution history and artifacts
The gateway CLI supports two kinds of traffic:
- control commands such as
status,runs,approve <id>, andreport <mission_id> - conversational messages that fall back to a normal Harness chat session
Useful commands:
uv run harness gateway --help
uv run harness gateway dispatch --transport whatsapp --user +37200000000 --thread +37200000000@s.whatsapp.net --message "status" --json
uv run harness gateway converse --transport whatsapp --user +37200000000 --thread +37200000000@s.whatsapp.net --message "what can you do for me?" --jsonHarness now targets a local WhatsApp Web bridge with QR pairing instead of the Meta Cloud API transport. The bridge is generated into the workspace, paired through the CLI, and used for both outbound notifications and inbound replies.
Workspace-local storage lives under:
.harness/gateway/whatsapp/config.json.harness/gateway/whatsapp/bridge/.harness/gateway/whatsapp/session/.harness/gateway/whatsapp/bridge.log
Typical setup flow:
# configure the local bridge and default chat model/provider
uv run harness gateway whatsapp setup --provider openrouter --mode self-chat --allowed-user +37200000000
# pair your phone by scanning the terminal QR with WhatsApp > Linked Devices
uv run harness gateway whatsapp pair
# start the long-lived bridge
# use either OpenRouter or OpenAI credentials, depending on your configured provider
export OPENROUTER_API_KEY="..."
uv run harness gateway whatsapp start
# inspect health and config
uv run harness gateway whatsapp status --json
# send a manual smoke-test message
uv run harness gateway whatsapp send --to +37200000000 --text "Harness WhatsApp smoke test"Notes:
- conversational WhatsApp replies use the provider/model stored in
.harness/gateway/whatsapp/config.json - the current OpenRouter default for the WhatsApp chat path is
openai/gpt-5.4-nano - while the model is thinking, the bridge sends WhatsApp typing presence so the user sees an active writing bubble
- control commands still work inside the same chat thread, so
statusandrunsdo not need a separate transport
For implementation details and scope notes, see docs/whatsapp-qr-plan.md.
Harness includes a behavioral eval stack under evals/.
Use it to compare defended and bare agent behavior, generate mutated fixtures, calibrate judge outputs, and track saved benchmark runs.
uv run harness eval --helpCurrent subcommands:
listmutatecalibratehistoryadjustmentsexport-adjustmentsvalidatereviewresearchdocs-auditworkflowrun
# Run the smoke suite with defended-vs-bare A/B and save artifacts
uv run harness eval run --suite smoke --ab --n-runs 3
# Run with JSON output
uv run harness eval run --suite smoke --ab --json-out
# Run mutation-based variants
uv run harness eval run --suite smoke --benchmark-mode mutated --mutation-seeds 7,8
# Inspect analyzer output from saved eval runs
uv run harness eval adjustments evals/runs --limit 20
# Export a consolidated adjustment corpus
uv run harness eval export-adjustments adjustments.jsonl --root evals/runs
# Scaffold a new review or workflow fixture
uv run harness eval create 25-missing-guard --kind review
uv run harness eval create 26-cli-smoke --kind workflow
# Let Harness assign the next fixture number and register it in the default suite
uv run harness eval create plugin-runtime-smoke --kind workflow --add-to-suite
# Validate fixtures, suites, and gold labels
uv run harness eval validate
# Run deterministic feature-workflow fixtures over the CLI surface
uv run harness eval workflow --suite workflow-smoke --json-outThe eval harness uses two layers of scoring:
- Hard metrics from execution evidence and fixture-specific behavior contracts.
- Optional LLM-judge scores for qualities like scope discipline, decomposition, pushback, and epistemic grounding.
Harness now uses multiple eval families:
eval run: the original coding-agent benchmark harnesseval review: structured code-review fixtureseval research: research memo fixtureseval docs-audit: documentation-audit fixtureseval workflow: deterministic feature-workflow fixtures that execute real CLI command sequences against local workspaces and wrapperseval create: scaffold a new fixture with companion files for any of the supported eval families, including placeholder gold labels foreval runand optional default-suite registration
The hard layer is behavior-first, not exact patch-text matching. A correct fix should not fail just because of harmless whitespace noise; the contracts are intended to check what changed and why, not only whether a diff matches a single string shape.
Each saved eval run also persists artifact-backed adjustment hints such as:
- what kind of failure happened
- which verifier or guardrail would have helped
- what corrective behavior should be reinforced later
Those adjustments are written into harness_adjustments.json beside the other
run artifacts and can be inspected or exported with the eval CLI.
For benchmark rules and asset layout, see evals/BENCHMARK.md. For the current external DeepSWE-style results snapshot, see evals/DEEPSWE_RESULTS.md.
uv run ruff format --check .
uv run ruff check .
uv run pyright
uv run pytestThese are the same quality gates enforced in CI.
uv run ruff format .
uv run ruff check --fix .uv run pytest packages/core/tests/test_verification.py -q
uv run pytest evals/tests/test_workflow_runner.py -qHarness now supports bounded unattended research runs through:
uv run harness research schedule-once --config .harness-scheduler.toml --cwd /path/to/workspace
uv run harness research list-runs --cwd /path/to/workspaceScheduler defaults can live in TOML:
[research_scheduler]
max_steps = 3
max_risk = "low"
base_branch = "main"
create_branch = false
commit = false
push = false
open_pr = false
draft_pr = trueCI wiring now includes:
.github/workflows/ci.ymldeterministicresearch schedule-oncesmoke coverage.github/workflows/research-autonomy.ymlmanual and scheduled autonomy bursts with uploaded run artifacts and an optional secret-backed live canonical eval lane on manual dispatch plus a separate mutation-capable manual lane guarded by environment approval
All of these workflows now write a concise autonomy summary into the GitHub workflow step summary, so reviewers can see status, stop reason, and step-level actions without downloading artifacts first.
For the manual live and mutation lanes, dispatch inputs can also opt into PR commenting:
comment_on_pr = true
pr_number = 123
If pr_number is omitted, the workflow tries to find an open PR for the
current branch, and mutation mode also tries the generated promotion branch
before falling back to the checked-out ref.
Manual live mode is opt-in and intended for provider-backed checks such as:
run_live_eval = true
live_fixture = 09-handover-vision-flow
live_provider = openrouter
live_model = google/gemma-4-26b-a4b-it
The live lane is disabled by default and requires the corresponding provider
secret, for example OPENROUTER_API_KEY.
Mutation mode is also opt-in and intended for explicitly bounded GitHub-side automation. Its manual dispatch inputs gate:
run_mutation = true
mutation_max_steps = 2
mutation_max_risk = low
mutation_create_branch = false
mutation_commit = false
mutation_push = false
mutation_open_pr = false
The mutation lane runs only on manual dispatch, uses a dedicated
autonomy-mutations environment, gets write permissions only in that job, and
can post the run summary back to a PR when comment_on_pr=true.
Harness also supports deterministic mission orchestration in CI through:
uv run harness mission schedule-once --mission mission-demo --config .mission-scheduler.toml --cwd /path/to/workspace
uv run harness mission summarize --mission mission-demo --cwd /path/to/workspace --jsonScheduler defaults can live in TOML:
[mission_scheduler]
max_steps = 10
auto_complete = true
[mission_roles.planner]
model = "openai/gpt-5.5"
brief = "Decompose the mission into milestones, features, and assertions before coding."
[mission_roles.worker]
model = "openai/gpt-5.4"
brief = "Implement the bounded feature and leave a concrete handoff."
[mission_roles.validator]
model = "openai/gpt-5.5"
brief = "Check milestone assertions independently and emit blocking findings when needed."
[mission_roles.reporter]
brief = "Summarize mission state, blockers, and next actions."CI wiring now includes:
.github/workflows/ci.ymldeterministicmission schedule-oncesmoke coverage.github/workflows/mission-autonomy.ymlmanual and scheduled deterministic mission bursts with uploaded run artifacts plus an optional secret-backed live canonical mission eval lane on manual dispatch, with mission summary output inGITHUB_STEP_SUMMARY
The mission CI lane seeds a bounded mission plan, approves it, runs
mission schedule-once, persists a mission report, and publishes step-level
status plus next actions in the GitHub workflow summary.
Manual live mode for missions is opt-in and intended for provider-backed checks such as:
run_live_eval = true
live_fixture = 12-mission-planning-flow
live_provider = openrouter
live_model = google/gemma-4-26b-a4b-it
The live lane is disabled by default and requires the corresponding provider
secret, for example OPENROUTER_API_KEY.
This repo is increasingly oriented around a simple claim:
The code around the model matters.
That means Harness focuses on:
- explicit runtime state instead of opaque conversations
- execution evidence instead of answer-only scoring
- defended-vs-bare comparisons instead of ungrounded claims
- reproducible artifacts instead of benchmark anecdotes
- environment-layer improvements, not only model swaps
If you are working on coding agents, evals, or runtime defenses, that is the part of the stack this repository is trying to make concrete.