Multi-Agent Methods for Long-Horizon Autonomous Engineering
Long-horizon software work fails when goals drift, progress cannot be checked, and failures cannot be rolled back. This article describes a multi-agent setup built around a task graph, separated roles, an artifact repository, a verification ladder, and hard budgets, then applies the same discipline to bootable systems, formalization, language migration, and cross-domain work.
Complex software is no longer “delivered” when a single function compiles. Kernels and drivers, persistence, networking, graphical interfaces, and install and upgrade paths each depend on invariants from the layer below. The same is true of mathematical formalization, language migration, and hardware co-design. Handing this work to coding agents is not mainly a problem of how fluent a single completion is. The hard part is keeping the goal stable over a long span of time, keeping evidence reviewable, and making failures reversible.
Why Long-Horizon Tasks Fail
Short tasks have a tight feedback loop: change a few lines, run tests, read the error. Long-horizon engineering is the opposite. Intermediate state is large, and errors propagate across modules. Common failure modes fall into four groups.
First, goal dilution. The initial prompt only says “a system that boots” or “move the service to a safer language.” Later agents loosen constraints to raise a local pass rate, and the result is a demo that cannot be maintained.
Second, false progress. Logs are full of “done,” but there is no executable acceptance check. The UI can be drawn, yet the disk image will not boot. A proof script compiles, while a key lemma is still a placeholder.
Third, coordination tax. Hundreds or thousands of workers without a shared task graph reimplement the same subsystem, or edit the same file in parallel before the interface is frozen. Merge conflicts become the main cost.
Fourth, uncontrolled self-improvement. If a model may freely rewrite its own toolchain, evaluation set, and permission policy while running, short-term metrics can improve while behavioral boundaries stop being auditable. A responsible split is to separate “improve the solution to the task” from “improve the agent’s own capabilities and permissions.” The latter stays off by default, or is limited to a baseline that a person has published.
Treat the Cluster as an Operating System, Not a Chat Window
A runnable multi-agent system needs at least five layers. Each layer is an ordinary engineering object, not an unexplained “black-box collaboration.”
Task graph. Break the goal into nodes with dependencies: specification, interface contract, implementation, tests, integration, and release. A node is only “not started,” “in progress,” “awaiting verification,” “accepted,” or “abandoned.” Do not replace that state machine with a natural-language “mostly done.”
Role separation. A planner changes only the task graph and acceptance criteria. An implementer submits patches only inside authorized directories. A verifier runs the prescribed checks and does not edit product code directly. A coordinator handles locks, retries, and escalation to a person. The same class of model instance can play all four roles, but the permissions must differ. One identity that can do everything is an abandoned responsibility boundary.
Artifact repository. Intermediate results go into version control: design notes, interface definitions, test vectors, build logs, and failure samples. Chat transcripts are not the source of truth. Reproducible commits are.
Verification ladder. From cheap to expensive: static checks, unit tests, integration tests, property tests, end-to-end scenarios, and human sampling. Every failure at every level must produce evidence that can be located, not a request to “try again.”
Budgets and circuit breakers. Set hard caps on tokens, duration, concurrency, and external calls. If progress does not improve inside a defined window, shrink the problem or hand it back to a person. Do not add agents without limit.
A task node does not need to bind to any vendor API. An ordinary data structure is enough:
id: fs-journal-crashdepends_on: [block-device-contract]accept_if:- replay_after_power_loss == byte_identical- no_unchecked_alloc_in_irq_pathowner_role: implementerverifier: integration-suite-03budget: {steps: 40, wall_clock: 2h}
From an Empty Directory to a Bootable System: A Stress Test, Not a Myth
“Produce a system that boots on a laptop, starting from an empty folder” is a useful capability probe. It presses planning, low-level programming, driver timing, and integration at once. Written as a repeatable exercise, it should fix the boundaries rather than chase rumored day counts or agent counts.
A practical milestone order is: a repeatable build and cross-compile; minimal boot and serial logging; memory and interrupts; a block device and a read-only filesystem; a journal that can recover from a crash; a minimal subset of a network stack; a minimal window or framebuffer; install media and checksums. Each step needs a machine check that stops on failure. Drivers and boot paths involve hardware timing. Agents may draft them, but on-device validation must be done by someone who has the hardware and a safe isolation setup. “The simulator passed” is not “a physical machine was delivered.”
Humans not writing every line does not mean humans are not responsible. The owner freezes the threat model: no outbound network by default, no privilege escalation, and no access to production secrets. They review the boot chain and update signatures, and they keep a one-step rollback to the last known image. Otherwise “autonomous” only makes the cause of an incident harder to trace.
Evidence Before Narrative: Formalization and Language Migration
Turning a written proof into formal text that a machine can check line by line is tedious, but it is measurable. The effective method is not to pile on more executors. It is to list intermediate lemmas, pin library versions, forbid undeclared axioms, and let an independent checker make the final decision. Collaboration can be “claim lemmas, and on conflict the checker output wins.” If progress stays at the same percentage for a long time, stop adding concurrency. Split the stuck lemma, or admit that the premises are insufficient. When comparing model generations, compare pass rates only under the same prompt, the same checker, and the same budget. Do not treat a demo’s progress as a theorem.
Moving a service from a dynamic language to a systems language that emphasizes ownership and concurrency safety follows the same evidence ladder. First lock external behavior with characterization tests, then replace the internal implementation, and only then talk about startup time or memory. A speedup must be measured under the same load, the same hardware, and a stated warmup rule. A single internal run cannot be generalized into a universal multiplier. Planning, coding, review, and commit can be chained by agents, but merge rights should be bound to code owners and automated gates: a red test must not merge, and a generated commit message must match the real diff.
Keep the Same Discipline Across Domains
Mathematics, numerical physics, bioinformatics, and hardware description differ in the acceptor, not in “being more intelligent.” For physics or numerical work, publish the equations, the discretization, the mesh, and the conserved quantities. If a computation does not finish, report the residual and the range of validity. Do not package an unfinished derivation as a discovery. Where experiments and devices are involved, agents produce designs and simulation plans only. Hazardous operations and real hardware stay outside the autonomous loop.
Cluster size is not capability by itself. Thousand-way concurrency pays off only when the task graph can be split, verifiers are cheap, and write conflicts are rare. On tightly coupled kernel paths, ten implementers with locks often beat a thousand writers that do not wait for each other. A common industry pattern is a shared read-only specification, write paths sharded by subsystem, and integration serialized by a small number of coordinators.
Cost, Speed, and Safety Switches
Faster generation and longer context increase how fast errors spread. Engineering should watch three things together: cost per accepted commit (a patch that passes acceptance, not characters generated), the number of human interventions, and the number of rollbacks. A faster tier is a throughput option, not a quality option. Critical paths still take the full verification ladder. Billing for input and output should follow the actual invoice and contract, not rumor prices written into an architecture decision.
Self-improvement should be graded. What is allowed: adjust prompts, retrieval, and task splits against a fixed evaluation set. What is not allowed: rewrite safety policy at runtime, widen tool permissions, disable tests, or delete failure samples from the evaluation set. If recursive self-improvement is locked to an already published baseline during training or deployment, that trades a capability ceiling for predictability. That is a safety design, not a missing feature.
A Checklist Before Going Live
Before launch, confirm that the goal can be rejected automatically; that each role has minimal write permission; that secrets and production environments are unreachable; that every accepted state corresponds to checker output; that budget circuit breakers have been rehearsed; that a person can reject any commit; and that logs are kept long enough for a postmortem. A claim that more than nine in ten commits come from agents is meaningful only when gates and audit are automated to the same degree. Otherwise it only postpones review debt until after an incident.
The value of long-horizon autonomous engineering is to move tedious, checkable, clearly bounded work off a person’s calendar. It is not a substitute for specification, responsibility, or the last confirmation in the physical world. Make the task graph and the evidence solid first. Talk about cluster scale after that, or the system will drift while it only looks busy.
