04 / 06

Agents

An assistant writing Nyx has a specific problem: it does not know what already exists, and it does not know which traps this language has. Left to itself it reinvents a standard library function, or invents syntax that looks right, or reads the compiler source to "understand how it works" and gets lost. So nyx init seeds the answer to both questions inside the project, in plain files any assistant can read.

What gets seeded, and what each file is for

AGENTS.mdThe playbook: how a program is built here, the decision procedure, the hard rails, and the traps that ruin a first attempt. Provider-neutral, following the agents.md convention, so any assistant reads the same file.
CAPABILITIES.mdA generated index of the standard library — what already exists, so nothing gets rewritten. It is regenerated from the installed toolchain on every nyx build, so it cannot drift.
docs/nyx/LLM.mdThe dense reference: builtins, methods, types, the traps in long form, idiomatic patterns.
docs/nyx/guides/Three guides — write a program, fix a compile error, report friction.

Nothing here mentions a particular assistant. That is deliberate: the context belongs to the project, not to whoever happens to open it.

The rule that saves the most time

The first thing AGENTS.md says, verbatim:

> **GOLDEN RULE — do NOT read the compiler or stdlib source** (`std/`, `compiler/`, or
> anything under your Nyx install) "to understand how it works". You don't need to and
> you WILL get lost. If you want a function, look it up in `CAPABILITIES.md`. If you want
> an idiom, look it up at <https://nyxlang.com/by-example/>. **No network access?**
> `CAPABILITIES.md` alone is enough to find the right function — skip the idiom lookup
> and write it directly. That's it.

The rest of the file is a nine-step procedure — state the task, check CAPABILITIES.md, find the idiom, write the smallest thing that works, self-check with nyx check and nyx vet, run it, test it, read the error if it does not compile, and stop if you hit a real wall — followed by five hard rails: do not invent syntax, do not reinvent the standard library, do not wander into the compiler source, do not hack around a limitation, do not leave the project directory.

vet names the trap instead of leaving a parser error

Some mistakes are grep-able: they have a shape. nyx vet matches those shapes and reports each one with a stable code, the file and the line, so an assistant gets the trap by name instead of a confusing error three steps later:

$ nyx vet shapes.nx
warning[W101] shapes.nx:2: Enum variants use `.`, not `::`: `Shape.Circle(5)`, never `Shape::Circle(5)`. (docs/nyx/LLM.md §5 enum-dot-not-colons)
warning[W102] shapes.nx:3: Map literal keys must be STRINGS: `{"k": 1}` and `{}` work (v0.16), but `{ident: 1}` is NOT a map literal and fails loudly with `NYX0106`. (docs/nyx/LLM.md §5 map-literal-string-keys)
warning[W104] shapes.nx:4: Channels must be Map, not int: `let ch: Map = channel_new(10)`, never `let ch: int`. (docs/nyx/LLM.md §5 channel-is-map)
warning[W103] shapes.nx:5: `charAt()` returns int (ASCII/codepoint), NOT String — compare with numbers: `if c == 65`. (docs/nyx/LLM.md §5 charat-returns-int)
warning[W107] shapes.nx:6: Check the return of `http_serve`/`tcp_listen`/`udp_bind`: a failed bind (port taken) returns `-1` — `if http_serve(8080, handler) < 0 { return 1 }`. (docs/nyx/LLM.md §5 check-bind-return)

Those five are the codes that exist today. The tail of each line — (docs/nyx/LLM.md §5 enum-dot-not-colons) — points at the entry that explains it at length, inside the project. The warning and that entry cannot say different things: both are generated from the same table.

Adapters, if your tool wants its own file

$ nyx init my-app --agent=claude,cursor,copilot

That seeds, on top of the neutral scaffold, one small file per named tool, in the location each of them looks at. Each is a short file that says the same thing: read AGENTS.md first, the guides are in docs/nyx/guides/, the standard library index is CAPABILITIES.md. They are pointers, not a second copy — there is exactly one source of truth, and duplicating it is how the two versions start disagreeing.

The flag is also the only place on this site where those names appear. The scaffold itself does not care which assistant reads it.

Spec first, when the project deserves it

For anything bigger than a script, the expensive failure is not bad code — it is code that confidently solves the wrong problem. nyx init my-app --sdd (or nyx sdd init on a project you already have) seeds seven pieces that make an assistant ask instead of assume:

docs/constitution.md          what the project is for, and how decisions are made
docs/glossary.md              the words this project uses, defined once
docs/adr/0000-template.md     the template for a decision that outlives a feature
docs/sdd/onboarding.md        how to complete the constitution: 7 questions, one at a time
specs/README.md               the cycle, and the spec template
docs/evidence/nyx-0.31.0.md   generated: the traps that are live in this toolchain
tests/constitution_test.nx    generated: greps src/ for the traps the compiler cannot catch

The constitution arrives empty, and says so:

**SDD_INCOMPLETE** — this constitution is still empty. An agent that reads this marker
**offers** the user to fill it in (`docs/sdd/onboarding.md`: one question per section, in
order) and removes this paragraph ONLY when the seven sections below have at least one
TRUE line each. Nobody invents content to get rid of the marker — three true lines are
worth more than twelve plausible ones.

That marker is the whole mechanism. An assistant that reads it offers seven questions — purpose, users, scope and non-goals, invariants, definition of done, technical constraints, how we decide — one at a time, writes the answers down in the user's own words, and removes the marker only when every section has a true line. "Not applicable" is a valid answer; a plausible default is not. Declining is also fine: --sdd is an offer, and the whole scaffold is reversible by deleting the files it created.

From there the cycle is constitution first, then specs/NNN-feature/spec.md (what and why, with anything unanswerable listed under Open questions rather than guessed), then plan.md (how), then tasks.md (cut small enough to verify one at a time). A spec that contradicts the constitution is wrong, not the constitution.

Two of those seven files are generated rather than written, and that is the point: docs/evidence/ lists the traps that are actually live in the toolchain that seeded the project, with the test that proves each one — if a manual contradicts it, the manual is stale. tests/constitution_test.nx turns the same table into a test that greps your own src/. Both are regenerated by nyx update, so neither can quietly describe an older version.

When it genuinely cannot be done

$ nyx report

Step nine of the procedure is to stop. If the language or the standard library genuinely cannot do something, or there is a bug, or the documents were wrong, nyx report creates a FRICTION.md in the project with the sections to fill in: what you were trying to do, the smallest code that reproduces it, and the literal error. Nothing is sent anywhere — the file is local, the user reads it, and sending it to the maintainers is a separate, explicit --send. A clean report is worth more than a hack.

Keeping it current

Every seeded file ends with a stamp naming the version and the language that produced it. When the toolchain moves ahead of a project, the wrapper notices the mismatch and warns — once, on stderr, without touching the file, because it may well have your edits in it. Refreshing is your decision:

$ nyx update --sync-docs

Run inside the project, it re-seeds AGENTS.md, the reference and the guides from the installed toolchain, regenerates CAPABILITIES.md, and leaves a .bak of anything that differed. Per-tool adapters are never overwritten: they are opt-in and usually edited.