Principles for Solving long horizon tasks with Harness Engineering
A system that forgets well.

Coding agents can complete small tasks. But they fail, often spectacularly when working on larger ones. So much so that since early days it has become common sense that a larger goal should be broken down into tasks for an agent to be effective. Besides that, context-window rot has always been a constant. The longer it has to go on its own the worse the output. So, a useful agent system should therefore do three things well:
- break a large goal into sufficiently smaller tasks
- delegate those tasks without losing coordination
- preserve the important context while discarding low-value details
The goal is to build a system that manages context deliberately.
Before we side track
I know there is a broader debate between reading and understanding every line of code an agent writes and using completely autonomous fleets of agents like the system I am about to describe. I think that is a different discussion. There are systems, and parts of systems, where not reading the code is a perfectly valid choice. Not all code has the same value. I think much of the disagreement around agentic coding comes from pretending that all code should be held to the same standard. Startups can reasonably trade understanding for speed when the code is mostly a means to validate an idea, raise funding or reach an exit.
In some environments, I’d argue that that trade-off is harder to make. You often need to own the domain you are working in. Even if all the generated code is correct, there is a limit to how much a person can read and understand. Beyond that point, the risk is losing the ability to reason about the system and modify it with confidence.
Now, if you’re interested in letting go off the wheel, the following are some thoughts why that doesn’t work with vanilla agents in July 26 and what to do about it.
The mismanaged Geniuses Hypothesis
The mismanaged Geniuses Hypothesis
Agents are usually trained on relatively small, self-contained tasks. These might include:
- adding a database table
- connecting an API
- fixing a failing test
- implementing a component
- configuring a web server
- changing a form
- debugging a specific error
These tasks appear often in training data. They have clear boundaries and usually fit inside one working session.
A complete application is different. The exact application is likely to be unique. I mean, that’s the whole purpose of building an application. It is something new. Something unique, otherwise you wouldn’t need to build it in the first place. So it follows that there may be many examples of authentication systems, database migrations and React components, but there are far fewer (sometimes none) examples of the precise end-to-end product or feature you are trying to build.
This makes complete projects out of distribution. Their duration, complexity and number of dependencies are larger than the tasks agents usually see.
However, the smaller tasks inside the project are not unusual.
Decomposition transforms an unfamiliar long-horizon task into a sequence of familiar short-horizon tasks.This is why task decomposition improves agent performance.
Why one agent wont cut it
A single agent can often make good progress at first. Over time, however, its context fills with low-level material:
- tool-call output
- source files
- generated code
- command logs
- failed attempts
- temporary observations
- repeated explanations
- intermediate reasoning
- irrelevant details from completed work
Some of this information matters when the agent is working on one specific problem. Most of it does not need to remain in the main context for the rest of the project.
As the context grows, the agent may lose track of the original goal. It can become trapped in one failing implementation, repeat old experiments or forget why earlier decisions were made.
The problem is not only the size of the context window. It is the quality and composition of the information inside it.
The agent needs high-density context: decisions, constraints, failures, outcomes and current state. It does not need a complete transcript of every action.
Replace raw history with processed memory
Instead of placing every tool call and implementation detail in the main agent’s context, the system should process events as they happen.
A dedicated memory process could extract facts such as:
- what the agent attempted
- what worked, what failed, why it failed
- which files changed
- which assumptions were confirmed or disproved
For example, instead of preserving a long terminal session, the system might store:
The agent tried to authenticate with an API key in the request body. The service rejected this with a 401 response. The documentation and a successful manual request confirmed that the key must be sent in the Authorization header. The client now uses a bearer token. Integration tests pass.
That memory now has the important result without keeping every command, response and failed code edit.
A useful memory may also include an important code snippet, a file reference or test result when those details are necessary. The idea is just to preserve only the detail that has future value.
Use specialised context processors
A single memory process may not be enough. Different processors can maintain complementary views of the project:
- Implementation memory: changes, failures, fixes, key code locations and technical reasoning.
- Project state: goals, dependencies, completed or blocked work, unresolved questions and next actions.
- Product state: the current interface, incomplete flows, design mismatches and visual regressions.
- Decision history: what was decided, why, and whether later evidence changed that decision.
Together, these views would give a more accurate picture than code state alone. That also the issue of temporal coupling. The system needs to distinguish a current decision from an older decision that has already been reversed.
Cut down the noise
The main coordinating agent should continue to drive the project. But, it should not receive the full execution history of every worker.
When it delegates a task, the worker should return a structured result containing:
- the outcome
- evidence that the task is complete
- relevant changes
- important decisions
- failures or remaining risks
- any new tasks discovered
The memory processes can then update their specialised records.
The main agent remains responsible for direction. The workers handle local execution. The memory layer preserves continuity.
Memory should remain queryable
Not every past detail needs to stay in the active context.
The main agent could keep a short description of each previous session and query the full session only when necessary.
This is closer to retrieval than recollection. The system does not carry its entire history at all times. It knows that the history exists and can retrieve the relevant part when needed.
The specialised memory agents could remain as persistent sessions. The main agent would query them when it needs their perspective.
This creates a form of organisational memory rather than one enormous prompt.
Embrace Agents as Shift Workers
Even the main coordinating agent will eventually accumulate too much context.
The system should therefore support deliberate handoffs. Before the active agent’s context becomes unreliable, it should produce a handoff containing:
- the current objective
- the project state
- completed tasks
- current tasks
- known failures
- important decisions
- open questions
- immediate next steps
- references to deeper memory
A new coordinating agent can then take over with a clean context.
This is similar to shift work. The next person does not need to relive every minute of the previous shift. They need an accurate handover and access to the underlying records. And to be honest we ourselves are not exactly the same person everyday. We carry over context, but it’s essentially a new session every morning.
That also brings the idea of memory consolidation when moving from a session to another. Which can resembles the processes that happen during sleep, like dreams for example.
The broader idea
Long-horizon agent performance could be more about creating a system that forgets intelligently. An efficient context compaction and handover mechanism that can keep consistently driving towards a goal.
The surrounding system, the harness, can turn a large, unusual task into a managed sequence of smaller, familiar tasks. It can preserve only the information needed to connect those tasks.
That may be the practical route to reliable, long-running agent systems: a coordinated set of short-lived workers, persistent memories and clean handoffs.
References
- Original article: Alex Zhang and Omar Khattab, Language model harnesses are compositional generalizers
- Related hypothesis: Alex Zhang, The Mismanaged Geniuses Hypothesis
- Referenced article: Alex Zhang’s original post on X