{"id":49309270,"url":"https://github.com/lannguyensi/harness","last_synced_at":"2026-06-14T09:01:43.752Z","repository":{"id":353324766,"uuid":"1218917765","full_name":"LanNguyenSi/harness","owner":"LanNguyenSi","description":"Declarative control plane for agent harnesses: one YAML for grounding, tools, memory, and hooks. Describe, validate, diff, apply.","archived":false,"fork":false,"pushed_at":"2026-06-10T15:50:35.000Z","size":3455,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-10T16:10:35.044Z","etag":null,"topics":["ai-agents","claude-code","control-plane","declarative","dx","harness","yaml"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/LanNguyenSi.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":"docs/ROADMAP.md","authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-23T10:48:19.000Z","updated_at":"2026-06-10T15:41:40.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/LanNguyenSi/harness","commit_stats":null,"previous_names":["lannguyensi/harness"],"tags_count":49,"template":false,"template_full_name":null,"purl":"pkg:github/LanNguyenSi/harness","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LanNguyenSi%2Fharness","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LanNguyenSi%2Fharness/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LanNguyenSi%2Fharness/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LanNguyenSi%2Fharness/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/LanNguyenSi","download_url":"https://codeload.github.com/LanNguyenSi/harness/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/LanNguyenSi%2Fharness/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34315075,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-14T02:00:07.365Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-agents","claude-code","control-plane","declarative","dx","harness","yaml"],"created_at":"2026-04-26T11:30:49.122Z","updated_at":"2026-06-14T09:01:43.745Z","avatar_url":"https://github.com/LanNguyenSi.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# harness\n\n**Declarative control plane for agent harnesses.**\n\nOne zod-validated YAML manifest for grounding, tools, memory, hooks,\npolicies, and workflows, plus a CLI that describes, validates, diffs,\napplies, audits, and *enforces*.\n\n\u003e Most config tools tell you what an agent is configured to use.\n\u003e `harness` tells you what an agent is *allowed to do*, under this\n\u003e exact context, and why.\n\nA coding agent like Claude Code is configured across half a dozen\nfiles (`settings.json`, `CLAUDE.md`, memory notes, MCP registrations,\nhook scripts, per-project overrides), and no single file answers\n*\"what can this agent do right now, and why is it set up that way?\"*.\n`harness` puts all of it in one YAML you read, validate, and diff;\ngenerates the config the agent loads from it; and at runtime blocks\ntool calls that violate the declared rules while recording every\ndecision.\n\n## See it work\n\nOne rule, declared in `harness.yaml`: *no session may merge a PR\nuntil it has logged a review.*\n\nClaude Code goes to merge PR 42. Before the tool call runs, the\nruntime hands the event to `harness`, which checks it against the\nmanifest. The hook protocol wire shape is the legacy engine-vocabulary\nenvelope (operators see this on stderr; agents read it via\n`permissionDecisionReason` when the policy declares no `ux:` block):\n\n```console\n$ harness policy intercept       # Claude Code runs this before each tool call\n{\"decision\":\"block\",\"reason\":\"review-before-merge: no matching ledger entry for tag `review:42`\",\"hookSpecificOutput\":{\"hookEventName\":\"PreToolUse\",\"permissionDecision\":\"deny\",\"permissionDecisionReason\":\"review-before-merge: no matching ledger entry for tag `review:42`\"}}\n```\n\nBuilt-in block-enforcement policies ship a `ux:` block since v0.17.0,\nso the agent sees a plain-language three-section form\n([`docs/for-agents.md`](docs/for-agents.md#agent-facing-block-messages-ux-block));\nthe engine-vocabulary text above stays in the audit ledger.\n\nBlocked. `harness explain` says exactly why:\n\n```console\n$ harness explain review-before-merge --trace\nname: review-before-merge\ndecision: deny\nenforcement: block\nreason: no matching ledger entry for tag `review:42`\nledgerTag: review:42\nextract:\n  PR_NUMBER: \"42\"\nrequiresEval:\n  matchedCount: 0\n  reason: no matching ledger entry for tag `review:42`\n# ... (trimmed; the full trace also shows the matched trigger, every extracted variable, and the ledger query)\n```\n\nThe rule pulled `PR_NUMBER=42` out of the tool call and looked for a\n`review:42` entry in the evidence ledger. There wasn't one. So the\nreviewer (or a review subagent) logs that entry, and the *same* merge\ncall, retried, goes straight through, no restart, no config edit:\n\n```console\n$ harness policy intercept       # same call, after the review was logged\n$                                # (no output, exit 0: allowed)\n```\n\nEvery one of those decisions is recorded:\n\n```console\n$ harness audit --since 1h --policy review-before-merge\ntimestamp            policy               outcome  reason\n-------------------  -------------------  -------  --------------------------------------------\n2026-05-14 19:09:03  review-before-merge  deny     no matching ledger entry for tag `review:42`\n2026-05-14 19:09:13  review-before-merge  allow    1 matching ledger entry for tag `review:42`\n```\n\nDeclare the rule once; every session is held to it, with a paper\ntrail of every decision.\n\n## Concepts in six lines\n\n| Term | What it is |\n|------|-----------|\n| **manifest** | The one YAML file (`harness.yaml`) where you declare everything: tools, hooks, policies, memory. |\n| **apply** | `harness apply` renders the manifest into the config files the agent runtime actually reads. |\n| **policy** | A rule of the form *when the agent does X, require evidence Y*. Evaluated at runtime; can block the call. |\n| **evidence ledger** | An append-only log of facts an agent records during a session. Policies check it; `audit` / `explain` replay it. |\n| **hook** | A script the agent runtime runs at a lifecycle event (session start, before every tool call, ...). How policies get enforced. |\n| **policy pack** | A reusable bundle of policies, hooks, and templates shipped under one name and enabled with a single manifest key. |\n\n## What harness does\n\n```mermaid\nflowchart LR\n    declare[\"1. Declare\u003cbr/\u003e\u003ccode\u003eharness.yaml\u003c/code\u003e\"]\n    apply[\"2. Apply\u003cbr/\u003e\u003ccode\u003eharness apply\u003c/code\u003e\"]\n    enforce[\"3. Enforce\u003cbr/\u003ehooks + policies\u003cbr/\u003eat runtime\"]\n    record[(\"4. Record\u003cbr/\u003eevidence ledger\")]\n    observe[\"5. Observe\u003cbr/\u003e\u003ccode\u003eaudit\u003c/code\u003e / \u003ccode\u003eexplain\u003c/code\u003e /\u003cbr/\u003e\u003ccode\u003esession-export\u003c/code\u003e\"]\n\n    declare --\u003e apply\n    apply --\u003e enforce\n    enforce --\u003e record\n    record --\u003e observe\n    observe -. refine .-\u003e declare\n```\n\nObserve → refine → declare is the whole loop. The read-side surfaces\n(`audit`, `explain --trace`, `session-export`) replay rows the runtime\nalready recorded, so what flows back into the manifest is grounded in\nwhat actually happened.\n\n## Pick your audience\n\n- **Operator?** [`docs/for-humans.md`](docs/for-humans.md): install through first `apply`, first real policy, diagnostics cheat sheet.\n- **Agent (or onboarding one)?** [`docs/for-agents.md`](docs/for-agents.md): workflow lifecycle, policy / ledger sequence, CLI cheat sheet by side-effect class, the audit triumvirate.\n- **Writing your own policy?** [`docs/writing-custom-policies.md`](docs/writing-custom-policies.md): three tripwires, four worked recipes (each validated in CI), author loop, field reference.\n- **Guarding destructive runtime commands?** [`docs/runtime-reality-hook.md`](docs/runtime-reality-hook.md): block compose/systemctl/kill/deploy calls when the live process state has drifted from what the docs expect.\n- **Looking up a CLI verb?** [`docs/CLI.md`](docs/CLI.md): every command the `harness` binary exposes, grouped by purpose (manifest, runtime, hooks, approvals, gates, preflight).\n\n## Install\n\n```bash\nnpm i -g @lannguyensi/harness\n```\n\nThe CLI binary is `harness`. Node 20 or newer required.\n\n## First-time setup\n\nIn a hurry? [`docs/quickstart.md`](docs/quickstart.md) is the bare\ncommand path, install to wired-in, no prose.\n\n```bash\nharness init --interactive\n```\n\nGuided wizard. Detects `~/.claude/` and `~/.codex/`, MCP servers\nalready wired in `settings.json`, harness binary version. Picks a\nprofile (`solo` / `team` / `custom`) and writes a starting\n`harness.yaml`. Ctrl-C aborts cleanly. Walkthrough +\nlimitations: [`docs/init-interactive.md`](docs/init-interactive.md).\n\n### Profiles at a glance\n\n| Profile | External accounts / tools required | Best for |\n|---------|------------------------------------|----------|\n| `solo`  | None. `npm` + Claude Code is enough. | Single operators who want the Understanding Gate without committing to a tasking system. |\n| `team`  | An **agent-tasks** account ([hosted](https://agent-tasks.opentriologue.ai) or [self-hosted](https://github.com/LanNguyenSi/agent-tasks)). | Teams that already use `agent-tasks` for PR review tracking. The merge gate (`review:\u003cpr-number\u003e` ledger tag) wires against the agent-tasks MCP. |\n| `full`  | Same as `team` plus `@lannguyensi/agent-preflight` and `gh` on PATH. | Operators who want every reference policy enforced (dogfood gate, preflight gates, review-subagent gate, merge gate). |\n\n**Not using agent-tasks?** Pick `solo`. The `team` and `full` review gates currently match only the agent-tasks MCP tool names, so a `gh pr create` workflow stays unprotected by them today. Tool-agnostic gates that also match `gh pr` are tracked in the backlog.\n\nIf you prefer non-interactive (CI, fresh-VM provisioning), pick a\ntemplate directly:\n\n```bash\nharness init --template solo   # memory-router + understanding-before-execution pack\nharness init --template team   # solo + agent-tasks MCP + review-before-merge policy\nharness init --template full   # everything from the Appendix A reference manifest\n```\n\nUse `harness init --probe` for a JSON snapshot of detected runtimes\nand MCPs without writing anything.\n\n## Try it without installing\n\n`harness dry-run` reports which hooks fire and which policies match\nfor a given tool call, against the reference manifest, before any\nledger I/O:\n\n```bash\ngit clone https://github.com/LanNguyenSi/harness \u0026\u0026 cd harness\nnpm install \u0026\u0026 npm run build\nnode dist/cli/main.js dry-run \"merge PR 42\" \\\n  --tool mcp__agent-tasks__pull_requests_merge \\\n  --tool-args '{\"prNumber\":42}' \\\n  --config docs/examples/full-manifest.yaml\n```\n\n`docs/examples/full-manifest.yaml` is a schema-coverage example, not a\nrunnable config (the file header spells out the contract). For a\nmanifest tailored to your machine, install globally and run\n`harness init --interactive`.\n\n## Uninstall\n\n`harness uninstall` is the single-command teardown: dry-run by default,\n`--apply` to mutate, `--restore-from \u003cbackup\u003e` to roll back. Full\ninventory + recommended order in [`docs/uninstall.md`](docs/uninstall.md).\n\n## Status\n\nharness ships in phases. All seven are released: read-only inventory →\nmanaged edits → declarative truth → policy layer → polish and dogfood\nlessons → the Understanding Gate Policy Pack → the Risk Gate. Phase 7\n(the Risk Gate) landed in `v0.27.0`. Operator-surface milestones along\nthe way: `harness pause/resume` in `v0.22.0`, `migrate-home` in\n`v0.24.0`, Codex-runtime adapter polish in `v0.28.x` and `v0.29.0`,\n`approve risk --force` in `v0.30.0`, the opt-in `runtime-reality`\ndrift gate in `v0.31.0`, the opt-in `solution-acceptance` pack in\n`v0.32.0`, the operator-only `approve branch-protection` marker in\n`v0.33.0`, and the `harness gc` retention cleanup plus non-TTY-safe\nconfirmations in `v0.34.0`. The current release is `v0.34.0`.\n\nThe phase-by-phase plan with acceptance criteria lives in\n[`docs/ROADMAP.md`](docs/ROADMAP.md); what shipped in each version is\nin [`CHANGELOG.md`](CHANGELOG.md).\n\n## Policy Packs\n\nA *Policy Pack* is a reusable bundle of hooks, policies, instruction\ntemplate, and permission profiles shipped under one name and enabled\nfrom `harness.yaml` with a single key:\n\n```yaml\npolicy_packs:\n  - name: understanding-before-execution\n    config:\n      mode: grill_me                  # fast_confirm | grill_me | strict\n      permission_profile: safe-start  # safe-start | implementation-after-approval | high-risk-grill-me\n```\n\nManage packs with `harness pack add / remove / list`. Two packs ship\ntoday: [`understanding-before-execution`](docs/policy-packs/understanding-before-execution.md)\n(forces an Understanding Report before any write-capable tool fires)\nand [`branch-protection`](docs/policy-packs/branch-protection.md)\n(blocks source mutations on protected branches without an explicit\noverride). Custom packs from `path:`, `npm:`, or `git:` sources are\nout of scope for v1 (see the pack docs for the future-vocabulary\ncontract).\n\n## What's next\n\nThe seven-phase roadmap is complete. The Risk Gate (Phase 7) shipped in\n`v0.27.0`: `harness policy intercept` reasons about the action itself\n(Action Envelope → Context Resolver → Risk Classifier), evaluates each\npolicy's `when:` clauses, and enforces a four-way `allow / warn /\nrequire_approval / deny` decision, so `DROP TABLE users`, `kubectl\ndelete namespace prod`, and `terraform destroy` against an unverified\nproduction target are blocked before the runtime fires them. See\n[`docs/risk-gate.md`](docs/risk-gate.md).\n\nCapability beyond the seven phases is not a quiet roadmap expansion: it\nlands as an explicit follow-up design doc or a separate sibling\nproject, per [`docs/ROADMAP.md`](docs/ROADMAP.md) (\"Out of scope across\nall phases\").\n\n\u003e Bring your favorite agent harness. Add governance.\n\n## Why this exists\n\nOn 2026-04-23, an `agent-grounding` checkout that was 16 commits\nbehind origin led two tasks to be incorrectly called \"stale\". The\ncheck that would have caught it already existed:\n[`agent-preflight`](https://github.com/LanNguyenSi/agent-preflight)\nruns `git fetch` + `git status` and emits a structured `ready` +\nconfidence-score result. The missing piece was not the check, it was\nthe deterministic *trigger*: a `SessionStart` hook that invokes\n`preflight run` and a policy that gates further work on the result.\nBuilding that wiring needs an agreed-upon place for harness config to\nlive first. That conversation is the origin of this repo.\n\n## Related\n\n- [`agent-grounding`](https://github.com/LanNguyenSi/agent-grounding): evidence-ledger, claim-gate, review-claim-gate; `grounding-mcp` is the canonical client surface harness queries through `queryLedgerByTag`.\n- [`agent-memory`](https://github.com/LanNguyenSi/agent-memory): the memory surfaces the control plane inventories.\n- [`agent-tasks`](https://github.com/LanNguyenSi/agent-tasks): MCP-registered task platform whose registration + health appear in `harness describe`.\n- [`agent-preflight`](https://github.com/LanNguyenSi/agent-preflight): local preflight validator; the canonical implementation of preflight-hook content harness wires.\n- [`codebase-oracle`](https://github.com/LanNguyenSi/codebase-oracle): opt-in MCP for multi-repo RAG search; not in Full, wire via `harness add mcp codebase-oracle --command codebase-oracle,mcp`.\n- [`agent-dx`](https://github.com/LanNguyenSi/agent-dx): ships `git-batch-cli`, a day-to-day tool whose inventory appears in `harness describe`.\n\n## License\n\nMIT, see [LICENSE](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flannguyensi%2Fharness","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flannguyensi%2Fharness","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flannguyensi%2Fharness/lists"}