Cold open
Looks right. Reads right. Wrong later.
Coding agents don't fail by writing garbage you'd spot. They fail by shipping something plausible that breaks in production — in front of a user.
✓looks right
✓reads right
✗is wrong — later
I do nearly all of my agent coding in Rust. On purpose.
agents lie. the compiler doesn't.02 / 34
Built this way since February.
205
dated plan documents in docs/plans. First one, 13 Feb
618
merged PRs. Most of them agent-authored, all human-merged
1
production SaaS · teamcadence.ai
▸Every example in this talk is a real file from that repo. Nothing staged, nothing toy.
agents lie. the compiler doesn't.03 / 34
CHAPTER I
Declare before use
🦀agents lie. the compiler doesn't.04 / 34
concept 01the agent loop
An agent is a loop, not an oracle.
propose
writes the next change
→→observe
reads what came back
↺repeat
with updated context
▸The model only knows what its tools show it. Everything in this talk is about shaping what flows back through this loop.
agents lie. the compiler doesn't.05 / 34
concept 02backpressure
Backpressure.
Everything that can push back on a generated change before it reaches main.
▸Agent quality tracks the backpressure around it more than the model inside it. And languages differ wildly in how much you get for free. That difference is this talk.
a generated change
▼◂rustctype errors, sub-second
◂clippylints, on deny
◂testsbehaviour
◂CIsame script, -D warnings
◂a second modelintent
◂youjudgement
▼main
agents lie. the compiler doesn't.06 / 34
concept 03the working loop
Plan. Implement. Verify. Ship.
plan
decide exactly what changes
→implement
small steps, fast checks
→verify
prove it, don't trust it
→ship
commit, push, watch CI
concept 04 · seamA plan around a single commit. The unit this loop runs on. Small enough to review, small enough to undo.
▸This map is the rest of the talk. Each chapter lights up part of it.
agents lie. the compiler doesn't.07 / 34
The plan is the ceiling.
Whatever ambiguity survives planning becomes a decision the agent makes alone, mid-session, at speed. Bulletproof means unambiguous, clear and directed. Boring, even.
PRD / spec→the what and the why, before any code
review the plan→harder than you'd review the code
checklist of seams→work cut into single commits, stable IDs
↺how plans get bulletproof is the last chapter. hold the thought.
agents lie. the compiler doesn't.08 / 34
CHAPTER II
The compiler can't be bluffed
🦀agents lie. the compiler doesn't.09 / 34
Backpressure, instantiated
Confidence vs. a type checker.
agent writes
a plausible call
→cargo check
under a second
→rustc error
specific · located
↺pastes it back
until it compiles
cargo check · what the agent reads backrustc
error[E0599]: no method named `find_by_org` found for struct `UserRepo`
--> crates/db/src/users.rs:142:31
|
142 | let users = repo.find_by_org(org_id).await?;
| ^^^^^^^^^^^ method not found in `UserRepo`
help: there is a method `list_for_org` with a similar name▸Not just no — the line, the type it expected, often the fix. The agent feeds that back into its own context and converges. That loop is the whole game.
agents lie. the compiler doesn't.10 / 34
Hard on purpose. Honest by accident.
Strict types→the agent can't fake an interface
Borrow checker→a whole class of bugs, caught for free
Exhaustive match→it can't "forget" a case
Actionable errors→a correction loop that converges
▸The stuff that makes Rust annoying to learn is exactly the stuff that keeps an agent honest.
agents lie. the compiler doesn't.11 / 34
Make the broken state impossible
Don't review for the bug.
Make it not compile.
crates/db/src/lib.rsrust
/// A compile-time guard on every repository method.
/// A TenantScope is constructible only from a valid OrgId,
/// so an unscoped query simply cannot be written.
pub struct TenantScope { org_id: OrgId }▸A cross-tenant leak is the worst bug we could ship — so we made it a type error. The agent can't write the leak. I deleted the review; I didn't automate it.
agents lie. the compiler doesn't.12 / 34
The gate · scripts/cargo-agent.sh
The tooling is the rest of the gate.
--message-format=json→40 lines of error: file:line — not 4,000
test --changed→runs only the crates your diff touched
sqlx cache drift→= FAIL — you can't fake the DB contract
flock→parallel agents queue, they don't race
CI runs the SAME script→-D warnings → local gate == merge gate
▶DEMO 1 — hallucinated API → lean located error → self-fix
agents lie. the compiler doesn't.13 / 34
The last gate isn't on your machine.
commit small→one seam, one commit, readable in one sitting
push early→CI runs the same script. Warnings are errors
babysit CI→red CI is backpressure too. Not done until green
PR review bots→one more model reading your diff
Cadence session review→reads the transcript, not the code. Tool calls vs what you asked
▸Local gate equals merge gate. Let them drift apart and the agent learns to pass the easier one.
agents lie. the compiler doesn't.14 / 34
agents lie. the compiler doesn't.15 / 34
concept 05context is the budget
A drowned agent is a dumb agent.
Every line of tool output lands in the context window and stays there. Fill it with cargo noise and the agent starts forgetting what it was doing. Tokens cost money. Context costs judgement.
✗4,000 lines of raw cargo output
✓the 40 that matter
▸Two levers. Send the agent less. Have it say less back.
agents lie. the compiler doesn't.16 / 34
Lean tool calls · lever one
Compress the chatter. Gate the truth.
rtk
Rust Token Killer. Transparent proxy over a hundred-plus shell commands. git, docker, ls, the lot. 60–90% smaller, zero config.
→ makes the calls cheaper
headroom
The one getting popular. Wraps the whole agent — AST-aware compression, cache-aligned prefixes, retrievable originals. 60–95% smaller.
→ makes the session cheaper
x-agent
Per-toolchain gates, cheap steps first. fmt, then check, then clippy, then tests. Structured pass/fail, 90–97% less noise.
→ makes the loop honest
▸Run a compressor and a gate together. Just never put lossy compression in front of authoritative output. A dropped error line costs more than it saves.
agents lie. the compiler doesn't.17 / 34
Lean results · lever two · github.com/JuliusBrussee/caveman
Make the agent grunt.
standardYour component re-renders because you create a new object reference on every render.
caveman fullNew object ref each render. Inline object prop = new ref = re-render.
caveman ultraInline obj prop → new ref → re-render.
ultra is a party trick. half to three-quarters terse is the sweet spot.
▸Around 75% fewer output tokens. Code and error messages stay exact. Only the prose gets clubbed.
agents lie. the compiler doesn't.18 / 34
Stop waiting on tests that prove nothing.
cargo crap→complexity × undertested-ness finds the six scary functions
cargo-agent --changed→runs only the crates your diff touched
a justfile works too→one obvious entry point beats tribal knowledge
▸Forty tests that assert nothing aren't free. You wait for them on every pass..
▶DEMO 3 — crap-report-findings.md: real risk vs CRAP noise
agents lie. the compiler doesn't.19 / 34
CHAPTER IV
The honest part
🦀agents lie. the compiler doesn't.20 / 34
What they still get wrong
Rust catches a lot. Not everything.
✗fights the borrow checker by cloning everything
✗reaches for .unwrap() / .clone() / unsafe to make the error go away
✗invents crate APIs that look right and don't exist
✗writes async that compiles and deadlocks
✗writes 40 tests that assert nothing, to look thorough
agents lie. the compiler doesn't.21 / 34
Map vs. territory · docs/temporal-workflow-catalog.md
“Do not ‘fix’ the catalog by pretending those writes do not exist. Record reality, then refactor the code separately.”
▸An agent will happily make the docs describe the code it meant to write. The map has to match the territory — or it's worse than no map.
agents lie. the compiler doesn't.22 / 34
A gate for each failure mode.
over-cloning / unwrap→clippy on deny, unwrap banned in CI
invented APIs→cargo check, every step, before review
testing trivia→cargo crap, from the lean chapter
compiles-but-wrong→tests + a second model reviewing intent
context drift→every session is day one: re-read plan + git
▸One failure mode is left over — a decision you never saw, executed confidently. No compiler sees it. Last chapter.
agents lie. the compiler doesn't.23 / 34
CHAPTER V
Loopy McLoop Loop
🦀agents lie. the compiler doesn't.24 / 34
The leftover failure
It ran. It works. It's not what you asked.
Somewhere mid-session a question came up, and the agent answered it itself. That will happen — the only variable is whether you find out now or in the demo.
▸Type-level backpressure can't catch a wrong decision confidently executed. For that you need loops with a human in them.
agents lie. the compiler doesn't.25 / 34
concept 06the convergence loop
Draft. Cross-review. Converge.
model A drafts
PRD, plan, or code
→model B attacks
picky, adversarial
→A addresses
findings, not vibes
↺until nitpicks
that's convergence
▸The stop signal is mechanical — when the reviewer is reduced to nitpicking trivia, you're done. Different vendors miss different things. Diversity of perspective, machine edition.
agents lie. the compiler doesn't.26 / 34
The process
SEAMS
Supervised Engineering via Adversarial Model Steps
one commit at a timereview before and afterbots never merge
agents lie. the compiler doesn't.27 / 34
One seam, start to finish
The seam loop.
.seams/{issue}/per seam
a · plandiscover→seam plan→plan review ⟲→tier 3 → human
b · buildimplement→verify · verifier→seam report→report review ⟲→commit
c · shippush PR→CI + review bots ⟲→merge→next seam ↺
artefact readsyq '.tier'→whole front matter→whole docthe cheapest read that answers the question
▸Two artefacts per seam — a plan and a report, yaml front matter on both, reviewed at both ends by a model that didn't write the code.
agents lie. the compiler doesn't.28 / 34
Six behaviours. Swappable models.
coordinator
the only one you talk to
planner
carves off a single simple seam
implementer
codes the approved seam, writes the report
reviewer
different vendor, picks it all apart
verifier
runs the checks, reports verbatim
shipper
PRs, checks, babysits CI
▸Claude plans. Codex implements. Pi takes the cheap repetitive passes. Pick the model per role for cost, speed and quality.
agents lie. the compiler doesn't.29 / 34
The author can't grade its own tests.
docs/seams_config/_verification.mdrule
implementer ──run_verification──▶ verifier (separate agent)
▲ │
└──── pastes results into the report ◀────┘
▸Let the agent that wrote the code report whether the tests passed, and it will say they passed. So it can't. A different agent runs them — the result lands in the report whether it likes it or not.
agents lie. the compiler doesn't.30 / 34
The dial · autonomy vs. review
Boring flows. Risk stops.
Tier 1auto-commitdocs, test renames, config
Tier 2commit-and-continuemechanical moves, no behaviour change
Tier 3stage-and-blockauth, schema, billing → I approve, twice
PRs go to main or stack on each other. Either way a human reviews and merges. bots never merge.
▸This is the balance point. The agent runs free on what's boring and stops dead on what bleeds. Unsure means Tier 3.
agents lie. the compiler doesn't.31 / 34
No memory. Great memory.
cold start→re-read the plan, the seam artefacts, git
205 dated plans→docs/plans since February. The memory lives in the repo
same files, every session→stable prompt prefixes → cache hits
breaking the cache→a new message into an old session. 10–20% extra spend over time
not token-maxxing. token-cache-maxxing.
▶DEMO 2 — the fleet runs one real seam, artefacts land in .seams/
agents lie. the compiler doesn't.32 / 34
Three moves for tomorrow morning.
01Put a gate in front of your agentgithub.com/codesoda/x-agent
02Write the plan first, review it harda second model, until it's nitpicks
03One commit at a timediff too big to read = seam too big
▸Skip the cathedral. Any one of these pays for itself inside a week.
agents lie. the compiler doesn't.33 / 34