If you've been running agents for any length of time, you've probably noticed: the model isn't usually what's wrong. Models can write code, review it, plan architecture, debug failures. The part that breaks is what the model knows when it's doing those things: what got loaded, what got forgotten, what carried over from last run. Every architecture decision I've made on belayer in the last six months traces back to one question: how do you get the right context to the right task at the right time? That's the constraint — capability is downstream of it.

Hand-drawn framework diagram showing a harness router balancing depth, freshness, memory, context budget, and telemetry.

Runs end before agents get dumb

Context windows fill up. The more an agent reads, writes, and reasons, the worse it gets at all three. I started calling this the dumb zone — the point on the curve where adding more context degrades performance instead of improving it. You can usually feel it land in real time: the agent stops asking clarifying questions, starts repeating itself, starts trying things it already tried.

The naive fix is discrete runs. Break work into bounded sessions. Let each one start relatively clean. This is what humans already do, by the way: close the chat, open a new one, start the next task. Most harnesses today treat this as the answer, and it's the answer baked into V2 of belayer too.

But it's also a confession. Discrete runs work by truncation. We bound the window because we don't trust the agent to manage what's in it. The trade is amnesia: the agent that just spent 40 minutes understanding your architecture starts fresh next time, knowing nothing. Now we've got two problems that look like one: the dumb zone is the run-too-long problem, and amnesia is the runs-don't-talk-to-each-other problem. A harness that only solves the first creates the second.

Why can't the agent reason about the context it needs? If it knows what task it's doing, it should be able to ask "what would help me here?" and pull only what's relevant: the file, the prior decision, the test fixture. That beats having the harness pre-stuff a window with everything that might matter.

The agent has the model. The model can reason. Reasoning about what context to load is a task like any other.

That's the direction I think the next generation of harnesses has to go: less "what should I pre-load" and more "what should the agent be allowed to fetch on demand." Discrete runs become a tool for the agent to wield instead of a wall the harness puts around it. I'm leaving that argument for its own post. For now, it is the load-bearing assumption underneath everything that follows: discrete runs are how we cope today, and the rest of the architecture has to bend around that limitation while we figure out how to remove it.

Three demands pulling on one window

The same context window has to serve three different jobs across a normal day of work, and they don't agree about what should be loaded.

Depth. Implementation wants the plan, the architecture, the surrounding code, the test patterns — all of it close. More relevant context means better code. The agent doing the writing needs to hold the whole picture in view.

Freshness. Review wants the opposite. Loading the implementation context is how you get confirmation bias. The reviewer should encounter the code the way a human reviewer would, without knowing what the author intended — only what the code does. A reviewer who read the spec validates intent. One who didn't finds what the code does.

Memory. Prior-run learnings need to surface when relevant: what broke last time, which patterns this repo follows, what was tried and failed. All of it has to feed into both depth and freshness without crowding either one.

A harness that serves all three is the hard problem. Most don't try — they pick one and hope you don't notice the others.

Everything is moving, all at once

The model that's best at orchestration isn't the model that's best at reasoning through dense code, which isn't the model with the best vision processing. Opus 4.7, GPT-5.4, Gemini 3 Pro: these are engines, getting better at different things at different rates. That's just the model layer.

At the harness layer, new code review tools, planning frameworks, and QA scaffolds ship weekly. Each one is better than the last at something specific. Lock into any single tool at any layer and you watch the rest of the industry move past you. Constantly swap tools and you never build depth with any of them. The ecosystem rewards experimentation and production rewards stability; any architecture that doesn't account for that is either too rigid to grow or too loose to rely on — and that tension shapes every decision below. The shape of the system has to be one where you can swap layers without rewriting the others.

The model, the harness, and the repo

I find it useful to split agent identity into three layers: the model, the harness, and the repo context. They have different owners, different lifecycles, and different jobs. The split isn't universally agreed on — more on that below — but treating them as separable is what makes the rest of the architecture tractable.

