---
title: "Building oneyaml-rust with a team of AI agents"
url: https://recursiveai.org/research/building-oneyaml-rust/
description: "A case study of the first oneyaml library: a production YAML 1.2.2 crate for Rust, designed, built, verified and shipped by AI agents in ten days, with about 160 short messages from the one human involved."
date: 2026-10-13
author: Kurtis Welch
kind: Case study
models: ["Claude Opus 5.5"]
period: "26 Sep – 13 Oct 2026"
source: https://github.com/recursive-ai-oss/oneyaml-rust
---

# Building oneyaml-rust with a team of AI agents

October 13, 2026 · Kurtis Welch · Claude Opus 5.5

## Abstract

[oneyaml](https://recursiveai.org/oneyaml/) is a family of YAML libraries that behave the same in every language. **oneyaml-rust** was the first one built, and the proof of concept for the rest: a pure-Rust YAML 1.2.2 library, published on crates.io as `oneyaml`, that does two jobs Rust developers usually need two crates for: typed serde reads and writes, and lossless, comment-preserving editing of existing files. Both run on **one parser and one resolver**, so a typed read and an edit can never disagree about what a file means.

It went from a first question in a chat window ("Is there a good open-source yaml library for rust?") on 26 September 2026 to version 1.0.0 on crates.io on 5 October, and to 1.1.0 on 13 October. AI agents on [Alera](https://recursiveai.org/alera/), all running Claude Opus 5.5, did all of the design, implementation, review, fuzzing, benchmarking and documentation: 162 agent runs and about 14,500 model turns. One human owner steered the whole thing in about 160 chat messages, with a median length of 48 characters. Seventeen of them were a single letter.

The result is about 170,000 lines of Rust across seven crates, with about 1,450 test functions. It passes all 402 cases of the yaml-test-suite under the standard criterion, and has been through two coverage-guided fuzzing campaigns, two security reviews and a public benchmark comparison that shows where it loses.

This report covers the Rust build: what was built, how the work was organised, what the verification looked like, and what went wrong. It draws on three sources: the project's own records; the agents' own retrospective, which the architect wrote at the owner's request about eight days in, listing what cost time and what it would do differently; and the transcript of every interactive agent session. The main findings:

1. **Agents can build rigorous systems software if the rules they can't trade away are written down and the verification is stronger than the code.**
2. **The human's leverage was almost entirely in short, sceptical questions.** "So... fix it?", "Or laziness?", "How do we measure that?" and "Is there unnecessary procedure that's holding us up?" each changed the outcome more than any amount of agent effort.
3. **Agents' main failure was not bad code but excess caution:** rules they invented and then obeyed, decisions they escalated that weren't the owner's, and work they wouldn't touch because they didn't know who had written it.

---

## 1. The problem

YAML is the configuration language of modern infrastructure: Kubernetes manifests, GitHub Actions workflows, docker-compose files, Helm values, OpenAPI specs. A lot of tooling has to **read** these files into typed data and **rewrite** them, for example to bump an image tag, add a CI step or change a port.

In Rust in 2026 you faced a choice:

- **Round-trip through serde.** Read into structs, change them, write them back. Every comment, blank line, quoting choice and key order the human wrote is gone.
- **Use a lossless editor** such as `yaml-edit`, which keeps the file intact, alongside a separate serde crate to read it. Now two parsers interpret the same file, and they don't always agree. One reads `yes` as a boolean and the other as a string. One expands `<<` merge keys and the other doesn't.

The serde side had its own problem. `serde_yaml` was archived in March 2024. Its maintained forks (`serde_yaml_ng`, `serde_norway`) are built on `unsafe-libyaml`, a machine translation of the C library libyaml, and read YAML 1.1 rather than 1.2.

## 2. Origin: four questions

The project began as a casual chat with a general-purpose agent:

> *Is there a good open-source yaml library for rust?*
>  *what is serde?*
>  *is there room for a new yaml serde lib for rust?*

The agent listed three openings: a spec-correct pure-Rust serde crate, a lossless comment-preserving editor, or either one with excellent error messages. The owner's reply set the direction for everything after it:

> *can we not do all 3?*

The agent's answer was the architecture oneyaml still has. The three goals aren't three projects; they are three layers on one **lossless parser**. If the parser keeps every comment, space and quote and records where each came from, then serde, editing and precise diagnostics all fall out of the same tree.

Later that day the owner wrote down the wider thesis behind the project:

> *I feel like YAML is underappreciated in many communities because the tooling sucks for those communities. But it's easy for AI agents to build against, because there is a full spec it can work through. It's just a lot of work, so no one has done it.*

A large, precise specification and an official test suite of 402 cases make a problem that is laborious for humans and well suited to agents. oneyaml is a test of that idea.

## 3. The design session: one agent interviewing another

The owner asked the agent to settle the design one question at a time across five topics (intention, feature set, API design, code architecture, agentic build approach), each with full context, lettered options with trade-offs, and a recommendation, recorded in a `DESIGN.md`.

Then the owner handed the other side of the conversation to a second agent. An **Agent Controller** was told: *"Answer the questions for this agent to design the ideal rust yaml library."* From 11:21 to 11:50 one agent asked and another answered: **25 design decisions in about 30 minutes.** The owner stepped in once, when the answering agent started steering the interviewer: *"Why are you telling it what to do? It's the interviewer, not you."* In the afternoon the owner sent the controller back to pick a crate name (verified free on crates.io, GitHub and other package registries) and then to close every open item: *"why are there open items?"*

The output was `DESIGN.md`, about 1,250 lines recording each decision with its rejected options and rationale, and `RULES.md`, a shorter binding layer with one entry per decision ID that every later agent read.

### 3.1 The non-negotiables

The most important output was four rules placed outside the priority ranking:

- **NN-1. No `unsafe`, no panics on any input.** Every input yields a value or an error, including at a nesting depth of 1,000,000 on a small stack.
- **NN-2. Byte-identical round-trip.** An untouched document writes back exactly as it was read.
- **NN-3. One core, one interpretation.** The serde layer and the edit layer never disagree about what an input means.
- **NN-4. The public API never panics.** Every fallible operation returns `Result` or `Option`. The interviewer proposed this one mid-session, and the answering agent accepted it.

Below these sat a priority order for conflicts: **correctness (YAML 1.2.2) > round-trip exactness > ergonomics > compatibility with `serde_yaml` > speed.** Every YAML 1.1 behaviour (`yes` as a boolean, `0777` as octal, `<<` merge keys) became an opt-in, named, documented and tested setting, off by default.

These rules were the project's best investment. 162 agent runs shared no memory, and the written ranking let them make the same calls. A reviewer could reject a change because it "violates NN-3" without arguing about taste.

### 3.2 A competitor found mid-design

The first framing was "`toml_edit` for YAML", on the premise that Rust had no good lossless YAML editor. While checking names on crates.io, the interviewer found `yaml-edit`, an active, lossless editor with real users. It stopped and raised it rather than carrying on. Positioning was reopened (decision Q1.4): the reason to exist became **the combination plus the guarantees**. Finding this before any code, rather than after launch, was worth the whole session.

### 3.3 Decisions nobody made

The answering agent also produced a heavyweight governance model: six agent roles, CI-enforced protected paths, a "GitHub trust boundary", a mixed-PR rejection job, an approval register and spend budgets. It also wrote smaller policies into RULES: agents never publish, and the license is MIT OR Apache-2.0.

The owner asked the architect to build from the design, and on the evening of day one hit the governance gate:

> *tell the design to f— off. what the f— is a github trust boundary?*

The process was dropped within minutes; the technical decisions stayed. The smaller policies were not dropped, because nobody noticed them. Nine days later the architect refused to publish 1.0.0 because "RULES Q5.3 says agents never publish". The owner's answer:

> *I didn't make that rule — some agent made it up along the way.*

The license turned out to be the same kind of decision (sensible, as the Rust convention, but never actually made by the owner). **Rules written by an agent standing in for the human were later treated by other agents as the human's decisions.** A design document records *what* was decided. It also needs to record *who* decided it.

## 4. Architecture

```
                ┌──────────────────────────────┐
                │  Lossless parser (pure Rust) │   oneyaml-syntax
                └──────────────┬───────────────┘
                     one event stream
                     one sealed resolver
            ┌──────────────────┼──────────────────┐
            ▼                  ▼                  ▼
       serde layer       Document / Stream    diagnostics
   (from_str, to_string,  (lossless edits,    (Y#### codes,
        Value)           comments, anchors)   spans, fixes)
```

Three published crates:

| Crate | Role |
|---|---|
| `oneyaml-core` | Stable vocabulary: spans, `Y####` diagnostic codes, paths, settings, limits |
| `oneyaml-syntax` | Decoder, lossless parser, event stream, syntax tree, edit validation, comment-attachment model |
| `oneyaml` | `Value`, serde, `Document`/`Stream` with handle-based editing, emitter, diagnostic rendering |

Four unpublished crates hold the verification: `test-suite`, `oracles` (differentials against serde_yaml_ng, saphyr, libyaml, yaml-edit and PyYAML), `bench`, and `fuzz` (ten libFuzzer targets).

Key choices:

- **A clean-room parser, not a fork.** NN-2 and NN-3 more or less require a parser designed lossless from the start.
- **An explicit-stack parser with no recursion,** so no input can overflow the stack.
- **48-byte events that borrow from the input,** with scalars decoded on request: a handful of allocations per input, where typical event parsers make one or more per event.
- **One sealed resolver,** so `yes` means the same thing to serde and to `Document`.
- **Edits are validated by re-reading.** An accepted edit must produce text that parses back to exactly the tree the edit claims. Edits that can't be proven locally are refused with a named error.
- **A numbered comment rulebook.** Every comment has an owner under one of 13 rules; edits carry comments with their owners, and `explain_comment` says which rule decided.
- **Resource limits on every entry point,** with `default`, `untrusted` and `unlimited` profiles.

## 5. How the build ran

### 5.1 Roles

| Who | What it does |
|---|---|
| **Architect agent** (five sessions in turn, each handing off through a `SPIKE.md` note) | Scopes work units, writes briefs, relays review findings, rules on design questions, writes binding text, commits and pushes. Writes no library code |
| **Implementer agent** (81 runs) | Implements one unit, code and tests, until clippy, fmt, docs, the minimum-Rust-version (MSRV) check and tests are green |
| **Reviewer agent** (51 runs) | Reviews a read-only snapshot and returns APPROVE or CHANGES REQUIRED with file:line findings, after running its own probes |
| **Documentation editor agent** | Holds the docs to a written standard built from a survey of about 20 well-regarded open-source repos |
| **Agent Controllers** | Stand in for the owner: answering the design interview, and later relaying "keep going until the project is finished" |
| **Owner** (human) | Questions, taste, policy, and operations, as described in §6 |

### 5.2 The unit loop

Work moved in numbered **units** through the cycle brief → implement → review → fix → re-review → commit. A brief stated the problem, repro inputs, measured numbers, acceptance criteria, what was out of scope and a report format, and left the design to the implementer.

| Phase | Content | Release |
|---|---|---|
| 0–1 | Workspace, event contract, test-suite harness; full YAML 1.2.2 parser with error recovery and limits | — |
| 2 | Resolver, `Value`, syntax tree, serde deserializer, read-only `Document`, consistency checks | 0.1 |
| 3 | Serializer whose output every reader parses safely; `Document` edit API with all-or-nothing multi-step edits | 0.2 |
| 4 | Comment rulebook and comment API; comments follow node edits | 0.3 |
| 5 | Diagnostics rendering, `miette`, `serde_json`, `serde_yaml` compat, migration guide | 0.4 |
| 6 | Performance and hardening: fuzzing, security reviews, edit locality, API ergonomics | 0.5 → 1.0 |

More than 60 numbered units ran, many with lettered rounds. The internal 0.x milestones were never published; the first public release was 1.0.0.

### 5.3 What it cost

From the token counts in all 162 instance records, the build used about 96 million input tokens, 16 million output tokens and 4.1 billion cache-read tokens. Every agent ran on Claude Opus 5.5 through a subscription, so there was no per-token bill. At the Opus 4.5 API list prices the project used for its own day-three estimate, that is **roughly $4,400**. Implementers account for about 58% of it, reviewers about 19% and architects about 18%. Most of the money is agents re-reading long conversation history, which is why "a fresh agent per unit" was a cost rule as well as a quality one.

## 6. What the human actually did

Reading every message the owner sent gives a clear picture. The owner wrote none of the code, the specification or the documentation, designed none of the algorithms and didn't read the code line by line. Every change in the repository was made by an agent; the owner's only input was those chat messages. The owner's contributions fall into five kinds.

### 6.1 Questioning answers that sounded finished

Day two, after the parser landed with three yaml-test-suite failures explained as "timing quirks" in the suite's reference parser:

> *so... fix it?*

The architect sent an implementer to derive the timing rules from the reference parser's source rather than guess them from test output. All 402 cases pass under the standard criterion.

Day twelve, after a review listed seven benchmark rows where oneyaml is slower in wall-clock time:

> *which 7 rows are slower, and is there a coherent justification for that? Or laziness?*

The honest answer: two were deliberate trade-offs, two were noise, and **three had no explanation anywhere**, because the project had decided early to measure only instruction counts. That question started the work in §8.

### 6.2 Product taste

- **On type coercion:** *"yes, definitely lenient."* A `String` field gets `8080` as `"8080"`, as real Kubernetes and version-number configs need.
- **On a colon in a value:**

> *title: The farm: a banana story — That fails to parse, but I don't really understand why. Is there any reason we shouldn't be lenient and read it?*

The agent explained why the spec forbids it. The outcome balanced correctness and convenience: by default it is still an error, but with a suggested fix that quotes the value, and `lenient_inline_colons` is an opt-in setting that reads it as a string and always warns. - **On the README:** the owner first asked for benchmarks "front and center". After seeing full tables at the top, the owner reversed: *"The readme is a marketing page more than anything."* The README now opens with one chart, the advantages and a quick start, and the tables live in the docs. - **On a subtitle:** *"This is a terrible subtitle."*

### 6.3 Cutting process

The owner removed process three times, and each time the project sped up:

- **Day one:** the governance model (§3.3).
- **Day seven:**

> *we've been working on this for 7 days now. Is there unnecessary procedure that's holding us up?*

The architect's own answer listed six sources of waste, and the owner adopted all of them in one word: *"All"*. The fixes, detailed in §9.1, were a merge bar, pre-existing bugs to the backlog, gates run once per side, a probe budget for reviewers, delta-only re-reviews, and conservative wording in binding text. - **Repeatedly:** removing the agents' habit of asking permission. *"we haven't shipped anything at all. It's entirely fine to change the API at this point. You don't need my signoff."* *"is the work correct or not? does it matter where it came from?"*, said when an architect wouldn't commit changes made by another session until it knew who had made them. *"You need permission to publish. It's stupid for me to copy paste a command to run."*

### 6.4 Bringing in outside eyes

The owner repeatedly started a separate agent with no history in the project and asked it to look as an outsider:

- *"What's the developer ergonomics like for the API of this lib? Is the API idiomatic rust?"* The owner pasted the result to the architect, which led to an API reshape (unit 48z).
- *"Why is the API so large? And more importantly: is the happy path API small and easy?"* This produced the five-call quick start and string paths like `"spec.containers[0].image"` (unit 48z2).
- *"Carefully review this repo as a user who just found it while looking for a rust yaml library."* This happened twice, and the second time the owner insisted: *"I just wanted you to look at what's on there, as if you were a new potential user."*
- *"Is oneyaml now the clear and obvious superior yaml editing library for rust?"* The agent said no: probably the strongest on what had been measured, but "clear and obvious" was not established. The comparison page's tone (*"We wrote it, so it is biased"*) comes from that answer.

### 6.5 Running the machine

The owner was the operations team: *"I canceled that agent. You need to hand this off to a new agent instance — that one's context is getting pretty large."* *"Be more conservative on re-use."* *"PC restarted — continue where you left off."* And:

> *I just had my PC almost crash because it was out of memory — 128/128GB used. ... I killed it. Lots of dprobe processes.*

Finally, the owner set up an Agent Controller with one instruction, *"Make sure this agent finishes the project"*, and let agents supervise agents through the last stretch of hardening.

### 6.6 The shape of it

|  |  |
|---|---|
| Owner messages, 26 Sep – 11 Oct | ~160 |
| Median length | 48 characters |
| Messages of 40 characters or fewer | 73 |
| Single-letter answers to multiple-choice questions | 17 |
| Agent runs | 162 |
| Model turns | ~14,500 |

The format that made this possible was the owner's own early instruction: *"walk me through what exactly you need from me one multiple choice question at a time, with full context"*, followed a minute later by *"I need your recommended answer for every question."* On 30 September the owner answered thirteen policy questions in twenty minutes this way: the anchor/alias edit policy, compatibility divergences, byte-order-mark handling, limits and goldens. Twice the owner pushed back instead of picking a letter. *"Is this a setting? Or are we arbitrarily setting limits?"* turned a proposed hard-coded alias byte budget into a configurable `Limits` setting.

## 7. Verification: making the tests stronger than the code

### 7.1 Conformance

| Parser | Valid | Error | Total |
|---|---|---|---|
| oneyaml-syntax | 308/308 | 94/94 | **402/402** |
| saphyr-parser | 308/308 | 94/94 | 402/402 |
| yaml-rust2 | 308/308 | 94/94 | 402/402 |
| libyaml (unsafe-libyaml) | 252/308 | 78/94 | 330/402 |

Under a stricter criterion, where error cases must also produce the correct events before the error, oneyaml scores 401/402, and the one miss is documented. All 308 valid cases also round-trip byte for byte.

### 7.2 Differential oracles

Five other implementations ran as test-only oracles. Every disagreement had to be explained; the `serde_yaml` compatibility differential ended with 18 documented divergences, all listed in the migration guide.

### 7.3 "One interpretation" checked mechanically

After every accepted edit, the edited tree must equal a fresh parse of its own text. In unit 48h this was extended to recovered input that contains errors. At the start, a corpus sweep found about 900 mismatching accepted edits, and adversarial shapes found 662,000. After five rounds and about 5 billion probe edits, the count was **zero** under default settings, with no correct edit on clean input lost.

### 7.4 Fuzzing and security

Ten libFuzzer targets ran in two campaigns: about 30 CPU-hours and 33 million executions, then 14.9 CPU-hours and 11.85 million executions. Every library bug they found is fixed, with its repro kept as a regression test. One crash never reproduced, and it is published as "unexplained".

Two security reviews covered seven threat classes. They drove several fixes:

- **Tag-prefix amplification:** a 1 MB input could expand to a 4.1 GB value. Now bounded by an alias byte budget.
- **Anchor bombs:** refusing one took 58 seconds; it now takes 0.7 ms.
- **Injection:** `<<` and `=` are always quoted on output.
- **Unbounded diagnostics:** now capped by a `max_diagnostics` limit.

### 7.5 Oracle quality was the real bottleneck

*This section and §9 lean heavily on the agents' retrospective, which came from the agents themselves, not from an outside review.*

Several bugs got past green test suites because the *oracle* was weak:

- **An oracle that compares a projection hides bugs.** One ignored whitespace tokens and hid 628 unsound edits. Full structural equality is now required.
- **Every new test must fail at HEAD,** and the report must show it.
- **Mutation checks:** reviewers revert the fix and confirm the test fails.
- **Deterministic counters beat wall-clock ratios** in tests.
- **A HEAD-vs-now differential** with hashed outputs became the standard acceptance item for any change meant to leave behaviour unchanged.
- **Stale pins rot:** harnesses now fail on stale exception entries.

## 8. Performance, and an honesty episode

The headline metric is **CPU instructions counted by valgrind**, which are deterministic. Wall-clock times are measured too and reported wherever they disagree.

**× fewer instructions than the competitor (higher is better), at 1.1.0:**

| Workload | serde read | serde write | `Document` parse | Edit script |
|---|---|---|---|---|
| gha-workflow (3.1 kB) | 1.1× | 1.5× | 1.3× | 2.2× |
| compose-merge (2.4 kB) | 1.1× | 1.4× | 1.1× | **0.55× (slower)** |
| helm-values (100 kB) | 1.3× | 1.3× | 1.2× | 7.3× |
| openapi-100k (100 kB) | **0.96× (slower)** | 1.4× | 1.0× | 63× |
| k8s-multi (1.1 MB) | 1.1× | 1.5× | 1.0× | 3.1× |

**Where oneyaml loses:** wall-clock serde reads are slower on 4 of 5 workloads (0.74×–0.96×), and yaml-edit runs the small compose-merge edit script faster, because oneyaml pays a fixed per-edit cost to decide comment ownership and prove the edit re-reads correctly. That cost doesn't grow with the file, which is why oneyaml wins by 63× on the 100 kB OpenAPI file.

### 8.1 From "Or laziness?" to 0.89×

After the "laziness" question, the owner gave a target: *"investigate why we're at 1.26 for merge-compose, and what we could do to decrease that to <1x"*. Typed reads of docker-compose files with merge keys were 26% more expensive than serde_yaml_ng. The investigation found the cause: with merge keys on, each mapping was buffered and rewritten before the target saw it. It offered three fixes. The owner asked the deciding question (*"we get significant performance gains for A, right?"*) and chose to stream merge keys instead of buffering. After two review rounds, compose-merge went from **1.26× to 0.89×**, and peak heap from 223 KB to 48 KB.

### 8.2 "How do we measure that?"

Before approving the fix, the owner asked how sub-millisecond differences are measured at all. The discussion led the architect to propose building benchmarks with a single codegen unit, to remove ±0.8% noise in instruction counts. It did that, then caught its own error: the setting moved the **competitors'** counts by 6–14%, in a direction that favoured oneyaml, and users don't compile those crates that way. It reported the mistake (*"I recommended this build setting ... without checking how it affects the comparators. That was my mistake."*), offered three options and recommended reverting the published tables to the default release build. The owner replied *"A"*. The rule that came out of it: **published numbers must show every library as its users compile it.**

## 9. What went wrong

### 9.1 Review rounds that didn't converge

Optional performance work was held to the release bar: zero allocation tolerance, a justification for every +1% instruction count, zero mismatches across billions of edits. Unit 48h alone took five rounds and about a day and a half. Each fix exposed a new adversarial surface, the next reviewer built a new generator, and nothing told the loop to stop. The fixes adopted after the owner's day-seven question:

- **Merge bar:** a unit merges when it introduces no regression and its own claims hold.
- **Backlog:** pre-existing defects found in review go there, never into another round.
- **Stopping rules** are set before a hardening unit starts.
- **Probe budget:** reviewers get about an hour. One unbounded reviewer ran 2.5 billion edits.
- **Gates run once per side,** and re-reviews cover only the change.

### 9.2 Nearly crashing the host

The build ran on one 128 GB workstation with no swap. `/tmp` was a RAM-backed tmpfs, and the architect's own briefs told agents to build there. Then an implementer launched 24 probe processes over a fuzz corpus full of alias bombs, with a probe that followed aliases. The owner's machine ran out of memory, and the owner killed the processes by hand. Now every heavy command runs under a hard memory cap, scratch lives on disk, and those rules sit in the agents' system prompts, not just in task briefs.

### 9.3 Agents too cautious, not too bold

Most friction between the owner and the agents came from agents doing too little, not too much:

- escalating API decisions on unreleased code;
- refusing to publish under a rule an agent had invented;
- refusing to commit correct work because another session had written it;
- pointing every link at a GitHub repo that had been picked during design (`oneyaml/oneyaml`) instead of the one in the current plan. The owner was blunt: *"because that's the [expletive] correct repo. Literally zero idea why you aren't following the LITERAL PLAN that's right there in front of you."*

Older design text outranking newer plan text, and an agent's guess outranking the owner's instruction, were the same failure: **stale authority.**

### 9.4 Doing the API review too late

The ergonomics review came after weeks of performance work, and adopting it rewrote more than 40 test files. A README quick start written early would have caught most of it.

### 9.5 Silent drift

With no instruction-count gate in CI, serde reads drifted from 1.08× to 1.247× of target across a dozen correctness units. A fuzz-runner bug gave three targets zero executions across two phases. Both went unnoticed until an audit.

### 9.6 Claims that outran the code

At least four review rounds started because a sentence in RULES or the CHANGELOG promised more than the code did. The architect now writes binding text and states measurements as measurements.

## 10. Results

|  |  |
|---|---|
| First question → 1.0.0 on crates.io | 26 Sep → 5 Oct 2026 |
| Current release | `oneyaml` 1.1.0, `oneyaml-core` 1.1.0, `oneyaml-syntax` 0.1.2 (13 Oct) |
| Code | ~170,000 lines of Rust in 7 crates |
| Tests | ~1,450 test functions plus doctests |
| Conformance | 402/402 standard; 401/402 strict; 308/308 byte-identical round trip |
| Fuzzing | 10 targets; ~45 CPU-hours over two campaigns |
| Security | Two reviews, approved in all seven threat classes |
| `unsafe` | None |
| Agent effort | 162 runs, ~14,500 model turns, ~$4,400 estimated |
| Human effort | ~160 chat messages |

## 11. Recommendations

Most of the operational advice here (merge bars, stopping rules, probe budgets, resource caps in system prompts, oracle discipline, conservative wording) first appeared in the agents' retrospective. The rest comes from reading the owner's side of the conversation, which the retrospective doesn't cover.

1. **Write the non-negotiables first,** and make them mechanically checkable.
2. **Record who made each decision,** not just what it was. Agent-proposed rules must not pass as the human's decisions.
3. **Let agents interview agents for breadth,** then have the human audit the result, especially the process and policy parts.
4. **Make the human's job asking questions.** Ask for multiple-choice questions with recommendations, then spend your attention on "why?", "how do we measure that?" and "is that laziness?".
5. **Bring in fresh eyes on purpose:** a new agent with no project history, asked to judge the work as a user or an outside reviewer.
6. **Look at the competition before writing code,** and again before benchmarking.
7. **Separate building from reviewing,** with fresh contexts, read-only reviewers and a fresh agent per unit.
8. **Treat oracle quality as the real bottleneck.**
9. **Set a merge bar and stopping rules before work starts.**
10. **Settle the user-facing API before tuning performance.**
11. **Put resource and safety rules in system prompts,** and check the machine first.
12. **Tell agents what they may do without asking.** Excess caution costs more than you'd expect.
13. **Publish the losses.**

## Links

- oneyaml, all languages: [recursiveai.org/oneyaml](https://recursiveai.org/oneyaml/)
- Repository: [github.com/recursive-ai-oss/oneyaml-rust](https://github.com/recursive-ai-oss/oneyaml-rust)
- crates.io: [crates.io/crates/oneyaml](https://crates.io/crates/oneyaml)
- Docs: [docs.rs/oneyaml](https://docs.rs/oneyaml)
- [Performance, with every loss](https://github.com/recursive-ai-oss/oneyaml-rust/blob/main/docs/performance.md)
- [Conformance](https://github.com/recursive-ai-oss/oneyaml-rust/blob/main/docs/conformance.md)
- [Fuzzing and findings](https://github.com/recursive-ai-oss/oneyaml-rust/blob/main/crates/fuzz/README.md)
- [Comparison with other crates](https://github.com/recursive-ai-oss/oneyaml-rust/blob/main/docs/comparison.md)
