Documentation

Agent harness

An optional, deterministic conductor for role-based, multi-agent delivery. Ryvem owns the roles, loops, gates and persistence; your client's model executes each brief. Turn it on with an agents block in ryvem.json — leave it off and every flow behaves exactly as before.

Overview

Ryvem has no LLM of its own — cognition always runs in your client. That is deliberate: it makes the harness client-universal by construction. Ryvem is the deterministic conductor; the client model is the executor. The harness owns six expert roles, a set of loop state machines, the gates each step must clear, and the persistence that lets a loop survive a process restart and resume exactly where it stopped.

Every unit of work is a brief the client executes and reports back against a validated schema. Loop state lives in the temporal memory graph, so nothing is held in process memory: MCP is stateless, and the loop node is the single source of truth the harness resumes from.

Zero breaking change

Without an agents block, work and run-board run the single-context pipeline exactly as they always have. The harness only engages once you configure it.

The six roles

Each role is a deep, opinionated domain pack (the same markdown style as the stack skill packs). Every brief embeds the role's expertise, the repo's conventions digest, and the precedence rule that local conventions always win — improvements go out as suggestions in the report, never as edits to your convention files. A role's report is validated against its schema before any gate runs.

RoleFocusDefault gate(s)
pmProblem framing, INVEST user stories, testable Given/When/Then acceptance criteria, MoSCoW/RICE prioritization, the Definition of Ready.ready-definition
techleadDecomposition into sequenced work units, dependency DAG, role assignment over the enabled agents, gate criteria, integration review, loop-budget ownership.coherence
architectLayering (hexagonal/clean), DDD strategic and tactical design, SOLID, GoF and enterprise patterns, distribution choices, ADRs and fitness functions.architecture
engineerConventions-first implementation, stack skill packs, test-first when tests exist, small verified commits, refactor and debugging discipline.architecture, security
devopsCI/CD pipeline design, infrastructure-as-code and containers, SLI/SLO observability, progressive release with safe rollback, secret hygiene.review
securityOWASP Top 10 review, authN/authZ patterns, secret handling, supply-chain integrity, STRIDE threat modeling; blocks on unmitigated high/critical findings.security

Roles are activated per repo through agents.enabled. The tech lead assigns each work unit only to an enabled role; when a needed role is disabled, its concern folds into the nearest enabled role's brief and the gap is recorded as a suggestion.

Loops

A loop is expressed as data, never imperative code: an ordered list of steps, each naming the role that executes it, the gates its report must clear, and the id of the next step. The orchestrator walks the spec, so the whole machine is auditable and resumable as graph state. There are six loop kinds.

LoopSteps (role · gate)Purpose
definepm · ready-definition → architect · architectureRefine a card into a ready, feasible definition.
planarchitect · architecture → techlead · coherenceDraw the blueprint, then decompose into sequenced work units.
buildengineer → architect · architecture → security · securityImplement one work unit and clear the architecture and security gates.
reviewsecurity · review → architect · reviewSecurity and architecture lenses over the friendly-tone PR rules (non-blocking).
boardarchitect · architecture → techlead · coherence → techlead · coherencePlan the whole board, then integrate the executed units; spawns per-unit build loops in topological order.
onboardarchitect · coverage → pm · evidence → techlead · consistencyDeep-read an existing repo into the memory graph (map, business rules, glossary, synthesis).

The build loop's first step (engineer) carries no gate — implementation is verified by the dedicated architecture and security review steps that follow. Every loop's default iteration budget is 3. The onboard loop is driven through the onboarding flow and the onboard_status/onboard_record tools; harness_next's startKind starts the five task loops (define, plan, build, review, board).

Briefs and the self-driving protocol

A brief is the complete package a role needs to act. It carries the role's identity and mission, the conventions digest, the inputs the engine resolved from the graph and intel port, the expected report shape as a JSON Schema literal, the resolved execution mode with an inline fallback, and the exact next-step protocol.

Instructions are assembled as a byte-stable static prefix (persona, role identity, mission, precedence rule) followed by a === CURRENT STATE === delimiter and a volatile trailing block (the step framing, any re-plan banner, the tier block). Separating the two keeps the client's prompt cache warm across a loop.

Because harness_next is the sole entry point, its result always tells the client what to do next. The loop is a tight cycle:

harness_next  →  returns a role brief (with its report shape + protocol)
   execute the brief AS that role (spawn a subagent, or adopt it inline)