The model is stateless intelligence

It has no built-in knowledge of your repo, your conventions, or what it did last run. It's a function: prompt in, completion out. This is the layer where you want the most flexibility, because the best model for a task today might be the wrong one next month. Your architecture should make model swaps boring and unsurprising.

The harness is the runtime that wraps the model

Claude Code, Codex CLI, Cursor, OpenCode, hermes-agent, pi-mono — these are agent runtimes. They give the model tools, file access, memory, and workflow — discrete runs happen here. Where context gets shaped. Where the decision is made about what the model sees and what it doesn't.

It's also where the three competing demands collide. A code review tool that loads the full implementation plan before reviewing creates confirmation bias. A planning tool that doesn't load the codebase architecture produces plans that don't fit. The harness's job is to route the right context to the right task — and that job is harder than it looks from the outside.

The repo context is the world the harness operates in

CLAUDE.md. Architecture docs. Test conventions. The accumulated knowledge of how code gets written here. This is the layer you own as an engineer. It's what makes "write a function" become "write a function that follows our patterns, uses our error handling, and respects our module boundaries."

The repo context has a different lifecycle from the harness. You might switch from Claude Code to Cursor tomorrow — but your CLAUDE.md, your architecture docs, your conventions stay with you. They should survive any tool swap, which means they can't be locked inside any one tool.

Three phases, three contracts

belayer's pipeline runs in three phases: explore, climb, summit. Spec in, PR out, quality gate at the end. That part of V2 still holds. What V2 got wrong was treating the harness as "bring your own": a black box that wasn't the orchestrator's concern. That understated the hardest part, because each phase has a different relationship with context, and getting that wrong is how you get automation that ships confidently in the wrong direction.

Explore — anything becomes a spec

Explore takes whatever you've got — Figma files, tickets, brainstorming transcripts, screenshots — and produces a spec.md.

Explore is where memory matters most. The agent writing specs needs to know what's been tried before, what patterns this repo follows, what the team's priorities are. Without long-term memory, every spec starts from zero — and specs that ignore history repeat it. This is the phase where persistent context earns its keep.

Climb — spec becomes a PR

Climb takes a spec.md and produces a PR. Depth matters here. The agent needs the plan, the surrounding architecture, the module boundaries, the test patterns — all loaded and close. Implementation is context-hungry by nature.

But it's also where the dumb zone hits hardest, because the work is long. A complex feature can fill a context window before the code is done. The harness has to manage this tension: deep context, bounded runs, and continuity between them.

Summit — PRs become value

Summit takes a PR, runs a risk gate and regression sweep against staging, and outputs a merged change, a flag, or a rollback.

Summit is where freshness matters. The reviewing agent should encounter the code without the implementation context. It should see what the code does before it sees what the author intended. Confirmation bias is the silent failure mode of automated review.

A reviewer that loaded the plan will validate intent. A plan-blind reviewer will find what the code does. That's the real validation-vs-verification difference.

The harness as router, not container

V2 missed this. The harness isn't just "the thing that runs the agent." It's the layer that decides: explore gets memory, climb gets depth, summit gets fresh context. Same underlying learnings, different projections into each context window.

A harness that treats every task the same — loading everything it has into every run — is leaving performance on the table at best and introducing systematic bias at worst.

Tight integration vs. composability

There's a genuine, unresolved disagreement here about whether the layers should be cleanly separable or deeply woven.

On one side, projects like OpenCode and much of the open-source agent community advocate for clean separation. The harness loads context, the context lives in the repo, the two stay composable. Memory is a capability the harness provides instead of something the harness becomes.

On the other, Anthropic's Claude Code has built a multi-level memory hierarchy directly into its harness. Letta, born from the MemGPT research project, argues the question itself is wrong: memory isn't a plugin you add to a harness, it is the harness. Their position is that managing context is the harness's core job, and treating it as a separable concern produces shallow systems. Randomlabs' Slate takes a similar line; its Thread Weaving architecture treats memory management and orchestration as the same problem, inseparable by design.

