Expand description
§harness-loop-engine — loop engineering for harness-rs
Agent = Model + Harness. A harness wraps a single agent call. A loop wraps the harness: it runs that call again and again, on a cadence, with state, verification, budgets, and gates — driving toward a goal over time instead of in one shot. This crate is harness-rs’s loop layer.
“Loop engineering is replacing yourself as the person who prompts the agent. You design the system that does it instead.” — and you stay the engineer responsible for that system.
The building blocks already live elsewhere in harness-rs — scheduling
(harness-scheduler), worktrees (harness-sandbox), sub-agents
(harness-loop), memory (harness-core), MCP (harness-mcp). What this
crate adds is the orchestration discipline that turns those parts
into a loop you can trust:
LoopLevel— maturity levels L1 (report) → L2 (assisted) → L3 (unattended). A loop earns autonomy in stages.HumanGate— the proceed-or-escalate decision, tied to the level. Built-ins:AlwaysEscalate,AllowlistGate,CallbackGate.ActionExecutor— the side-effect handoff after a verified L3 auto-approval. Built-ins:ApprovalOnlyExecutor,CallbackActionExecutor.TokenBudget— a per-round spend ceiling, because unattended loops spend without bound if you let them.LoopSpec— the inert, serializable description of a loop.LoopEngine— the runner: recall state → isolate → maker sub-agent → checker sub-agent → gate → record state.LoopScheduler— runs loops on their cadence.patterns— the seven named production loops (daily triage, PR babysitter, CI sweeper, …), each a ready-madeLoopSpec.
§The anatomical loop
schedule (cadence)
│
▼
recall STATE / memory ──► isolated worktree (sandbox)
│ │
│ ▼
│ maker sub-agent (proposes)
│ │
│ ▼
│ checker sub-agent (tests + gates)
│ │
│ ▼
│ human gate? ──┬─ safe/allowlisted ─► action executor
│ └─ risky/ambiguous ──► escalate
▼ │
write STATE / memory ◄────────────────────────── recurse next tick§Two debts to watch
Loop engineering names two failure modes that accrue silently. This crate makes them visible rather than solving them — they are engineering responsibilities, not features:
- Intent debt — the drift between what a loop was meant to do and
what it actually does. Antidote:
LoopSpec::intentis a required, one-sentence statement of purpose, injected into every maker turn and printed in every report. Review it as the loop evolves. - Comprehension debt — the gap between what the loop ships and what humans still understand about its behaviour. Antidote: the maker/checker split, the recorded state spine, and rendered reports keep a legible trail of every round.
§Safety stance
Verification stays on you — unattended loops make unattended mistakes.
Defaults are conservative: L1 makers are strictly read-only, the default
gate for every level is AlwaysEscalate, and L3 auto-proceed requires
an explicit AllowlistGate. Graduate a loop’s level only as you build
trust in it.
Modules§
- patterns
- The production-loop catalogue.
Structs§
- Action
Receipt - Evidence that an auto-approved action was handed off to its executor.
- Allowlist
Gate - Auto-proceeds only for verified actions whose
kindis on the allowlist, and only at L3. Everything else escalates. This is the workhorse gate for unattended loops with a narrow blast radius. - Always
Escalate - Never auto-proceeds — every proposal is escalated. This is the correct gate for L1 loops (and a safe default for anything you’re unsure about).
- Approval
Only Executor - Default executor: records that a gate approved the action but performs no
external side effect. This keeps
LoopEngine::newsafe while making the missing production handoff visible in the round report. - Budget
State - Running tally of spend within a round, checked against a
TokenBudget. - Callback
Action Executor - Wrap a synchronous callback as an
ActionExecutor. Use this for application-specific handoffs without defining a bespoke type. - Callback
Gate - Wraps an arbitrary closure as a gate — for custom policies (budget-aware, time-of-day, denylist, MCP-scope checks, …).
- Loop
Engine - Binds a
LoopSpecto the live pieces it needs to run: a model, the maker/checker tool sets, an isolation sandbox, a gate, and (optionally) memory for the state spine. - Loop
Scheduler - Ticks registered loops on their cadence.
- Loop
Spec - Declarative definition of a single loop.
- Proposed
Action - A change the maker produced and the checker verified, presented to the gate for a proceed-or-escalate decision.
- Round
Report - The full record of a round — the maker/checker reports, token spend, the gate decision, and the outcome. Suitable for delivery to a channel and for writing to memory.
- Stdout
Sink - Prints deliverable reports to stdout.
- Token
Budget - A declarative spend ceiling for a single round of a loop.
Enums§
- Action
Error - Budget
Limit - Which ceiling a round crossed.
- Gate
Decision - The gate’s verdict for one proposed action.
- Loop
Level - How much autonomy a loop is trusted with.
- Round
Outcome - What one round of a loop did.
Traits§
- Action
Executor - Carries out a verified, auto-approved action.
- Human
Gate - Decides what happens to a verified proposal. Implementations encode the human-gate policy; the engine consults this once per round.
- Loop
Sink - Where a finished round’s report goes. Implement this to route reports to Slack, email, a file, a tracker — anywhere. The default is stdout.
Functions§
- default_
gate_ for - The gate a level implies when the caller doesn’t specify one.