harness_report  →  submit the report with the returned briefId + loopId
harness_next  →  advances the loop, or reports it is done
   … repeat until harness_next returns loop-done

The cycle is idempotent by construction: while a brief is pending, harness_next re-serves the same brief, and harness_report accepts only that briefId. Every subagent brief embeds an inline fallback — a client that cannot spawn a subagent adopts the role itself in the same context and notes the substitution, rather than failing.

Gates

A gate is a named acceptance check run against a validated report. When it passes, the loop advances; when it fails, it produces concrete, actionable feedback that the next brief embeds so a retry is informed, not blind.

GateAttested fieldBlockingPasses when
ready-definitionreadyForDevelopmentYesThe card meets the Definition of Ready (no blocking open questions).
coherencecoherentYesThe work-unit DAG is acyclic and every unit is INVEST-shaped.
architecturefeasibleYesThe design is judged sound to proceed.
securitygatePassYesNo high/critical finding is left without an accepted mitigation.
reviewNoAlways — a non-blocking lens that surfaces findings without halting.
coveragecoverage[]YesThe onboard map records at least one area actually read.
evidencerules[].evidenceYesEvery business rule is anchored to at least one file path.
consistencyconsistentYesThe onboard map and knowledge are free of contradictions.

Evidence-executed gates

Attestation alone is weak — a model can report gatePass: true. So a gate can be bound to real shell commands that Ryvem executes itself. Define the commands in agents.checks and bind them to gates in agents.gateChecks; a bound gate passes only if its attestation held and every check exited 0. Ryvem captures the exit code and a redacted tail of output (up to 4000 chars), persists it on the gate result, and folds the failing excerpt (up to 1200 chars) into the retry feedback.

{
  "agents": {
    "enabled": ["engineer", "architect", "security"],
    "execution": "subagents",
    "maxIterations": 3,
    "checks": [
      { "id": "unit",  "run": "npm test",        "timeoutMs": 300000 },
      { "id": "lint",  "run": "npm run lint" },
      { "id": "types", "run": "npm run typecheck" }
    ],
    "gateChecks": {
      "architecture": ["lint", "types"],
      "security": ["unit"]
    }
  }
}

Each failed gate spends one iteration. When the budget (maxIterations, default 3) is exhausted, the loop escalates to you with the full trail — every gate result and what was tried — rather than looping silently or lowering the bar. On escalation (and on an explicit abort) the last schema-valid report is persisted as a salvage with an exit reason, so partial work is never discarded.

Checks are user-authored

The commands run at the same trust level as an npm script — they live in your committed ryvem.json and secrets are redacted from captured output. With no checks/gateChecks, every gate is attestation-only, exactly as before.

Stuck detection and salvage

A separate, zero-inference layer watches the loop's report history for repetition. It is pure bookkeeping over data already in the graph — no LLM, no I/O — and it recognizes three deterministic patterns.

PatternFires when
identical-reportsThe last 3 reports (same role and payload) are byte-identical.
abab-alternationThe last 4 reports alternate between two distinct reports (A, B, A, B).
gate-feedback-loopThe last 3 reports each fail the same gate with identical feedback.

When any pattern fires, the next brief is prefixed with a RE-PLAN banner: diagnose the root cause of the repeated failure rather than the symptom, change strategy — a different decomposition, tool or assumption — and state explicitly what is being done differently. Unlike harnesses that halt and wait for a human, Ryvem's detector never stops the loop; it redirects it.

Model tiering

The strongest model should orchestrate; cheaper models should execute the grunt work under its plan. Model selection is always client-side — no MCP server can switch the client's model — so Ryvem expresses tiering as configuration, brief protocol text, and graph bookkeeping, never as a hidden API call.

A tier profile is a small record: an id, a model string in provider/model form, an optional reasoning effort (low/medium/high/max), an optional editStyle (diff/whole), and a note. A role pins only what it names and inherits the rest — a role's executor tier is its own overrides.<role>.tier, or the orchestrator default otherwise.

{
  "agents": {
    "orchestrator": "flagship",
    "tiers": [
      { "id": "flagship", "model": "provider/large", "effort": "max" },
      { "id": "worker",   "model": "provider/mid",   "effort": "high", "editStyle": "diff" }
    ],
    "overrides": { "engineer": { "tier": "worker" } }
  }
}