The integrated camp makes a strong case. The harness does make invisible decisions that external plugins can't control: how instructions load into context, what survives compaction, how memory surfaces to the agent. Claude Code's memory system is a three-layer bandwidth-aware hierarchy with background consolidation, staleness detection, and aggressive pruning, all built directly into the harness. Letta's Context Constitution codifies similar principles. These aren't superficial integrations. They're deeply engineered, and they work.

One observation worth sitting with, though: the parties most heavily advocating for vertically integrated context — where the lines between repo context and agent harness blur — are also the ones with an economic incentive to keep you in their ecosystem. Tight coupling creates switching costs. Switching costs create lock-in. That doesn't make them wrong. It does make the argument worth examining carefully.

I'm currently leaning composability. Not because the integrated approach can't produce better results today, but because when the ecosystem shifts this fast, the ability to swap any layer without rewriting the others is a bet I'd rather make than the alternative.

belayer as a language, not a runtime

So if the harness is the layer that routes context, what's the orchestrator? My current position is that it should be a declarative language rather than a runtime. A YAML pipeline that says: run explore with this input, run climb with this spec, run summit with this PR. Each node is a black box. The pipeline defines sequence, contracts, and data flow. It doesn't define what's inside.

If the language is right, any orchestrator can speak it. The pipeline becomes the spec that orchestrators run instead of an orchestrator you're locked into. Docker Compose doesn't care what's in your container; belayer's pipeline doesn't care what's in your node. It cares that spec.md goes in and a PR comes out.

This refines what "bring your own harness" means. The orchestrator still doesn't prescribe which harness you use. But it does have opinions about what a harness must support to be orchestratable:

  • Long-term memory that persists across discrete runs
  • Context shaping per task type — not just "load everything"
  • Event-driven entry points — the orchestrator triggers work based on pipeline events instead of interactive sessions

These aren't implementation requirements. They're interface requirements. How you build the memory system, how you shape context, how you handle events — that's yours. But if your harness can't do these three things, the pipeline can't route context correctly, and the orchestration falls apart.

You can't learn from what you can't see

One more cross-cutting requirement is telemetry. If you're going to swap models, swap harnesses, swap orchestrators, you need to know what changed and whether it made things better or worse.

Without rich, queryable data on every run, you're flying blind: what model wrote this code, what session produced this PR, what plan led to this outcome. Evals are impossible. Regressions go undetected. The question "did switching from Opus to Gemini for planning improve spec quality?" becomes unanswerable.

A telemetry layer isn't a telemetry system. It's a requirement that one exists. The data is already being produced — git history, session transcripts, model attribution. The missing piece is the join layer that connects code to the session that wrote it, the session to the model that ran it, the model to the pipeline that triggered it. Without that join, every architecture conversation reduces to vibes. With it, you can run experiments and learn.

A good telemetry layer doesn't have opinions about how you collect this data. It has opinions about what must be queryable: which agent wrote which lines, in what session, with what confidence. The rest is yours.

Notes

  • Context is the constraint. The harness is where it gets solved.
  • Three demands — depth, freshness, memory — share one window. A harness that doesn't acknowledge the trade-offs is making them implicitly.
  • Three layers — model, harness, repo context — should be separable, at least until someone proves the integrated camp has a sustained edge that survives the next model swap.
  • Three phases — explore, climb, summit — each get a different context projection from the harness, sourced from the same memory.
  • If the contracts between layers are right, each layer can evolve independently. That's the bet. I don't know yet whether it's right, but it's the direction I'm walking, and this is what I'm learning along the way.

Up next

Discrete runs are a load-bearing crutch in everything above. The follow-up post is about getting rid of them: agents that reason about their own context budget. What to pull in, what to drop, what to ask the harness to fetch. Discrete runs become a tool the agent uses instead of a wall the harness puts around it. That's where the architecture has to go.