OxL Reference

AI agents (Claude Code, Codex, Cursor, Gemini CLI)

Decisions D-9100..D-9149 in docs/decisions.md (section "Session 7 - AI"). Sources: compiler/src/mcp/ (library), tools/oxl/cmd_mcp.cpp, tools/oxl/cmd_ai.cpp, tools/lldb/oxl_snapshot.py, tools/ai/ (skills and instructions). Tests: test_mcp (gtest), mcp_stdio, ai_skills_check, ai_setup, install_relocatable (ctest).

OxL is new: a model has never seen it. Two things make an agent productive without burning tokens on guessing and on reading files:

  1. An MCP server built into the compiler binary (oxl mcp): precise, short answers from the real front end (diagnostics with machine-made fix hints, test failures only, signatures from the std sources, one section of the Standard, a debugger snapshot).
  2. Skills and instructions that teach the language compactly: a cheat sheet, the mistakes models make (each with its diagnostic code), idioms, testing, debugging, project layout. Every code block in them is compiled by CI.

Quick start#

sh
oxl ai setup                 # in your project: Claude Code (.mcp.json, .claude/skills, CLAUDE.md, AGENTS.md)
oxl ai setup --all           # Claude Code, Codex, Cursor, Gemini CLI
oxl ai setup --codex --cursor ./myproject

Restart the agent (Claude Code: /mcp). The agent now sees the server oxl with 11 tools, the skills, and AGENTS.md. oxl ai list prints what each client gets. A second run changes nothing; existing configuration is merged (other MCP servers are kept).

The tools (server oxl)#

Output is compact plain text by default; format: "json" is available on check, test, run, symbol, std_lookup, debug. Every tool caps its answer and ends truncated lists with ...N more. isError is set when the answer is a failure (compile errors, failing tests, non-zero exit).

ToolArgumentsAnswer
checkpath (package, file; default .), code (a snippet instead of a file), files (unsaved buffers), limit, formatok, or file:line:col severity code: message per diagnostic with notes and a one-line fix: replace \a` with `b`(the compiler's quick fix) orhelp:`; a summary line
buildpath, profile, output, timeoutok build/name (dev, 0.2s) or the compact diagnostics
runpath, args, stdin, profile, timeout, max_chars, formatexit N (secs) + tails of stdout / stderr (a panic message is in stderr); timeouts kill the process group; compile errors as diagnostics
testpath, filter (regex), exact, tag, kind, seed, failed, args, limit, format1 passed, 2 failed (0.2s) and only the failures: name, location, message, at lines of user code, output tail; passed tests are only counted
fmtpath (formats in place; check only reports) or codethe formatted text, or already formatted
symbolfile, (line, col) or name, op = info / def / refs, limitsignature + doc + definition (def: file:line:col); references with their source line
std_lookupquery (name, Type.name, regex), module, limitstd.core List<T>: var fn push(x: T) - Appends an element.; same-named variants (sum of 14 numeric lists) collapse into one line with [+N similar]
explaincode, max_charsthe diagnostic page (docs/diagnostics/<code>.md, without the Russian line), near-matches for a mistyped code
specquery (§7.2, 7.2, III.9, App. A, or a keyword), lang (en / ru), max_charsthe section text; a chapter answers its introduction and an outline of subsections; a keyword lists matching sections with a snippet
debugpath, breakpoints (file.oxl:line or a function), expressions, args, stdin, timeout, max_frames, max_locals, formatnon-interactive snapshot: stop reason, OxL stack frames, locals of the innermost frame (pretty-printed), values of the expressions; without breakpoints it stops at the first panic
newname, template (cli / lib / service), dirthe created files

Resources: every Markdown / text file of share/oxl/ai is served as oxl://ai/<path> (resources/list, resources/read), so clients without skill support can still read the skills. initialize carries a 120-word instructions text (the tool loop and the "do not guess" rule).

