Working with a coding agent
melee newwrites anAGENTS.mdthat tells an agent the rules. The two it needs most are thatmelee devis not the compiler, and that a clean compile is not a working app.
An agent that has written Rails or Sinatra will be productive in a melee app within a few minutes and will
also, left to itself, reach for four things that do not exist here: a gem, a background job, a class that
builds methods at runtime, and a Date. None of those fail in an obvious place. Most of them fail at compile
time with a message about a type, and some of them compile and behave differently from how they behaved in
development.
So the useful instructions are not a summary of the API — the agent can read that. They are the handful of things that are true of melee and of nothing else the agent has seen.
What melee new writes
Every app scaffolded since this was added has an AGENTS.md in its root, named after the app:
notes/
AGENTS.md the dialect, the loop, and what a green build does not prove
README.md the same directory, for a person
Agents that look for AGENTS.md, CLAUDE.md or an equivalent pick it up with no prompting. If your app
predates it, or you keep your instructions somewhere else, melee new a throwaway app in /tmp and copy the
file out — or write your own from the three sections below.
An AGENTS.md you already have is never overwritten. melee new . in a directory that has one keeps yours
and says so.
The two instructions that matter
melee dev is CRuby, not the compiler. It is the fast loop, and it is not the truth. An agent that runs
melee dev, makes a request, sees a 200 and reports success has proved less than it thinks: the deployed app
is a binary built by Spinel, and the two disagree about more than you would like. Tell it to finish with
melee check, and with melee test --both when there is a test — the --both half compiles the test and
diffs it against the CRuby run, which is the only cheap way to catch a dialect trap before a user does.
A clean compile is not a working app. Wrong arity, calling a method on nil, and Integer + String all
compile and raise when they run, and so does a misspelt method reached through an explicit receiver —
db.frist(...), user.nmae — in at least some shapes. An agent that reasons “it compiled, so it works” will
hand you a broken route with real confidence. Tell it to exercise the route it changed, and treat a green
build as the start of checking rather than the end of it.
Both of these are in the scaffolded AGENTS.md. They are worth repeating in your own prompt when you ask for
something substantial, because they are the two beliefs an agent brings from every other Ruby codebase.
The reference to point it at
The library’s documentation ships with the library, so it is on disk at the version the app actually builds
against, after the first melee dev, melee check or melee test:
.melee/stdlib/docs/llms.txt the index, and the dialect in ten rules
.melee/stdlib/docs/dialect.md what compiles and what does not, with the workaround for each
.melee/stdlib/docs/reference.md every method with its signature
That beats pointing at the web: it cannot drift from the toolchain, and it works with no network. But it only exists after a build, and plenty of tools want a URL, so the manual publishes two indexes in the llms.txt shape:
https://melee.ideasasylum.com/reference/llms.txt the app-facing surface and nothing else
https://melee.ideasasylum.com/llms.txt the whole manual, including the operator pages
Start an agent on reference/llms.txt. The whole manual is a lot of tokens to spend on an app that needs one
route and a migration, and most of it is about running a server rather than writing an app.
What to expect it to get wrong
Not a complete list — the dialect is — but these are the ones that come up again and again, in rough order of how often:
- A gem. There is no bundler and no
Gemfile. The require list is short and closed; anything outside it has to be written by hand or done without. - A background job. No threads, no queue, no
async. Work that outlives a request goes in a durable object with a timer, which is a genuinely different shape and worth reading before asking for one. Date,Time.parse,DateTime. Timestamps are Unix seconds orYYYY-MM-DDstrings, and the arithmetic is yours.- A mixed container. An Array or Hash that holds two shapes, or a method that returns a
Stringon one path andnilon another, poisons type inference — and the error surfaces somewhere else entirely, often as aNoMethodErroron a method that plainly exists. row[:name]. Rows are Hashes keyed by String.- A rescue through an alias.
rescue HTTP::Errornever matches; the class has to be spelled in full. - Editing a migration that has already run. Migrations are files applied in name order, once.
Reviewing what it wrote
The same three commands you would run yourself, in this order:
melee check # does it compile
melee test --both # does it behave the same compiled as interpreted
melee dev # does the route actually do the thing
melee check is the one an agent skips, and it is the one that catches the dialect. Ask for its output rather
than for a summary of it — the diagnostics name the file and line, and a summary of a compile error is worth
much less than the compile error.