Harness 2026-11-01
AgentC Blog

Your agent called a method that doesn't exist. When should it find out?

Picture an agent calling a method that sounds right and building more code on top of it, until the build fails on that very first line. Where could a mistake that small have been caught, and does catching it sooner change anything?

5 min read ~200ms if you're an agent Subscribe via RSS

Picture yourself watching your agent work in a Crystal project. It needs a folder created, so it writes File.mkdir_p("reports/2026"). It reads naturally. It is also not a real method in Crystal; the real one is Dir.mkdir_p.

The agent doesn't know that yet, so it keeps going. It writes the report builder that uses that folder, then the controller that calls the builder, then a test. At the end it runs the build, and the compiler stops on the first line it wrote, four files back. Now it has to unwind its own work, or you do.

The mistake took one line. Where should it have been caught?

Two timelines for one line

Caught at the end: the method is wrong on line one, and nobody finds out until the build. By then three more files assume it works. The fix is small; finding it, and checking everything built on top of it, is not.

Caught at the line: before the agent writes the call, it asks the project what methods really exist. The answer comes back in a moment, and the wrong name never gets written.

That second timeline is what amber-lsp does for Crystal projects. It ships with Amber CLI, and it answers from the project's real code: its own files, every library it depends on, and Crystal's standard library.

What the agent sees

Asked about the real method, it returns the exact signature and where it lives (paths shortened here):

$ amber-lsp lookup 'Dir.mkdir_p'
amber-lsp lookup: found (fresh)
Dir.mkdir_p(path : Path | String, mode : Int32 = 511) : Nil  — src/dir.cr:294  [crystal]
  Creates a new directory at the given path, including any non-existing

Asked about the one that sounds right, it can compile a tiny test against the project to be sure:

$ amber-lsp lookup 'File.mkdir_p' --verify
amber-lsp lookup: absent (fresh)
amber-lsp lookup: verified absent in 204 ms

That check, which compiles a small test, took a fifth of a second. In the example above, catching it there means the agent never builds three more files on a call that doesn't exist.

In an Amber app, it also checks each Crystal file against the framework's rules right after the agent edits it. Here it is on a controller whose class got the wrong name:

$ amber-lsp --check src/controllers/invoices_controller.cr
amber-lsp: covered 5 diagnostics, 1 error
src/controllers/invoices_controller.cr:1: error: amber/controller-naming: Class 'InvoicesHandler' in controllers/ directory should end with 'Controller'
src/controllers/invoices_controller.cr:1: information: amber/spec-existence: Missing spec file: expected 'spec/controllers/invoices_controller_spec.cr' to exist
src/controllers/invoices_controller.cr:1: information: fsdd/doc-block-required: Class 'InvoicesHandler' is missing a doc comment
src/controllers/invoices_controller.cr:2: information: fsdd/doc-block-required: Method 'index' is missing a doc comment
src/controllers/invoices_controller.cr:2: warning: fsdd/method-type-signature: Method 'index' has incomplete type signature: missing return type

The error is the framework's own naming rule. The rest are rules we build with: a spec file for every controller, a comment on every class and method, a declared return type. All of it reaches the agent in the same turn as the edit, while the file is still open in front of it.

Did looking things up help?

When we made the agent look methods up before calling them, its code compiled on the first try more often. In the 40-task evaluation reported with Amber CLI 2.0.7, Claude Sonnet went from about 6 tasks in 40 failing to compile on the first try to about 1. The smaller Claude Haiku went from about 15 failures to about 7. The details and limits are below.

What happens as the agent works

amber setup:agent connects Claude Code and Codex to the checker in any Crystal project with four hooks:

  • When a session starts, the agent learns whether the checker is ready and is told to look methods up before calling them.
  • Before a Crystal edit, the edit is refused if the checker is missing, out of date or fails its checksum, and the agent is told to ask you to run amber setup:agent.
  • After a Crystal edit, the file is formatted and, in an Amber app, checked against the rules.
  • When the agent tries to finish, the project is built and any compiler errors go back to it.

Stopping the edit makes a missing checker visible right away, instead of letting the agent keep writing Crystal without its way to look things up.

Try this today

You don't need Crystal for the habit. The next time your agent is about to use a function or method it hasn't used before in your project, ask it: "Before you call that, show me where it is defined and what it takes." If it can't find it, it was about to guess. Step 7 of the lesson sets up the full checker for a Crystal project and shows the two checks to set up with your language's tools.

The cheapest correction is the one the agent gets while it is still writing the line.

First-try compile rate, with and without lookup
Sonnet
without lookup
85.0%
lookup required
97.5%
Haiku
without lookup
62.5%
lookup required
82.5%
40 tasks. Source: Amber CLI 2.0.7 release notes.

How we tested it

  • The tool output: Amber CLI 2.0.7 with amber-lsp 1.0.0, run on November 1, 2026 on two small example projects made for this post. The File.mkdir_p story above is an illustration built around that real lookup, not a recorded session.
  • The 40-task result: from the Amber CLI 2.0.7 release notes: requiring lookup raised first-try compile rates from 85.0% to 97.5% with Sonnet and from 62.5% to 82.5% with Haiku. The task counts above are those rates applied to 40 tasks. The evaluation's raw data is not published, so treat these as reported figures from our own team.
  • Limits: one framework, two models, one task set. The lookup result and the checker example are separate: the evaluation measured looking methods up, not the after-edit checks.

Next in the series: To the builder who is worn out from reviewing their agent's code