The Archyl Harness: Coding Agents That Declare Their Work Before They Start

Last week I wrote about three agents, three pull requests, and one incoherent system. The post ended with an exercise: take the last week your team merged more than one agent-authored pull request, read them side by side, and ask what in your current setup would have told you they disagreed.

I did that on our own repository and the answer was nothing. Not "the reviewer eventually noticed", not "CI caught half of it". Nothing, because none of the agents ever said what they were about to do. Each one read the repository, wrote code, and opened a pull request. The first moment a human could see two of them working on the same service was review, which is the last moment, and by then both had finished being confident.

So we built the missing step. The Archyl Harness shipped this week. It is not another coding agent. It sits above the agents you already run, and it makes each of them announce a unit of work, against the documented architecture, before it touches anything.

A work session, from the inside

The loop has four calls, exposed as MCP tools. An agent plans, opens a session, works while heartbeating, and closes the session with what actually happened.

Here is the second of those calls, from a real session on the Archyl project itself, trimmed:

▶ start_work_session(
    task: "rank recalled memories by freshness so stale facts stop winning",
    agentName: "claude-code/vincent")

# Harness Session

- **Session ID**: `24643fa6…`
- **Gate**: warn
  - 1 target element(s) are being worked on by other active sessions — coordinate before changing them
- **Leased elements** (you are the announced worker on these):
  - component `Harness Service`
  - container `MCP Server`
- **Conflicts** (someone else is already working here):
  - MCP Server — held by claude-code/memory-ui: render the memory graph with element clusters

**Protocol**: call `heartbeat_work_session` at least every 30 minutes while working,
and `finish_work_session` with a summary (and decisions worth recording) when done.

## Most relevant elements

- **Harness Service** (component) — `backend/internal/service/harness`
  Work sessions, leases, preflight gate, element memory.

## Related decisions (respect these)

- ADR-5: Agents propose, humans merge [accepted]

## What previous sessions did here

- **MCP Server** [PITFALL] (claude-code/vincent, 1 day ago): every new ID argument
  name must be added to idArgumentResolvers in authz.go, or the cross-org check
  silently skips it.

Four things happened in that single call, and none of them are things a rules file can do.

The task was resolved against the C4 model, so the agent got the slice of architecture that matters instead of the whole thing. Advisory leases were taken on the elements it is about to change, which is how the next agent finds out about this one. The preflight gate returned a verdict. And the briefing carried the decisions that constrain the work, plus what the last agent to stand here learned the hard way.

That last line is memory, and it deserves its own post rather than a paragraph in this one. The short version: sessions leave notes, conventions and pitfalls attached to architecture elements, and the next session gets them back automatically.

The gate has three verdicts, and deny is the rare one

The preflight gate is deliberately small. It answers one question, before work starts, with a verdict the agent can act on.

allow means no other session holds a lease on your target elements and no error-level guardrail applies to the task. Proceed.

warn is the common one, and it comes with reasons. Another session is already working on an element you are about to change, or a conformance rule with error severity covers this task. The exact string in the first case is the one you saw above: N target element(s) are being worked on by other active sessions — coordinate before changing them. The agent proceeds, but it has to address every listed reason, and the reasons name names.

deny only happens when a session asks for it. Pass exclusive: true and a lease conflict stops the session instead of warning it. That is the flag for work that must not race with anybody: a schema migration, a contract change, a rename that touches every caller. The session never opens, and the agent is told to report to the user rather than route around it.

Being precise about this matters more than making the gate sound clever. deny is not a policy engine. It does not read your plan and refuse it on principle. It refuses to let two agents claim the same element when you have said that element is exclusive, and everything else is a warning the agent must answer for.

The Guard watches the writes

The session covers intent. The Guard covers what actually gets written.

It is a PreToolUse hook for Claude Code, installed with the plugin. Before the agent writes or edits a file, the hook reconstructs the file as it would be after the edit, sends it to your project's conformance rules, and reads the verdict. A critical violation blocks the write and returns the reason to the agent:

Archyl Guard: this change violates the project's architecture rules for
backend/internal/adapter/http/handlers/report.go:
- [critical] No direct database access from HTTP handlers — move the query
  behind a service

Adjust the change to respect these rules, or ask the user whether to override them.

The agent reads that, fixes the layering, and carries on. No human was interrupted, and the violation never reached a branch.

Two design choices are worth stating plainly. ARCHYL_GUARD_BLOCK controls the threshold: critical by default, high to block more, off to warn only. And the hook is fail-open everywhere. No API key, no network, no jq installed, a slow response: the edit proceeds untouched. A governance tool that can break someone's editing session gets uninstalled in a week, so it can't.

Closing the loop

finish_work_session takes an honest outcome: a summary, the decisions worth recording, the follow-ups left undone. The leases are released, the summary is pinned to the elements the session held, and if the work changed the architecture, createChangeRequest: true opens a draft Architecture Change Request.

