Agent experience (AX)
Your agent reads the interface, not the repository.
When it's wrong and the compiler knows the fix, the verdict carries it. iyi holds this by language rule: a module compiles against what its dependencies declare, so a model can read an interface without the repository.
Same fix. 31–43% fewer prompt tokens, for no fewer rounds.The recorded session ↓
Same four verbs in both lanes. Watch what each one has to read.
A replay of the measured result (method below). Code shown is illustrative; the recorded session follows.
The loop, recorded.
4 files, one mistake, the compiler's own verbs. The same verbs answer over MCP, byte for byte.
01 · Ground the edit
{"file":"agent/app.iyi","imports":[{"import":"app/greeter","api":{"module":"app/greeter","interface_hash":"f2f9576ba7e3996e204d5c93ccf5f42d","functions":[{"name":"polite","parameters":["name : String"],"returns":"String","doc":"The exported surface carries its doc comment, so the grounding pack an agent\nreads says what the function is for and not only what it takes.","rendered":"def polite(name : String) : String"},{"name":"shout","parameters":["name : String"],"returns":"String","rendered":"def shout(name : String) : String"}],"types":[{"name":"Greet","kind":"trait","visibility":"pub","methods":[{"name":"greet","parameters":[],"returns":"String","required":true,"rendered":"abstract def greet : String"}]}],"impls":[]}}]}02 · Ask for the verdict
[{"file":"agent/app.iyi","line":8,"column":1,"size":4,"message":"instantiating 'App.main()'"},{"file":"agent/app.iyi","line":9,"column":8,"size":5,"message":"undefined method 'polit' for App:Module\nDid you mean 'polite'?","suggested_edit":{"file":"agent/app.iyi","line":9,"column":8,"size":5,"replacement":"polite"}}]03 · Apply it, and confirm
fixed app.iyi:9:8: `polit` -> `polite`
(no output)
04 · Re-run only what the change reaches
1 passed, 0 failed
0 to run, 1 skipped: no test's imports reach the change
The servers are in the binary.
There is nothing to install and no second implementation to keep in step. iyi lsp speaks the Language Server Protocol to an editor and iyi mcp serves check, fix, context, test and doc as Model Context Protocol tools to a harness, both over stdio, and both are shells around the same front end a build uses. So there is no agent mode and no forked behavior: same verb, same file, two doors.
Byte for byte the same answer through both doors.
Compared on every recording, and the record is refused when they differ.
identical: true · bytes: 318
Does the edit reach anyone?
Pick an edit and see who has to rebuild.
Change a body
module app/greeter interface unchanged what a consumer type-checks against implementation unchanged the bodies a consumer compiles: macros, generics, the initialiser source changed the file dependencies unchanged what this module was compiled against
Change a declaration
module app/greeter interface changed what a consumer type-checks against implementation unchanged the bodies a consumer compiles: macros, generics, the initialiser source changed the file dependencies unchanged what this module was compiled against gone def shout(name : String) : String new def shout(name : String, times : Int32) : String
How the numbers were measured.
On four modules a pack is no smaller than the sources it stands in for. So the gate that runs both arms measures it on two of the repository's samples whose imports carry bodies: webapp.iyi, against kemal/dsl and kemal/router, and calc.iyi, against calc/lexer, calc/parser, and calc/ast. The prompt tokens are from the webapp.iyi task, written once against the pack and once against the sources.
The project is records/agent/ in this site's repository. Install the compiler and the frames on this page are what you will see.
- samples
- webapp.iyi · calc.iyi
- token task
- webapp.iyi
- runs
- twenty-six
- arm A
- sources
- arm B
- iyi mod context
- pack size
- 52–59% of sources
- rounds to green (the model's)
- tied three · lost three