Building with AI agents
Xeer is designed so that a program can drive it as competently as a person. That is not a compatibility layer bolted onto a human-first tool — it shaped the framework. It is why the app's entire shape lives in one declarative file, why the API surface is small enough to describe exhaustively, and why every failure carries a stable code and a suggested repair instead of a paragraph of prose.
If you are pairing with an agent, this page is what to give it.
#Every command speaks JSON
xeer check --json
xeer build --json
xeer deploy --jsoncheck, build, new, doctor, deploy, promote, rollback, link, env, deployments, and the
rest print exactly one envelope:
{
"protocol": "xeer.command.v0",
"command": "check",
"ok": false,
"diagnostics": [
{
"code": "XE1002",
"severity": "error",
"message": "…",
"file": "xeer.app.json",
"span": { "line": 12, "column": 9, "length": 6 },
"hint": "…"
}
]
}dev, preview, and test are long-lived, so they stream newline-delimited xeer.dev.v0 events
instead. preview.ready is the readiness handshake — an agent waits for that rather than sleeping and
hoping. test.case.fail carries a Diagnostic-shaped failure.
#Diagnostics are the interface
interface Diagnostic {
code: string; // XE####, stable
severity: 'error' | 'warning' | 'info';
message: string; // human wording, free to change
file?: string; // project-relative POSIX path, never absolute
span?: { line: number; column: number; length?: number }; // 1-based
hint?: string; // suggested edit
}Dispatch on code, never on message. Codes are stable; wording is not. file and span locate the
problem precisely enough to edit without searching, and hint is the platform's own suggestion for
closing it.
Every code is catalogued in the diagnostics reference — which is generated from the same catalogue the compiler emits from, so it cannot fall behind the codes you actually see.
xeer doctor --json is the other half: it reports the environment (Node version, platform,
resolvable dependencies, generated config, local state) as structured checks, which is how an agent
distinguishes "your code is wrong" from "this machine is not set up".
#The MCP server
@impetik/xeer-mcp exposes the whole loop as
Model Context Protocol tools:
// .mcp.json, or your harness's MCP configuration
{
"mcpServers": {
"xeer": {
"command": "npx",
"args": ["--package=@impetik/xeer-mcp", "--", "xeer-mcp"],
"env": { "XEER_MCP_ROOT": "." }
}
}
}| Tool | Does |
|---|---|
xeer_new | Scaffold a project, optionally from a named template |
xeer_check | Validate the manifest and analyse the source |
xeer_test | Run the application's own test suite, with the full event stream |
xeer_build | Produce the content-addressed artifact |
xeer_doctor | Diagnose the local environment |
xeer_deploy | Deploy to production, or to the preview URL |
xeer_promote | Make a preview version live |
xeer_auth_status | Who the CLI is signed in as |
xeer_inspect | Read a running app's manifest, state, or logs |
xeer_dev_start / _status / _stop | A dev session, addressed by handle and resumed by cursor |
xeer_diagnostics | What an XE#### code means, and the edit that closes it |
Every tool returns the CLI's envelope unchanged, as both structured content and a JSON text block, so a
client that ignores structured output still sees all of it. When the CLI crashes without printing an
envelope the server synthesizes XE0000 rather than failing the call in a different shape — the result of
a tool call is always the same kind of thing.
xeer link and xeer env are deliberately absent. Which hosted app a checkout deploys to is the
owner's decision, so on an identity conflict the surface reports the diagnostic and its documented repair
rather than performing it. xeer env reads and writes secrets — xeer env pull returns plaintext — so it
is not reachable through a tool call at all.
XEER_MCP_ROOT is a confinement root: a directory argument that escapes it is refused.
#Why dev is three tools
A tool call is request/response; xeer dev is a long-lived stream. So the session is owned by the server
and addressed by a sessionId, with the protocol's own sequence number as a resumable cursor:
xeer_dev_start → { sessionId, cursor, status: 'ready', preview: { url, … }, events }
edit a file
xeer_dev_status → { events: [compile.start, compile.diagnostic?, compile.ready?], openDiagnostics }
xeer_dev_stop → { status: 'stopped' }No event is summarised away — the agent reads the same stream a terminal would show. Repairing diagnostics
needs none of this, because xeer_check runs the same compiler; the session exists for when the running
app matters.
Always stop a session you started: local state is leased per project, so a leaked session makes the next
run fail with XE1812.
#The loop that works
xeer new → edit → xeer check → edit → xeer test → xeer build → xeer deploy
↑___________| ↑____________|Two things make this reliable rather than hopeful:
xeer checkis fast and complete. It validates the manifest and analyses both source graphs without running anything, so the edit-check loop is tight and every failure is located.xeer testproves behaviour, not compilation. An agent that only checks has proved the code parses. An agent that tests has proved the app does what the tests say — including who is allowed to do what, because tests run as three different users.
The step most worth insisting on is the second one. Xeer ships a test runner precisely so that "it compiles" is never mistaken for "it works", and an agent with no human reviewing every diff needs that distinction more than a person does.
#Why the framework's shape helps
- One declarative manifest. An agent can read what an app is — its tables, its indexes, its capabilities — without inferring it from code. And it can change what an app is by editing one file, which the compiler then validates.
- Deny by default.
ctxhas three properties. There is no ambient resource an agent can reach for by accident, and no credential lying around to misuse. - A closed, small API. Seven database methods, six input types, four matchers. It fits in a context window, which means an agent is choosing between options it can actually enumerate rather than guessing at an API surface.
- Authorization in the data layer. A table policy holds for every read and write of that table, so a handler an agent wrote cannot leak rows by forgetting a filter.
- Content-addressed builds. The same source produces the same artifact id, and promote and rollback act on that id — so "ship exactly what was reviewed" is mechanical rather than a matter of trust.
#These docs, as plain text
This site is not the only form the documentation comes in. Every page is also served as Markdown, so an agent never has to scrape HTML to read it:
/llms.txt | The index: what Xeer is, and every page with its purpose and its Markdown URL. |
/llms-full.txt | The entire documentation in one request. |
<page>.md | Any page on its own — /guides/server.md, /reference/cli.md, and so on. |
The diagnostics reference in there is generated from the compiler's own catalogue, so the codes an agent reads cannot drift from the codes the platform emits.
#For Claude Code specifically
The repository ships a skill under .claude/skills/xeer/, including
the generated diagnostics catalogue. Copy it into your project's .claude/skills/ or into
~/.claude/skills/ to have it load automatically.
#Next
- Diagnostics reference — every code, what it means, how to repair it.
- CLI reference — every command and its
--jsonshape. - Testing — the step to insist on.