That is the part that keeps the model from drifting silently. An agent that restructures a service does not quietly edit the C4 model. It files a proposal, a human reads how the documentation should catch up, and the merge goes through the version check we wrote about last week. Agents propose. People merge. We are not planning to remove that boundary.

Across it all, the Fleet console in the Agent Hub shows every session in the organization live: who is working, on what, holding which elements, behind which gate, how fresh their last heartbeat is. Elements under an active lease also show a working indicator directly on the C4 diagram, which is the view where "someone else is in here" is actually useful.

We built it under itself

The Harness was built by agents working under the Harness, on an Archyl project that documents Archyl.

That was not a demo. It was the only way to find out whether the loop survives contact with real work, and it changed the product several times. Sessions hit warn for real, on real conflicts, because two agents were genuinely editing the same container in the same hour. The pitfall in the transcript above is a memory one session wrote after losing an afternoon to it, and a later session got it back in its briefing before touching the same file. Three Architecture Change Requests came out of those sessions, each one a human reviewing how the model should catch up with what an agent had just done.

It also produced smaller corrections that only dogfooding surfaces. The gate badge in the console used to render a neutral chip for allow, until it was pointed out that a badge showing "nothing is wrong" on every row is noise. It now renders nothing at all when the verdict is allow with no reasons, and the reasoning behind that got stored as a convention on the project, so the next agent to touch that component does not helpfully add it back.

Installing it takes one command

From the root of your repository:

curl -fsSL https://raw.githubusercontent.com/archyl-com/agent-skills/main/templates/setup.sh | bash

It asks for your project and an API key, then writes three things: a .mcp.json pointing at Archyl's MCP server with ?profile=coding, a committable .archyl.json binding the repository to the project (the key stays in your environment), and the harness loop appended to CLAUDE.md and AGENTS.md:

# Architecture — Archyl Harness

This project's architecture is documented in Archyl. Work under the harness loop:

1. For any non-trivial task, call `plan_work` first — it returns an implementation
   plan grounded in the documented architecture.
2. BEFORE changing code, call `start_work_session` (task + your agent name).
   Read the briefing: gate verdict, leased elements, conflicts, decisions, guardrails.
...

Then /plugin marketplace add archyl-com/agent-skills and /plugin install archyl-developer@archyl-marketplace in Claude Code, which brings the archyl-harness skill and the Guard hook. Plugin version 0.7.0 is live.

?profile=coding is the small detail that makes the rest work. Archyl's MCP server exposes 189 tools, which is the right number for managing an architecture and the wrong number to put in front of an agent that is trying to add rate limiting. The coding profile advertises 16: orientation, task-scoped context, the four session tools, memory, and the conformance and diff checks. Nothing that edits the model directly, because that path goes through Change Requests. In our own testing, an agent handed the full catalog explores it. An agent handed sixteen tools follows the loop.

What it doesn't do

Leases are advisory. Nothing locks. A lease tells the second agent that the first one is in there, in its briefing, in the console and on the diagram. It does not stop it. That is deliberate for now, because a hard lock on a model of your architecture is a very effective way to stop your team from working when an agent dies mid-session, but you should not describe leases to your team as mutual exclusion.

An agent that never opens a session is invisible. Every guarantee here starts with the agent calling start_work_session. Nothing in the protocol forces that call. The skill and the CLAUDE.md snippet make it the default behavior; a determined agent, or one connected without the harness skill, simply writes code the way it always did. The Guard hook is the one part that fires without cooperation, and only in Claude Code.

deny is only as good as what you wrote. The gate reads your conformance rules and your leases. An empty rule set and a single agent produce allow forever, which is technically correct and completely uninformative.

Plans are grounded, not correct. plan_work is an AI plan built from your C4 model, ADRs and guardrails, with a deterministic fallback that returns the ordered ground truth when no AI provider is configured or the model returns something unusable. It respects the documented architecture. It does not know whether the documented architecture is a good idea.

A Change Request needs a known author. Sessions started with a credential that is not bound to a user can't open one, and finish_work_session says so in its response rather than failing. If your CI bot's key is org-scoped, its outcomes land as memory but not as a proposal.

Where to start

If you already run agents against a documented Archyl project, the setup command above takes about five minutes and the first session will tell you something. Watch the Fleet console during an afternoon when two agents are running. The interesting moment is the first warn, because it names a collision that used to be invisible until review.

If you don't have a documented architecture yet, that is the actual prerequisite, and it is the same one as always: the Harness arbitrates using the model, so an empty model arbitrates nothing.


The Harness is part of archyl: work sessions, the preflight gate, the Fleet console and memory. The plugin, skills and Guard hook and the GitHub Actions are open source. Full setup is in the Harness guide. Related reading: many agents, one architecture, why your agents have a rules file and not a model, and the MCP server behind it.