At loop start the brief frames the top-level model as the orchestrator and instructs it to delegate, not execute. Each role descends with its tier stated and locked for the sub-run, plus the inline fallback for clients that cannot select a subagent model. This is an architect/editor split: the architect (or tech lead) produces a plan; the engineer receives that plan verbatim as a work order and a cheaper tier executes it mechanically — with the evidence gates watching the result.

Tiering is also adaptive, but only as advice recorded in the graph for audit. After 2 consecutive same-step gate failures, or when the stuck detector fires, the harness recommends escalating the step to the orchestrator tier. After 2 clean first-try passes at an escalated tier it recommends downgrading back. The client applies the recommendation where it can; the engine never switches a model itself.

Token economy

Context is the scarce resource. The harness attacks it with mechanisms borrowed from the best coding harnesses and measured on real inputs — engineering, not model problem-solving.

Budgeted repo map
99.5%smaller

~1.4 MB of source rendered as a 7.7 KB ranked symbol skeleton, fitted to an exact token budget.

Output shaping
96%smaller

A 488 KB tool flood capped to 19.6 KB with a "run a narrower query" nudge.

Blob-hash cache
29/30from cache

After editing 1 of 30 files, the changed blob is re-parsed and the other 29 are served from the graph cache.

Measured with bun bench/synthetic.ts — zero model inference.

Budgeted repo map

The repo_map tool returns a ranked symbol skeleton — files with their key definitions — instead of dumping whole files. Symbols are extracted per file, the definition/reference graph is ranked by personalized PageRank, and the ranked list is fitted to an exact token budget by binary search (largest score-ordered prefix whose render fits) with a cheap chars/4 estimate. Each file's symbol index is cached per git blob hash and re-parsed only when its blob changes; files over 512 KB and binaries are skipped. The default budget is 2000 tokens, and focus path fragments bias the ranking toward what you care about.

Context ledger

Within a loop, once a sizeable artifact — the conventions digest, an accepted plan, a checkpoint — has been embedded in a brief, a later brief that would re-embed the same version instead emits a single pointer line: "you already hold this, unchanged — do not re-read." The version is a content hash, so the pointer is replaced by the full artifact automatically the moment it changes. Second briefs shrink toward a single line.

Onboarding deltas

Reading a repo into memory is incremental. On the first pass onboard_status returns the full budgeted deep-reading protocol and records a git anchor alongside the codebase map. On every later pass it diffs HEAD against that anchor (via merge-base) and returns the exact targeted work list — areas to re-read, new areas, files to verify as removed, and renames — never a whole re-read. The intelligence about what changed is server-side and deterministic; a checkpoint condenses loop progress so later briefs re-seed from graph state instead of dragging the transcript.

Driving the harness

Five harness_* tools drive everything; the universal entry point is harness_next. See the MCP tools reference for full signatures.

ToolRole in the loop
harness_nextThe self-driving entry point: acquires the loop lease and returns the pending or next brief (or reports the loop done).
harness_reportSubmits a completed brief's report; the engine validates it, runs the gates, and advances or spends a bounded retry.
harness_statusLists live loops and their state (kind, status, step, iteration, pending brief) without advancing anything.
harness_configWrites the agents block of ryvem.json — enabled roles, execution mode, budget, tiers, checks.
harness_abortTerminally aborts a loop and releases its lease; it serves no further briefs.

In a client with slash commands the flows drive this for you. In a client without them, paste this into your rules file (.cursorrules, an Antigravity or Codex rules block):

When working a board task through the "ryvem" MCP server, drive the agent harness:
1. Call harness_next (with startKind:build and subject:<TASK-KEY> to start a build loop).
2. It returns a role brief plus the exact next-step protocol. Execute the brief AS that role.
3. Submit the result with harness_report, passing the returned briefId and loopId.
4. Call harness_next again and repeat until it reports the loop is done.
The briefs already embed the repo's conventions, the role's expertise and the gates.
If your client cannot spawn subagents, adopt each role yourself in the same context.

Ownership, leases and reconciliation

Each loop carries a lease — a session id and a heartbeat — that harness_next acquires and refreshes. A lease held by another live session blocks; a lease whose heartbeat is older than 5 minutes is stale and reclaimable only with an explicit takeover: true. And because work often finishes out of band, an external finish or PR merge reconciles any open loop on that subject to completed-externally, so the harness never keeps serving stale briefs. Configure the harness in Configuration; everything it remembers is queryable in the memory graph.