Harness Script Engineering for AI agents.
Own the run, not just the prompt.
Created by Manpreet Singh · Part of Singh Labs
Quickstart · Pillars · CLI · Manifesto · Adopt in 30 min
">https://img.shields.io/badge/node-%E2%89%A518-blue">
You already write AGENTS.md to tell agents what your project is.
Bridle adds HARNESS.md to tell agents how their runs must behave — the loop
they follow, what they must log, which skills they may touch in which phase, what
needs a PR, and how they recover after a crash. Then a tiny CLI lints the file and
stamps every run's trace with the exact harness version that governed it.
AGENTS.md → the OS for your project (you probably have this)
HARNESS.md → the OS for every agent run (this is Bridle)
Prompts became artifacts. Now runs become artifacts too.
You set an agent loose on your backlog overnight. In the morning you ask what it
did. It edited eleven files, logged nothing, and merged something into main —
and the only record is a scrollback buffer that's already gone.
With Bridle:
GOOD nightly-20260720T1015Z-a1b2c3
harness v2.0.1 (9f3c01d2ab77) · 14 events · 0 escalations · 3 PRs, 0 direct pushes
More cases in examples/.
"Vibe Engineering" fixed prompt chaos: short prompts, AI-written plans, human approval. But run-level behavior — how agents act over hours or days, how they're traced, evaluated, governed, recovered — still lives inside your tools, implicit and invisible. When a long-running agent goes sideways at 3am, you can't debug a policy that was never written down.
The whole industry is converging on this: harness anatomy write-ups, long-running- agent guidance built on progress logs and Git history, research treating the harness as a first-class executable document, and agentic-SDLC courses that treat agents as governed contributors. Bridle packages that convergence into files you can commit today. Read the full argument in the Manifesto.
# in your project
npx github:manpreet171/bridle initYou get:
your-project/
├── AGENTS.md # project OS (skipped if you already have one)
├── HARNESS.md # ★ the Harness Script — fill in its 5 sections
├── prompts/ # AI-written implementation plans, human-approved
├── skills/ # tool know-how, tagged with cost/trust/role bands
└── logs/ # append-only run traces (JSON Lines)
Fill in HARNESS.md, then make it real:
npx bridle lint # refuses a harness missing any pillar
npx bridle run start scrape --agent claude-sonnet-5
npx bridle run log tool_call --detail '{"tool":"oxylabs","status":"ok"}'
npx bridle run log check_pass --phase evaluate
npx bridle run end good
npx bridle statusRecent runs:
GOOD scrape-20260720T1015Z-a1b2c3
harness v1.2.0 (9f3c01d2ab77) · agent claude-sonnet-5 · 5 events · 0 escalation(s)
Every event carries the run ID, the agent, the harness version and a hash of the harness file — so if someone edits the harness mid-run, the trace shows it. Full walkthrough: Adopt in 30 minutes.
Every HARNESS.md has four load-bearing sections. The linter enforces all of them,
because a run under an incomplete harness has undefined behavior.
| Pillar | Question it answers |
|---|---|
| 1 · Run Charter | What does a good run observably look like? What loop (Plan → Act → Evaluate) does every step follow? What are the budgets, and which sub-agents may exist? |
| 2 · Trace Contract | Which events — tool calls, code edits, DB writes, API hits — must be logged, where do they go, and how do they tie back to a run_id + harness version? |
| 3 · Skill Lattice | Which skills (tagged cheap/frontier, safe/risky, read-only/write/destructive) may be used in which phase? Planning never writes. Evaluation uses different eyes. |
| 4 · Governance Lane | Which changes auto-merge, which need a PR and a human, which surfaces are forbidden, and how does a run get rolled back? Your VCS is the control plane. |
Plus a fifth section, Recovery & Escalation: a per-run progress log, a resume protocol so a restarted agent never redoes finished work, and explicit triggers for stopping and calling a human. Deep dive: docs/pillars.md.
Bridle is a document and a linter. It never sits between your agent and its work:
no server, no daemon, no API key, no runtime dependency, nothing phoning home, and
no added latency on your runs. If you delete the CLI tomorrow, your HARNESS.md is
still a useful document your agents read.
What it will never do is pretend it enforced something it only recorded. The harness declares the policy; your trace proves what actually happened; branch protection and CI are what physically stop a bad merge. Bridle makes the gap between those three visible instead of imaginary.
You don't have to write all four pillars on day one. --tier lets the linter hold
you to as much as you've actually adopted, so CI stays green while you grow:
npx bridle lint --tier 1 # Run Charter only — what is a good run?
npx bridle lint --tier 2 # + Trace Contract — what must be logged?
npx bridle lint # all four pillars + recovery (tier 3, the default)One honest tier-1 harness beats four aspirational ones. Move up when the previous tier stops being a lie.
One file, zero dependencies, Node 18+: bin/bridle.mjs.
| Command | What it does |
|---|---|
bridle init |
Scaffold HARNESS.md, AGENTS.md, prompts/, skills/, logs/ |
bridle lint [file] [--tier 1|2|3] |
Verify a harness honors the pillars for your tier + no unfilled placeholders. Exit 1 on failure — CI-friendly |
bridle run start <workflow> |
Mint a run_id, stamp harness version + SHA-256 hash |
bridle run log <event> |
Append a trace event (tool_call, code_edit, db_write, api_hit, check_pass, check_fail, escalation, note) |
bridle run end <good|bad> |
Close the run with a Charter verdict |
bridle status |
Summarize recent runs: verdicts, harness versions, escalations |
Traces are plain JSON Lines validating against
schema/run-log.schema.json — pipe them anywhere
(LangSmith, PostHog, Supabase, jq). A ready-made GitHub Action lints every
harness on every PR: .github/workflows/harness-lint.yml.
bridle/
├── HARNESS.md # Bridle's own harness — we dogfood
├── templates/
│ ├── HARNESS.template.md # ★ the Harness Script template
│ ├── AGENTS.template.md # project-OS template
│ ├── SKILL.template.md # skill + lattice bands
│ └── PROMPT.template.md # AI-written plan, human-approved
├── examples/ # real harnesses, all lint-clean at their tier
│ ├── minimal-tier1/ # ★ start here — a Charter and nothing else
│ ├── scraping-pipeline/ # 24h data pipeline, zero code edits
│ └── nightly-coding-agent/ # PR-only maintenance bot
├── schema/run-log.schema.json # trace event schema (JSON Schema 2020-12)
├── bin/bridle.mjs # the whole CLI, ~300 lines, 0 deps
├── docs/ # manifesto · pillars · adoption guide
└── .github/workflows/harness-lint.yml
Bridle is deliberately not a framework. Your orchestrator — Claude Code, Copilot, LangGraph, DeepAgents, cron + scripts — stays the runtime. Bridle gives it a script to follow:
- Agent tools that load
AGENTS.mdpick up the harness via one pointer line (already in the template). - Hooks/middleware call
bridle run logat the events your Trace Contract names; no hooks? The harness instructs the agent to call the CLI itself. - Your observability stack ingests the JSONL; the schema is stable and tiny.
- GitHub enforces the Governance Lane with the included workflow + PR template.
Good neighbours, not competitors:
- ponytail shrinks what your agent builds; Bridle governs how its run behaves. No overlap — ponytail never looks at your run policy, Bridle never opines on your code.
- LangSmith / PostHog / Supabase are trace sinks. Bridle's Trace Contract declares what must reach them; they store and visualize it.
AGENTS.mdis the project OS. Bridle is the run OS. Ship both.
Nothing to uninstall, really — there's no global install. But to remove it cleanly:
rm HARNESS.md # or harness/*.HARNESS.md
rm -rf logs/ # your run traces — read them before deleting
rm .github/workflows/harness-lint.ymlState Bridle writes outside those paths: none. The only file that isn't obvious
is logs/.open-run.json, which tracks the currently open run and is removed with
logs/. Your AGENTS.md, prompts/, and skills/ are yours — init created them
but nothing in Bridle depends on them, so leave them.
Is this a replacement for AGENTS.md / Vibe Engineering?
No — it's the layer above it. Keep your AGENTS.md, skills, and AI-written
prompts. Vibe is how you stop fighting prompts on day 1; Harness Scripts are how
you stop fighting your agent architecture on day 30.
Do agents actually follow a markdown policy?
As well as they follow AGENTS.md — which is to say: well when it's loaded, and
verifiably when you check. That's why the Trace Contract exists: the trace is how
you audit compliance, not hope for it. Anything your orchestrator can enforce
mechanically (hooks, branch protection, CI lint), move from hope to enforcement.
Does it need a config file?
No. No config, no env vars, no API key, no account. HARNESS.md and the CLI are the
whole product.
Do you have benchmark numbers? No — and I'm not going to invent any. Bridle is a documentation-and-audit discipline, not a model intervention; there's no honest way to A/B "runs you could explain afterwards" as a percentage. What I can show you is the mechanism: a trace stamped with the harness version and hash, and a linter that exits 1. Judge it on that. If you run a real comparison, open an issue — I'll link it here, including if it's unflattering.
One HARNESS.md or many?
One per long-running workflow. Root HARNESS.md for your main one; extras in
harness/<name>.HARNESS.md — the linter finds both.
Why "Bridle"? A bridle is the part of a harness that gives you steering. Same relationship: the model provides the horsepower; the Harness Script decides where it's allowed to go.
The ideas here synthesize public work on agent harnesses: LangChain's harness anatomy write-ups, Anthropic's engineering guidance on effective harnesses for long-running agents, research on natural-language agent harnesses executed by intelligent runtimes, and GitHub's & Microsoft's agentic-SDLC training. Bridle's contribution is the packaging: one template, one schema, one linter, one habit.
PRs welcome — and yes, they run under HARNESS.md. Bump the harness
version when you touch it, link your run_id in the PR template, and make sure
bridle lint is green.
Manpreet Singh
- LinkedIn: linkedin.com/in/manpreet17
- Medium: medium.com/@singh.manpreet171900
- Email: info@singhlabs.dev
If you write about Harness Script Engineering or ship a HARNESS.md because of
this repo, I'd genuinely like to hear about it.
MIT © Manpreet Singh