Introducing NAC, an Open-Source Harness for Long-Running Agent Work
15 min read • Aug 13, 2026
An open-source runtime built for complex engineering work. Nac coordinates parallel agent workers and persistent state across long tasks.
When implementing a feature, an agent can spend tens of thousands of tokens reading code, editing, debugging, editing further, until finally returning with a solution. By that time, it’s lost track of the finer details of what the user may have discussed in the early stages of the conversation. In extreme cases, this can even lead to the agent carrying out its task in a way that the user never initially intended, with important user-message context diluted as the session continues.
Most agent systems do not distinguish between different stages of work. The investigation, its tool output, its false starts, the evolving plan, and the state of the larger task all accumulate in one transcript. And this accumulation can even actively harmful: model performance itself degrades over long tasks, a failure mode now known as context rot.[1] On long-horizon tasks, where the work runs through many sequential steps, the agent’s context becomes a constraint, and when context fills up, compaction operations can throw away important detail.
We think this couples two things that should be separate:
- the temporary context needed to perform an action; and
- the persistent state needed to continue a workstream.
Nac is an open-source agent harness we built for ourselves around that separation and is available under Apache-2.0 at https://github.com/arcee-ai/nac. This blog explains the implementation, the ideas it draws from, and why agent harnesses are becoming a new kind of inference runtime.
Nac in action
Nac sessions can extend over many hours, sometimes even days - which isn't conducive to real-time video. Below is a timelapse from part of a nac session, working on generating and recording the the UI motion graphics for our launch video.
And here's the finished video:
What is nac?
Nac is an open-source agent harness that we built for ourselves for longer, more ambitious tasks. We use it internally for many different tasks: running experiments, supervising training runs, working on infrastructure, and rapidly prototyping new ideas. Many of these tasks are deeply intertwined — you may want to prototype an idea, evaluate it, integrate it into a different system, scale it up, use that feedback to refine the idea, and keep iterating from there.
Nac is built around a version of thread-and-episode architecture from Random Labs' Slate report [2]: a central orchestrator plans and decomposes work, and threads that are dispatched to complete a single work item. The threads return episodes, as structured summaries of the work they’ve accomplished, useful files, results, etc. Importantly, the orchestrator’s only action is launching threads; it cannot execute commands or edit files on its own. Nac makes this architecture concrete through a set of specific implementation choices.
Let’s walk through it, starting with the first thread the orchestrator creates. As part of the dispatch, the orchestrator specifies a concrete task and assigns it to a new thread. The orchestrator is prompted to keep the task bounded, but its scope is not enforced by the runtime. The dispatch then starts a worker, which is a fresh process and model context with the worker system prompt, the requested action, its tools, and any applicable project or skill instructions. There is no separate summarization pass: the worker system prompt instead specifies that the model’s final response should be a concise handoff for future work called an episode. The worker makes model calls and uses tools until the model returns a response with no tool calls, which is treated as the episode.
At this point, the worker’s execution context is discarded and never used as model context by the system again. Its changes to the environment remain, but the episode is the persistent representation of the work. It is stored in the thread, which is simply a named, ordered collection of episodes.
The next time the orchestrator assigns that thread a new task, nac creates a new worker with a fresh context. That worker receives the system prompt, the requested action, and all the episodes already stored in the thread. Furthermore, the orchestrator can supply episodes from other threads as context, an idea Slate describes as part of thread weaving. Nac implements this by resolving each named source thread to its most recent retained episode. Those source episodes are used as context for that action but do not become part of the target thread; only the episode produced by the new worker is added when the worker finishes.
Nac then proceeds through a series of alternating steps between orchestrator planning and thread execution. While planning, the orchestrator can query thread names and retained episodes at any time. When it chooses to dispatch work, it ends its turn by outputting a batch of thread calls, each with the following specification:
name— The target thread. NAC creates it if it is new or reuses its retained episode history if it already exists.action— The free-form instruction for the worker, intended to describe one bounded action.threads(optional) — Source threads whose latest retained episodes should be supplied to the worker. A same-batch source creates a dependency edge.skills(optional) — Skills to preload into the worker’s context.timeout(optional) — A time limit for the worker’s execution.
Implicitly, this defines a graph over the thread calls in the current batch. A source thread dispatched in that batch must execute its assigned work before the specified target thread; a previously completed source only supplies context. Nac rejects duplicate targets and validates that the graph is acyclic before execution begins. If it is not, nac rejects the batch and returns an error to the orchestrator.
Next, thread execution begins, utilizing the parallelism permitted by the DAG. Independent workers may run concurrently, but the orchestrator waits for the batch to complete before planning again. This gives each planning step a clear synchronization point and avoids requiring the orchestrator to poll background work. When the batch completes, the episodes from successfully completed threads and errors from failed threads are provided to the orchestrator (no additional query is needed); dependent thread calls whose same-batch sources failed are skipped. Worker failures are not transactional: if a worker changes the environment and then exits before committing its final response, those changes may remain without a new episode, so a returned error means the environment may have moved ahead of persistent history. This loop continues until the orchestrator decides to return a response to the user rather than create a new batch of threads. Finally, if the user sends a steering instruction while a run is active, nac queues it for the orchestrator’s next model call. It does not interrupt a model call or worker batch already in progress. After a run completes, the user can submit another prompt to continue the persisted session.
Why is the orchestrator-thread separation effective?
Nac’s orchestrator-thread specialization keeps the orchestrator focused on interpreting the user’s request, decomposing the work, and deciding what should happen next. It cannot act on the environment itself; execution must be delegated to threads.
orchestrator: decide and route, but do not actworkers: act, but do not expand the orchestration graphAs a concrete example, let’s say the user wants to optimize the performance of a specific part of a web application. A single agent would first have to understand the repository, set up the environment, and locate the specific hot path, reading through many files in the process. Only then could it begin profiling the hot path and identifying options—all while keeping in mind the user’s original intent from many messages earlier.
Nac’s orchestrator can instead dispatch threads to explore different parts of the codebase in parallel while another thread sets up the environment, accomplishing all of this in a single turn of orchestrator context. Their episodes give the orchestrator the important information it needs for the next step without including every execution detail, such as package-manager retries or timeouts that did not affect the result. The orchestrator can then assign profiling to another thread and receive the performance measurements and options it needs without working through the profiling process itself.
Two trends shaping agent harnesses
Agent harnesses have evolved along two related axes: enriching context so each model call receives a higher density of useful information and expanding the model's action space so it can initiate more capable operations.[3]
| Development | Context enrichment | Action-space expansion |
|---|---|---|
| Program execution | Returns filtered, aggregated, or exact results | Makes programs and loops available as compound actions |
| Memory and retrieval | Selects relevant prior state | — |
| Search and multi-agent systems | Selects and synthesizes information from multiple branches | Allocates inference across searches or workers |
| Recursive Language Models | Makes long context programmatically searchable | Adds transformations and recursive model calls |
| Fresh-session harnesses | Reconstructs context from files and handoffs | Repeatedly invokes specialized workers |
| Slate / nac | Routes persistent episodes into selected worker contexts | Dispatches whole workstreams and dependency graphs |
Tool use enabled the model to take actions in the first place, and to inject information about an environment into the model’s context.[4][5][6] Further program and code execution systems handed data processing operations — loops, filtering, aggregation, and exact execution — to ordinary runtimes, allowing the model to further enrich the information it receives, and further extending its action space.[7][8] Memory systems made retention and retrieval explicit responsibilities of the surrounding system, acting as context management and enrichment systems.[9][10][11] Search and multi-agent methods expanded this even further, and introduced a question of where inference compute should be spent to get the best results. [12][13][14][15]
Recursive Language Models make the trend especially clear: a long prompt lives in an external environment that the model can search, slice, and transform programmatically, including by invoking further model calls over selected pieces.[16][17] Other systems take a different path, invoking many fresh sessions over the course of a run. Anthropic's long-running harnesses[18][19], the Ralph loop[20], and Engram[21] carry progress through files and other external systems rather than one uninterrupted context. Coding agents do something similar whenever they preserve progress by editing the codebase itself. Cursor provides a prominent example: its planner-worker system coordinated hundreds of agents on long-running projects, including building a functional browser.[22]
In contrast to systems that move computation or persistent state outside a continuing context, compaction and subagents primarily relieve pressure within it.
Compaction straightforwardly targets context growth: it compresses a long trajectory to occupy a smaller amount of the context window by rewriting history. It is usually triggered by token pressure rather than task structure, and thus can overly compress or discard important pieces of information.
Subagents target context bloat: they keep excessive execution detail out of the main context by doing the work in a separate context and returning the final result. This also effectively increases the action space of the primary model, since it can take regular actions or a larger action via a subagent.
Slate’s architecture advances these trends in an opinionated way we found appealing. Routable episodes enrich each worker’s context with the state worth retaining, while thread dispatch gives the orchestrator a narrow but high-leverage action space. We built nac this way so progress can accumulate across long-running work without forcing its entire history through one growing transcript.
Harnesses are becoming inference runtimes
Seen from this perspective, harnesses are becoming inference runtimes: systems that turn model invocations, tools, and external state into larger stateful computations.
This is different from a model-serving inference engine, which executes and optimizes token generation. It is also more specific than a generic workflow engine, whose steps and transitions are normally specified in advance.
This view is part of a broader convergence around treating harnesses as runtime systems in their own right.[23][24][25]
An agent inference runtime constructs context, schedules inference, executes effects, preserves state, enforces capabilities, and defines how work synchronizes, fails, resumes, and stops. A thin harness executes a model-tool loop. A runtime owns semantics that would otherwise exist only implicitly in its transcript.
In nac, the mapping is concrete:
worker invocation = inference operationthread = persistent program stateepisode = committed workstream updatesource thread = data dependencydispatch batch = dynamic execution graphThe model remains the flexible intelligence that decides what work is useful. The runtime decides how those decisions become an operable computation. The split from the beginning, carried to its end: judgment stays in tokens, invariants live in the runtime.
Different runtime systems make different choices about how control is represented and what state survives. Onyx moves control the other way from nac: orchestration control flow becomes persisted, typed programs, shifting part of the decomposition itself from tokens into code.[26] LongHorizon-Harness differs on state: it advances one global, independently audited task record through serial manager, executor, and auditor rounds rather than maintaining multiple persistent workstreams.[27]
Once the harness decides where inference runs, what state it receives, what survives, how work synchronizes, and when execution ends, “harness” begins to understate the object. It is becoming a runtime.
When we reach for nac
Nac is built for work too large for one session but structured enough to advance through explicit handoffs. For a single focused change that fits in one coding-agent session, going direct is simpler and often faster. That adds overhead because the orchestrator cannot perform the task itself; it still has to delegate to a thread. Nac earns that overhead when the work can be divided into persistent workstreams.
A strong fit is a complex but decomposable task with well-separated parts and concrete acceptance criteria. In general, the following are good indicators:
- a meaningful high-level objective
- hard boundaries and safety constraints stated up front
- a concrete definition of done and acceptance criteria against which the work can be checked
- enough independent work to justify parallelism
- freedom for nac to decide its own internal decomposition
Examples include reproducing a machine learning paper toward specified results or porting a large codebase between languages while preserving its behavior.
Nac is useful in less structured patterns as well:
- A laundry list of isolated changes. Nac does not need to carry every detail at once or handle the changes sequentially, so it can manage their implementation and independent verification.
- Several long-running processes with user interaction between stages — for example, implementing features in a machine learning codebase, running experiments, and evaluating the results. Because each process retains its own episode history, we can move through other tasks and later return to the first without reconstructing its history from the rest of the session.
- Code review. Nac can decompose a review into smaller, more targeted reviews, synthesize their results, and even use a best-of-N pattern to review the same code multiple times.
- Large parallel code-changing jobs, for which we give nac a dedicated branch and worktree so its changes have an isolated place to land.
These patterns share more than length: each benefits from explicit boundaries between kinds of work while preserving continuity across them.
Nac as a tool for other agents
Nac ships with an MCP server that lets an agent such as Claude Code or Codex dispatch, monitor, and steer nac jobs as it would any other tool. This creates a pattern similar to Thinking Machines’ interaction model: a fast loop that stays with the human and a slow loop that executes heavier work asynchronously.[28]
The pattern we find most useful is to make the interactive agent a meta-orchestrator. It works with you in an ordinary session, and we instruct it to watch for the same signals we watch for: work that is decomposable, has a concrete definition of done, and forks into enough independent pieces to justify parallelism. When it sees that shape, it writes the job description itself, with a concrete objective and constraints, and hands the job to nac. The job runs in the background while the human-facing session continues.
What the meta-orchestrator can observe is deliberately shaped much like what the user can observe through nac. It can look through the orchestrator chat, it can retrieve thread episodes and recent thread events, and it can steer the orchestrator or specific threads. It can even choose different models for different sessions. Through nac’s MCP interface, the meta-orchestrator still cannot see a worker's discarded execution context or the underlying environment directly; the MCP server exposes no file or shell tools of its own. The outer interactive agent may still have its own independent environment and tools, of course. Session state must be queried; it is not automatically added to the meta-orchestrator’s context.
This pattern reflects our longer-term view of managed agents: not forever-running chats, but ongoing computations deployed and operated like production workloads that people can inspect, govern, and correct.
Try nac
Nac is available under Apache-2.0 at http://github.com/arcee-ai/nac
Install the current edge build:
curl -fsSL https://raw.githubusercontent.com/arcee-ai/nac/main/scripts/install.sh | sh- Read about our Open Model API Beta live now: arcee.ai/blog/open-model-api-beta
References
[1] Kelly Hong, Anton Troynikov, and Jeff Huber, “Context Rot: How Increasing Input Tokens Impacts LLM Performance”, Chroma Technical Report, July 2025.
[2] Random Labs, “Slate: moving beyond ReAct and RLM”, March 2026.
[3] Chenyu Zhou et al., “Externalization in LLM Agents: A Unified Review of Memory, Skills, Protocols and Harness Engineering”, 2026.
[4] Ehud Karpas et al., “MRKL Systems: A modular, neuro-symbolic architecture that combines large language models, external knowledge sources and discrete reasoning”, 2022.
[5] Shunyu Yao et al., “ReAct: Synergizing Reasoning and Acting in Language Models”, ICLR 2023.
[6] Timo Schick et al., “Toolformer: Language Models Can Teach Themselves to Use Tools”, NeurIPS 2023.
[7] Luyu Gao et al., “PAL: Program-aided Language Models”, ICML 2023.
[8] Xingyao Wang et al., “Executable Code Actions Elicit Better LLM Agents”, ICML 2024.
[9] Noah Shinn et al., “Reflexion: Language Agents with Verbal Reinforcement Learning”, NeurIPS 2023.
[10] Guanzhi Wang et al., “Voyager: An Open-Ended Embodied Agent with Large Language Models”, TMLR 2024.
[11] Charles Packer et al., “MemGPT: Towards LLMs as Operating Systems”, 2023.
[12] Shunyu Yao et al., “Tree of Thoughts: Deliberate Problem Solving with Large Language Models”, NeurIPS 2023.
[13] Qingyun Wu et al., “AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation”, 2023.
[14] Sehoon Kim et al., “An LLM Compiler for Parallel Function Calling”, ICML 2024.
[15] Adam Fourney et al., “Magentic-One: A Generalist Multi-Agent System for Solving Complex Tasks”, 2024.
[16] Alex L. Zhang, Tim Kraska, and Omar Khattab, “Recursive Language Models”, 2025, revised 2026.
[17] Seth Karten, Alex L. Zhang, Kevin Thomas, Sebastian Müller, and the Prime Intellect Team, “Prime Agent: A Self-Improving RLM Harness”, August 2026.
[18] Justin Young, “Effective harnesses for long-running agents”, Anthropic, November 2025.
[19] Prithvi Rajasekaran, “Harness design for long-running application development”, March 2026.
[20] Geoffrey Huntley, “Ralph Wiggum as a ‘software engineer’”, July 2025.
[21] Pantea Karimi et al., “Improving Coherence and Persistence in Agentic AI for System Optimization”, 2026.
[22] Wilson Lin, “Scaling long-running autonomous coding”, Cursor, January 2026.
[23] Lilian Weng, “Harness Engineering for Self-Improvement”, July 2026.
[24] Kai Mei et al., “AIOS: LLM Agent Operating System”, COLM 2025.
[25] Hailin Zhong and Shengxin Zhu, “AI Harness Engineering: A Runtime Substrate for Foundation-Model Software Agents”, 2026.
[26] Random Labs, “Designing a programmable runtime for agent orchestration”, July 2026.
[27] Ziyu Ma et al., “LongHorizon-Harness: Advancing Long-Horizon Agents for Real-World Tasks”, August 2026.
[28] Thinking Machines Lab, “Interaction Models: A Scalable Approach to Human-AI Collaboration”, May 2026.


