Tooling
This page answers: as an agent integrating with Argon (writing code, calling diagnostics, wiring an MCP harness), what does the tooling surface look like and how do I use it?
For the language itself, see Quick Reference. For why this surface exists in the shape it does, see RFD-0027. For the diagnostic schema’s stability commitment, see RFD-0028.
Architecture in one paragraph
Argon’s agent-facing tooling is layered. Tier 0 is the universal floor: every ox subcommand relevant to agents accepts --json and emits payloads conforming to schemas under share/argon/schemas/. Any harness that can run a shell command and parse JSON is integrated. Tier 1 is the MCP transport: ox mcp exposes the same operations as MCP tools, bytewise-identical to the CLI JSON. Tier 2 is the VS Code / Cursor extension for in-editor humans (and IDE-mode agents). Tier 3 is per-agent skill / rules files (share/agents/_common/argon-skill.md plus per-agent variants) that teach agents which Tier 0 / Tier 1 capability to reach for.
All four tiers are backed by a single in-process surface library, oxc-agent-surface. Transports never reimplement operations; they’re wire-format projections of typed Rust function calls.
Tier 0 — universal CLI + JSON schemas
Every agent-relevant subcommand accepts --json:
| Command | Schema | Notes |
|---|---|---|
ox check --json | diagnostics.schema.json (v1.0, ratified by RFD-0028) | Type-check + meta-property calculus + package constraints. Returns a DiagnosticsReport. |
ox explain <code> | (planned: explain.schema.json) | Diagnostic code → prose with example fix. Currently text output. |
ox query <name> --json | (planned: query-result.schema.json) | Run a named query against compiled state. Bindings + provenance. |
ox tree --json | (planned: package-tree.schema.json) | Resolved package tree + lockfile state. |
ox why <package> | (planned: provenance.schema.json) | Path-to-package explanation; provenance walk. |
Schema files ship inside the toolchain at ~/.argon/toolchains/<version>/share/argon/schemas/. Their version manifest is version.json:
{
"schema_set": "0.1.0",
"schemas": { "diagnostics": "1.0.0" },
"stable": ["diagnostics"]
}
Schemas listed in stable have crossed SemVer 1.0 via their ratification RFD; pin against those with confidence. Pre-1.0 schemas may break between minor toolchain releases.
Example: ox check --json
$ ox check --json | jq '{schema_version, summary}'
{
"schema_version": "1.0.0",
"summary": { "errors": 1, "warnings": 0, "infos": 0 }
}
The full payload:
{
"schema_version": "1.0.0",
"diagnostics": [
{
"code": "OE0226",
"severity": "error",
"message": "metarel endpoint mismatch",
"primary_span": {
"file": "src/lease.ar",
"byte_start": 142, "byte_end": 154,
"line_start": 8, "col_start": 5,
"line_end": 8, "col_end": 17
},
"primary_label": "expected `kind`, found `role`",
"secondary_labels": [],
"help": null,
"package_origin": "ufo",
"provenance_chain": []
}
],
"summary": { "errors": 1, "warnings": 0, "infos": 0 }
}
Every Diagnostic carries the same nine fields. severity is one of "error" | "warning" | "info". primary_span is null for spanless diagnostics (CLI-layer cross-format errors with no .ar source); when present, it carries both 0-indexed UTF-8 byte offsets and 1-indexed UTF-16 line/column. Column units are UTF-16 code units, matching LSP’s code-unit-width convention so multi-byte characters land in the same column an LSP-aware editor would compute. Indexing diverges from LSP — LSP’s Position is 0-indexed for both line and character — so an agent passing these into LSP Position fields must subtract 1 from each. Argon emits the editor-display form (1-indexed) per RFD-0028.
Exit code: 0 when summary.errors == 0, non-zero otherwise. Configuration errors in ox.toml short-circuit before any diagnostic compilation runs and surface as their own diagnostics in the same payload shape.
Tier 1 — MCP transport (ox mcp)
ox mcp is the Model Context Protocol server. Speaks JSON-RPC 2.0 over stdio. Configure your agent (Cursor, Claude Code, opencode, Codex, Continue, Aider) to launch it as an MCP server. oxup agents register writes the relevant config for detected agents on toolchain install — see Tier 4 below.
Tool surface
| Tool | Wraps | Returns |
|---|---|---|
argon_check | ox check --json over a workspace | DiagnosticsReport (text content with JSON body) |
argon_explain | ox explain <code> | Text |
argon_check_file | (planned) file-scoped check | DiagnosticsReport |
argon_query | ox query --json | Bindings + provenance |
argon_packages | ox tree --json | Package tree |
argon_why | ox why --json (post-provenance) | Provenance walk |
Tool payloads are bytewise-identical to CLI JSON because both transports route through the same oxc-agent-surface library — drift between channels is structurally impossible.
Lifecycle (v0 vs v1)
ox mcp ships in two scheduled phases within one release cycle.
- v0 (current): thin spawning transport. Each MCP tool call invokes the corresponding
oxCLI subcommand as a child process and streams its JSON output back. No persistent compiler state. Cold cache on every call. Simple lifecycle. - v1 (next): persistent
OxcContext. Holds one Salsa database across tool calls; warm caches across requests; correct cache invalidation against file changes between calls. Production-traffic shape. Same wire surface — clients targeting v0 work unchanged on v1.
See RFD-0027 for the rationale on shipping v0 first.
Wire example
→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"my-agent","version":"1.0.0"}}}
← {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","serverInfo":{"name":"argon","version":"0.4.x"},"capabilities":{"tools":{}}}}
→ {"jsonrpc":"2.0","id":2,"method":"tools/list"}
← {"jsonrpc":"2.0","id":2,"result":{"tools":[{"name":"argon_check","description":"...","inputSchema":{...}},...]}}
→ {"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"argon_check","arguments":{"workspace":"/abs/path/to/project"}}}
← {"jsonrpc":"2.0","id":3,"result":{"content":[{"type":"text","text":"{\"schema_version\":\"1.0.0\",...}"}],"isError":false}}
Workspace is optional; omitted falls back to the server’s launch CWD. Absolute paths only — relative paths surface a -32602 invalid params error to avoid CWD-drift surprises across tool calls.
Tier 2 — IDE extension
The Argon VS Code / Cursor extension wraps ox-lsp for in-editor humans and IDE-mode agents that pick up diagnostics via the editor’s extension-to-context glue. Install with:
oxup extension install
Or cursor --install-extension <vsix> against a release VSIX. Once installed, the language server activates on .ar files, populates the InfoView panel, and surfaces diagnostics through the editor’s standard publishDiagnostics channel. Agents running inside Cursor / VS Code see those diagnostics as part of their normal context.
Tier 2 is unchanged by RFD-0027 — it’s the existing surface, retained.
Tier 3 — per-agent skills / rules
Skill / rules files teach an agent which Tier 0 / Tier 1 capability to reach for. They’re documentation pointers, not implementations.
oxup agents register (called automatically by oxup install / update / default) walks every share/agents/<id>/ directory in the active toolchain and drops the skill file at the agent-specific config location:
| Agent | Target |
|---|---|
| Cursor | ~/.cursor/rules/argon.md |
| Claude Code | Skill plugin via ~/.claude/settings.json marketplace pointer |
| Codex | ~/.codex/AGENTS.md |
| opencode | rule file under opencode’s rule directory |
Single-source content lives at share/agents/_common/argon-skill.md. Per-agent variants under share/agents/<id>/ wrap that body with the frontmatter each agent expects. Substantive edits land in _common first.
If you maintain agent integrations in your project, you can override the global skill with a project-local file at <workspace>/.cursor/rules/argon.md (or the equivalent for your agent). Project-local rules win over global ones.
Tier 4 — registration as data
share/agents/<id>/registration.toml is a per-agent descriptor read by oxup agents register. Adding a new agent that uses an existing handler kind is a share/ data drop — no Rust changes required.
Descriptor shape:
[agent]
id = "cursor"
name = "Cursor"
[detect]
config_dir = "~/.cursor" # ~ expanded against $HOME
[[register]]
kind = "mcp-server"
config_relative = "mcp.json"
server_name = "argon"
argv = ["ox", "mcp"]
Detection is per-agent presence — missing config dir means the registration step is a silent no-op. Registration steps are idempotent on re-run; toolchain bumps re-aim transparently.
Currently supported handler kinds:
claude-marketplace— merge a marketplace pointer +enabledPluginsentry into Claude Code’s~/.claude/settings.json. Used byshare/agents/claude-code/registration.toml.mcp-server— merge anmcpServers.<name>entry into the agent’s MCP JSON config. Used byshare/agents/cursor/registration.toml. The same kind works for any agent consuming the standard MCPmcpServersshape.
New kinds extend the RegistrationStep enum + dispatch in oxup::agents. Adding a kind is a Rust change; adding a new agent that uses an existing kind is purely a share/ data drop.
I want to … do Y
| Task | Reach for |
|---|---|
| Get diagnostics on a workspace | ox check --json (or argon_check over MCP) |
| Understand what a diagnostic code means | ox explain <code> (or argon_explain over MCP) |
| See what packages a workspace depends on | ox tree --json (or argon_packages over MCP) |
| Run a named query against compiled state | ox query <name> --json (or argon_query over MCP) |
| Wire my agent up to call Argon’s MCP tools | oxup agents register (runs automatically on oxup install) |
| Install the editor extension | oxup extension install |
| Pin against a stable wire format | check share/argon/schemas/version.json’s stable array |
| Override the global skill content for one project | drop a project-local rule file (e.g. .cursor/rules/argon.md) |
Stability discipline
- Schemas in
stable: SemVer-locked. Breaking change → major bump; additive change → minor bump. Consumers pin. - Schemas not in
stable: pre-1.0, may break between minor toolchain releases. Each schema graduates to 1.0 via its own follow-up RFD as the underlying surface stabilizes. - MCP wire shape: tracks the published MCP spec revision. The server announces its supported
protocolVersionduringinitialize; clients negotiate. - Tool names + argument shapes: stable within a major. Adding a new tool is non-breaking; renaming or removing a tool requires a major bump.
- CLI flags:
--jsonis stable; per-command flag changes follow the standardoxCLI deprecation cycle.
Anti-patterns
- Don’t infer diagnostics from prose. Parse the JSON. The wire format is the contract.
- Don’t fork wire shapes between transports. CLI JSON, MCP tool payloads, and (future) LSP-extended response bodies are all the same data, projected from the same in-process surface. If you find yourself reconstructing a payload differently in different places, you’ve drifted.
- Don’t depend on a non-
stableschema in production. Pre-1.0 schemas may evolve. Use them, but pin to the toolchain version, and watch the next ratification RFD. - Don’t hand-author files generated by
oxc-codegen. Schemas, TypeScript bindings, and the diagnostic registry are emitted from Rust source-of-truth types viaschemars/ts-rs. Drift is gated byoxc-codegen checkin CI. - Don’t run
ox mcpwith relative workspace paths. v0 rejects them with-32602 invalid params; this is intentional and stays in v1.
Where this ships
- Schemas:
~/.argon/toolchains/<version>/share/argon/schemas/ - Skill content (single-source):
~/.argon/toolchains/<version>/share/agents/_common/argon-skill.md - Per-agent variants:
~/.argon/toolchains/<version>/share/agents/<id>/ - Registration descriptors:
~/.argon/toolchains/<version>/share/agents/<id>/registration.toml oxbinary:~/.argon/toolchains/<version>/bin/ox- LSP binary:
~/.argon/toolchains/<version>/bin/ox-lsp
oxup proxies (~/.argon/bin/ox, etc.) resolve the active toolchain via ox-toolchain.toml walk-up and exec the version-specific binary; integration code never hard-codes an absolute path.
See also
- RFD-0027 — the architecture rationale (why CLI is the floor, why MCP is Tier 1, why registration is data).
- RFD-0028 — diagnostics schema 1.0 ratification.
- Anti-Patterns — Argon-language anti-patterns (vs the tooling-specific ones above).
- Decision Guides — choosing between Argon language constructs.