Protocol: JSON-RPC 2.0, one message per line on stdin / stdout, protocol version 2025-06-18 with fallback to 2025-03-26 and 2024-11-05 (the server answers the client's version when it knows it, else the newest). Methods: initialize, ping, tools/list, tools/call, resources/list, resources/templates/list, resources/read, logging/setLevel; notifications are accepted and ignored. A malformed line is answered with -32700 and the server keeps running.

Measured output sizes (e2e test, tests/mcp/test_mcp.py)#

CallBytes
tools/list (all 11 schemas)about 8 300 (once per session)
check clean package2
check one arg-count error91
fmt snippet24
symbol signature + doc + def103 - 378
std_lookup push188
explain unhandled-error1 013
spec "§7.2"1 125 (one section instead of a 237 KB file)
run of a panicking program96
test with one failure of two170
debug panic snapshot (stack + locals)295

Compare: opening std/core/collections.oxl to find push costs about 50 000 tokens; the Standard is about 60 000 tokens.

Where the tools find their files#

oxl mcp finds everything from the installation prefix (<prefix>/bin/oxl), so it works from a release archive, a cmake --install tree and the build tree: standard library lib/oxl/std, diagnostic pages share/doc/oxl/diagnostics, the Standard share/doc/oxl/spec/oxl-standard{,.en}.md, skills share/oxl/ai, pretty-printers and the debug script share/oxl/lldb. Overrides: OXL_STD_DIR, OXL_DIAG_DOCS_DIR, OXL_AI_DIR, OXL_LLDB_FORMATTERS, OXL_LLDB (the lldb binary), oxl mcp --std-dir D --ai-dir D. OXL_MCP_LOG=1 / --log is reserved for traces on stderr.

check, fmt, symbol, std_lookup, explain, spec run in the server process (the language server's analysis: Snapshot, Queries); build, run, test, new, debug start the same oxl binary (or the program) as a subprocess with a time limit and bounded capture. Paths in answers are relative to the server's working directory.

debug: how it works#

The tool builds the package with --debug-info full into a private temporary directory, starts lldb --batch with the OxL pretty-printers and tools/lldb/oxl_snapshot.py, which creates the target, sets the breakpoints plus the runtime hook oxl_dbg_stop_panic (the program runs with OXL_DEBUG_HOOKS=1), launches with stdin / stdout / stderr redirected to files, waits (with a timeout) for the first stop, walks the stack keeping frames that have an .oxl source line, formats the locals of the innermost one, evaluates the expressions (p.x, xs[1], m["k"] through the formatters' synthetic children, else lldb expressions) and kills the process. Needs lldb (lldb-18, Xcode tools); without it the tool answers lldb not found and nothing else breaks. Interactive debugging stays with oxl dap (docs/debugger.md).

Setup per client (what oxl ai setup writes)#

Client--flagMCP entrySkillsInstructions
Claude Code--claude.mcp.json {"mcpServers": {"oxl": {"command": "oxl", "args": ["mcp"]}}}.claude/skills/<name>/AGENTS.md block + CLAUDE.md containing @AGENTS.md
OpenAI Codex CLI--codex.codex/config.toml [mcp_servers.oxl] (command, args).agents/skills/<name>/AGENTS.md block
Cursor--cursor.cursor/mcp.json (same JSON).agents/skills/<name>/.cursor/rules/oxl.mdc (glob **/*.oxl) + AGENTS.md
Gemini CLI--gemini.gemini/settings.json mcpServers + context.fileName ["GEMINI.md", "AGENTS.md"].agents/skills/<name>/AGENTS.md block

Without a client flag the clients whose directory already exists in the project (.claude, CLAUDE.md, .mcp.json, .codex, .cursor, .gemini) are used, in an empty project Claude Code. Options: --all, --force (overwrite a configuration file that is not valid), --dry-run (print what would be written), --link (symlink the skills instead of copying them: they follow the toolchain), --command C (the server command; default oxl when it is in PATH, else the absolute path of the running binary), --ai-dir D. The AGENTS.md text lives between and markers: a rerun replaces only that block.

The table is data (kClients in tools/oxl/cmd_ai.cpp): the conventions were taken from the clients' documentation and are not exercised against the clients themselves in CI (only the files are checked: tests/mcp/test_ai_setup.py). By hand, the same thing is one command per client:

sh
claude mcp add oxl -- oxl mcp              # add --scope user for every project
codex mcp add oxl -- oxl mcp               # or ~/.codex/config.toml
gemini mcp add oxl oxl mcp                 # or ~/.gemini/settings.json
# Cursor: Settings > MCP > add server: command `oxl`, args `mcp` (or ~/.cursor/mcp.json)

Any other MCP client: a stdio server with command oxl and argument mcp.

Claude Code plugin#

tools/ai/claude-plugin/ (installed as share/oxl/ai/claude-plugin) is a Claude Code plugin: .claude-plugin/plugin.json, skills/ (a copy of tools/ai/skills, kept identical by scripts/sync_ai_plugin.py and the ai_skills_check test) and .mcp.json (the oxl mcp server). Try it with claude --plugin-dir <prefix>/share/oxl/ai/claude-plugin, or add the directory to a plugin marketplace of your own.

The skills (tools/ai/skills, Agent Skills format)#

Each skill is a directory with SKILL.md (YAML front matter name, description = when to use it, then a short body) and reference/*.md files that are opened only when needed (progressive disclosure). The test ai_skills_check keeps SKILL.md bodies under 170 lines.

SkillContent
oxl-languagethe 12 differences from Rust / Go / TS, one screen of OxL; references: syntax, types, errors and effects, ownership, concurrency, services, std by task, mistakes (wrong code, its diagnostic code, the fix), idioms
oxl-testingtest kinds, assertions, fixtures, mocks, sim, fuzz, bench, snapshots; running and reading results with the test tool
oxl-debuggingthe cheapest-step-first workflow, reading panics, debug, dbg, traces, profiler, remote debugger
oxl-projectlayout, oxl.toml, workspaces, profiles, dependencies, the command table

tools/ai/AGENTS.md is the generic instruction file (use it as AGENTS.md, CLAUDE.md or GEMINI.md content); tools/ai/llms.txt is an index in the llms.txt convention.

Quality control#

  • tests/mcp/test_skills.py (ctest ai_skills_check) compiles every fenced block of tools/ai/**: oxl blocks must pass oxl check; ```oxl error:<code> must fail with exactly that diagnostic code; ```oxl run is run and its stdout compared with the // expect: lines; ```oxl test runs oxl test (every kind); ```oxl package is a multi-file package (//// path separators). oxl nocheck is not allowed. It also checks front matter, description length, relative links, and that the plugin copy equals skills/.
  • The mistakes list was derived by writing programs the way a Rust / TS programmer would and reading the diagnostics (reference/mistakes.md); add a block there when you see a model repeat a mistake.

Token economy rules the skills teach#

Prefer check to building; check with code to a file round trip; test {exact} to the whole suite; std_lookup to opening std files; spec to reading the Standard; symbol to grepping; debug to print statements; explain to guessing; one fmt at the end.

Limits and notes#

  • debug stops at the first hit; conditions are written in the program. Runtime breakpoints (rpc, msg, step, error) belong to oxl dap.
  • The MCP server is stateless: every tool call analyses from the files on disk (plus the files overlay of check).
  • The server does not write files except fmt (on path), build, new and the temporary directory of debug (removed afterwards).
  • main takes no parameters (std.os.args() gives the arguments); fn main(args: List<str>), a generic main or a result other than () / () | E is the error bad-main (§2.4, D-9405).

See also

Source: docs/ai.md

OxL 1.0.0-beta · Documentation version 1.0.0-beta© OxwaldLink · generated from the Standard, the std sources and the guides