Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

RFD 0066 — Agent integration: the Argon MCP server

  • State: discussion
  • Depends on: RFD 0014 (§19 runtime serving — the connection/serve split this parallels: a transport-agnostic dispatch core under a thin transport layer), RFD 0033 (the ad-hoc query and mutation surface — the type-checked-or-refused body this exposes as argon_ad_hoc_query), RFD 0036 (heterogeneous and specialized stores — the Connection::Remote federation path the remote profile rides), RFD 0046 (derivation serving surfaces — the structured ProofTree/explain model this consumes, and the why-not boundary it marks open), RFD 0052 (deployment topologies and the connection abstraction — the embedded vs. standalone split this server’s two profiles inherit)
  • Prior art: the Model Context Protocol (MCP) and the official Rust SDK (rmcp) — the tool/resource/prompt vocabulary and the stdio transport this server speaks; the Language Server Protocol (ox lsp) as the editor-frontend precedent — a second frontend over the same compiler internals, shipped with the toolchain, editor-agnostic; CQRS read-model framing (RFD 0020 D10) for why the runtime read surface is a shared asset a third frontend may serve without owning the engine.

Question

Argon’s compiler and runtime expose no live integration surface for a coding agent. ox gen --target ts-skill emits a static, per-ontology SKILL.md + SDK reference for writing TypeScript against a generated SDK — explicitly a code-generation artifact, not a runtime client. ox lsp gives an editor-agent the check loop, and nothing more. The live compiler+runtime agent lane is empty: an agent cannot reach the runtime’s structured provenance, bitemporal as_of, first-class n-ary relations, forks, or standpoints, and cannot close the authoring loop (edit → check → why → build → reload → query → explain) against a running knowledge base.

What is the right integration surface for a coding agent, and where does it sit relative to the existing frontends? Specifically: does it ride the existing transport-agnostic dispatch core (sibling to oxc-serve’s HTTP layer) or duplicate runtime logic; what does it expose and what does it withhold; and how does it keep source, artifact, and the served module coherent so an agent never reasons over a stale or wrongly-typed knowledge base?

Context

  • The dispatch core is already transport-agnostic. oxc-connection’s RuntimeService is the state holder oxc-serve wraps; the dispatch_*_core entry points and explain_fork_fact_proof are framing-neutral. oxc-serve is a thin axum /v1 layer over them (RFD 0014). A coding-agent surface is a third frontend over the same core — sibling to HTTP, not a new runtime.
  • RuntimeService carries the coherence machinery the bare Connection does not. It holds reload_if_changed/spawn_watch_task (hot-swap the active module on artifact change; loud-refuse an invalidating schema change against a live ABox, never silently re-type), the OperabilityLimits governor, per-scope mutation locks, cursor pagination over query rows, and the fork lifecycle. The bare embedded Connection (the Tide / RFD 0052 embedder path) has no reload — building on it would reintroduce source/artifact incoherence and duplicate reload logic.
  • The governor already enforces the loud-gate philosophy at runtime. OperabilityLimits enforces a request timeout, a reasoner budget checked at every fixpoint round boundary (so CPU-bound work terminates), and a row cap that refuses loudly rather than truncating. AdmissionControl (multi-tenant concurrency fairness) is a separate, orthogonal concern — inert for a single stdio client.
  • Cursor pagination over query rows already exists (DispatchRequest.page, R-M17/#259); only the Connection::query convenience omits it. Riding the full DispatchRequest through RuntimeService gets paging for free.
  • The coherence primitives already exist. oxc-oxbin::content_hash (SHA-256 over canonical CBOR, §18.6), the loaded module_hash, and the lockfile hashes are the substrate for a precise staleness model — none of it needs to be invented.
  • Structured provenance already exists for data facts. explain_fact returns a structured ProofTree; a clean non-derivation is reported as derived:false, root:None. The check-violation why is, by contrast, currently prose (render_violation_why). Real why-not provenance does not exist (RFD 0046 marks it open).
  • The diagnostic catalog is single-source and already teaches. ox explain OE#### emits extended explanations from grammar.d; the same catalog feeds CLI and LSP. The loud-gate codes (OE13xx, OE1317) are the actionable surface an agent most needs guidance on.

Decision

Specify oxc-mcp / ox mcp: an MCP (Model Context Protocol) server that exposes the authoring loop (check/build/why) and the runtime (bitemporal query, structured provenance, forks, standpoints) to agents, as a third frontend over the existing dispatch core — sibling to oxc-serve’s HTTP layer, parallel to ox lsp.

D1 — Runtime-provenance-led, one closed loop

The headline value is the runtime: structured ProofTree provenance (explain_fact), bitemporal as_of, first-class n-ary relations, forks, standpoints — none of which a coding agent can otherwise reach. The authoring loop (check/why/build) is the on-ramp, not the headlineox lsp already gives an editor-agent the check loop. The product is the closed loop: edit source → check → why → build → reload → query → explain_fact → iterate. The design is organized around making that loop coherent and legible, not around re-exposing the editor’s check surface.

D2 — The runtime backend is RuntimeService, not the bare Connection; the server is a third frontend

oxc-mcp’s tool handlers are to RuntimeService what oxc-serve’s HTTP handlers are: thin framing over dispatch_*_core + explain_fork_fact_proof, minus axum, plus the authoring tools. The backend is RuntimeService precisely because it carries reload_if_changed/spawn_watch_task, the governor, per-scope mutation locks, cursor pagination, and the fork lifecycle. The bare Connection has no reload — using it would reintroduce source/artifact incoherence and duplicate reload logic. One McpError(ConnectionError) newtype (to satisfy the orphan rule), symmetric to serve’s ApiError.

D3 — Two profiles, one tool surface

  • Local = RuntimeService (in-memory storage, watching target/<pkg>.oxbin) + oxc-workspace — the full authoring and runtime surface, coherent by construction; what a coding agent uses.
  • Remote = a /v1 HTTP client against a deployed ox runtime serve (the Connection::Remote impl, RFD 0052 D2) — runtime read/introspect only (you do not author against a deployed knowledge base), gaining admission + crash isolation from the separate process.

These are profiles, not maturity levels — the tool surface is one surface; a profile determines which tools are live. The agent learns which surface is available via argon_status.

D4 — The coherence invariant (the spine)

Source, artifact, and served module are kept coherent by construction, never guessed:

  • argon_build writes the .oxbin, then explicitly calls reload_if_changed before returning (deterministic — it does not rely on the watch debounce); the watch task is a backstop.
  • Every runtime result is stamped with the serving module_hash.
  • argon_status exposes {loaded_module_hash, on_disk_oxbin_hash, source_dirty, fork, as_of, limits, capabilities} so staleness is observable, never inferred.
  • An invalidating schema swap against a live ABox refuses loudly — structured schema_incompatible / needs_rebuild — never a crash, never a silent re-type.

The primitives (content_hash, module_hash, lockfile hashes) already exist; D4 composes them into a stated invariant.

(As-built: the dirty check is a content-hash of the build inputs — a blake3 digest over every *.ar under the project PLUS ox.toml / ox.lock (the prelude / dependency surface that changes the artifact without touching an .ar), compared to the digest captured at the last build. It is unsound-safe: an unreadable input fails TOWARD dirty, never silently clean. The first cut’s mtime proxy was racy and blind to ox.toml/lockfile edits — replaced. argon_build verifies active_module_hash == built_hash after reload rather than trusting reload_if_changed silently. A dirty runtime tool auto-builds (DirtyPolicy), or refuses with a structured DIRTY_WORKSPACE / NO_ARTIFACT result naming the next step.)

D5 — Governor: reuse, do not rebuild

The MCP server configures the existing OperabilityLimits (a tighter row cap to protect agent context) and adds per-call cancellation. It does not import AdmissionControl — multi-tenant concurrency fairness is inert and unneeded for a single stdio client. The row cap refuses loudly over the limit (the loud-gate philosophy applied to result size); it never truncates.

D6 — Pagination: ride the full DispatchRequest

Cursor pagination over query rows already exists (DispatchRequest.page, R-M17/#259); only the Connection::query convenience omits it. Riding RuntimeService + the full DispatchRequest gets paging for free. Over-cap unpaged reads refuse loudly — never truncate.

D7 — Error model: domain outcomes are successful results

Domain outcomes — check found violations, an ad-hoc body is ill-typed, a query is empty, a fact is not derived — are successful tool results (isError:false) carrying structured payloads. McpError is reserved for “couldn’t run.” Surfaced payloads carry stable, machine-readable fields: stale_artifact, needs_build, limit_exceeded, capability_required, diagnostic_codes, retryable.

(As-built: the split is exactly this — McpError is a newtype over oxc_connection::ConnectionError (orphan rule), mapping the core’s status / code / message / details onto rmcp’s ErrorData; everything else returns Ok(CallToolResult) with a structured payload (needs_build, stale_artifact, diagnostic_codes, limit_exceeded, truncated, …). A row-cap overflow (ARGON_RUNTIME_RESULT_TOO_LARGE), a derive of an underivable head (ARGON_RUNTIME_DERIVE_FAILED), an ad-hoc type error, and a check delta-guard rejection (ARGON_RUNTIME_CHECK_VIOLATION) are all domain outcomes, not errors. capability_required / retryable are reserved for the gated fork / Remote surfaces.)

D8 — ProofTree folding

A recursive derivation branches exponentially, so explain_fact returns a bounded projection — the root plus the first N inference levels, each unexpanded subtree carrying a stable node-id — plus an expand_proof(node_id) tool for depth on demand. Never naive full serialization.

D9 — Teaching lives in the diagnostic catalog, not in the server

Enrich the loud-gate codes (OE13xx, OE1317) with actionable, fix-class remediation in the single-source catalog (grammar.d) → CLI (ox explain), LSP, and MCP all benefit; the argon_check payload inlines them. The loud-gate sequence (an agent will not infer it from tool descriptions alone) is encoded in the server instructions field and in the argon_authoring_loop / argon_diagnose_absence prompts.

D10 — Write model: ephemeral fork first-class, promotion built correctly

The ephemeral fork (create → mutate test facts → query/derive/explain → auto-abort, never promotes) is read-shaped, safe, and first-class — the hypothetical-reasoning / rule-testing primitive. Promote-to-main is built correctly, not omitted: fork_diff summarizes in domain terms; promotion is capability-gated per-call with an unmistakable state indicator, carrying conflict behavior + provenance. The fork machinery already exists in RuntimeService.

D11 — why unification

explain_fact already returns a structured ProofTree for data facts; the check-violation why is currently prose (render_violation_why). Unify the check-violation why to the same structured trace shape (violated rule/constraint id, involved declarations, premise facts, spans) plus a prose rendering — one provenance model, two entry points. This is a real build item in oxc-runtime’s check-explanation path, not an MCP veneer.

D12 — Negative provenance: an honest boundary

“Why did X not derive / why is this query empty” is where ontology authors live, and real why-not provenance does not exist (RFD 0046 marks it open/out-of-scope; explain returns a clean derived:false, root:None). Do not fake it. explain_fact reports derived:false distinctly (a membership answer, not an error); argon_diagnose_absence guides the decomposition with existing tools (confirm the rule is evaluable, derive each body predicate, explain each expected premise, check as_of/standpoint). Genuine why-not is the top runtime frontier (a reasoner feature, RFD 0046), outside this RFD’s remit.

D13 — Packaging

oxc-mcp is a crate (an rmcp server; a Backend trait with Local/Remote impls; an actor/mailbox serializing the non-Sync state with per-call cancellation; the coherence layer). ox mcp is a subcommand in oxc-driver mirroring ox lsp, shipped with the toolchain via oxup, editor-agnostic. A Claude Code plugin bundle (a manifest registering ox mcp + the prompts as a skill) is the reference distribution. The rmcp (official Rust MCP SDK) API must be verified at implementation time.

Tool, resource, and prompt surface

Names are snake_case, no dots (MCP-tool-name convention). This section is reconciled to the as-built oxc-mcp surface (the embedded stdio profile); where the implementation refined the original enumeration the delta is stated inline. The decisions D1–D13 stand; only the surface census moves.

Authoring (loud gate):

  • argon_check — the full check pipeline over SOURCE; structured diagnostics ({code, severity, message, range, fix?}). Runs even when no artifact is loaded (the repair on-ramp); binds the same full_package_diagnostics the LSP runs. (Fix-class remediation is whatever the single-source catalog carries per D9 — the payload inlines the catalog codes, it does not author its own.)
  • argon_build — compile to .oxbin behind the loud gate, atomically write, reload, and verify active_module_hash == built_hash; returns {ok, moduleHash, wroteOxbin, gateFailures, message}. A gate failure is a domain outcome, not an error.
  • argon_status — the staleness probe: loaded vs on-disk module hash, sourceDirty, artifactLoaded, the paths.
  • argon_test — test-mode build; reports whether the test-bearing artifact compiled (the loud test gate).

Runtime read (full Truth4 envelope):

  • argon_query — a declared query; bitemporal as_of; cursor-paged; returns the FULL four-valued (Truth4) envelope (per-row truth, hidden K3 counts). Federation is driven by the query’s declared across [...] clause — there is no per-call across override (it is not on the lifted dispatch core, so exposing one would be a false affordance).
  • argon_ad_hoc_query — an RFD 0033 body (source string), type-checked against the loaded module or refused; full Truth4.
  • argon_derive — materialize a derived extent; full Truth4 envelope, optional per-tuple proof tags.
  • argon_scenario_run — materialize the whole derived model once and project every head in the FULL Truth4 envelope ({projection, factsDerived, facts:[{head, tuple, truth4, hidden}], hidden}). A scenario materializes only definite-Is facts (foreign connectors hard-refused; across / enumerate heads held separately; defeat planes 2-valued), so each fact carries truth4:"Is" and hidden is all-zero — the tag makes “all-Is by construction” legible rather than leaving the agent unable to tell it from an envelope-stripped read. projectK3:true renders the bare {head, tuple}. (As-built rename of the RFD’s argon_snapshot: the tool runs the scenario’s full derivation, not a paged store dump — the name now says what it does. Deliberately a tool, not a standing resource, as the RFD intended. The full-Truth4 envelope is single-sourced in the MCP renderer over the shared core derived_snapshot_value — the /v1/snapshot flat shape is unchanged.)
  • argon_explain_fact — the full structural AND/OR ProofTree for one fact (live read-point only); maxDepth folds the tree. A not-derived fact returns derived:false plus a whyNot negative-provenance tree — an honest membership answer (D12), not a synthesized why-not.
  • argon_expand_proof — re-reconstruct a fact’s proof at a larger maxDepth to drill past a folded marker (D8). (As-built: folding is by depth, not by per-node id — maxDepth is the stable handle; same reconstruction as explain_fact.)
  • argon_checks_current — evaluate the module’s checks against current state (optionally one by name); returns the violation set + clean.
  • argon_why — glass-box runtime check violations: evaluate the scope’s checks and return the firings. (As-built: the D11 unification — a single structured check-violation provenance shape in oxc-runtime, prose + structured trace — is NOT what shipped here. argon_why returns the structured firing set the runtime already produces; the deeper D11 build item in oxc-runtime is a follow-on, see “Gated / follow-on”.)

Write (full check-guard pipeline):

  • argon_mutate — a declared mutation; returns the receipt, minted entities, and the RFD 0046 D2 derived delta ({added, removed} per head, when includeDerivedDelta is set) + observe-channel diagnostics. A check delta-guard rejection (ARGON_RUNTIME_CHECK_VIOLATION) is a structured domain refusal — atomic, nothing persisted — not an error.
  • argon_ad_hoc_mutate — an RFD 0033 mutate body (source string), type-checked then executed and persisted through the SAME RFD 0025 check delta-guard pipeline as a declared mutation.
  • argon_batch — an ordered array of declared mutations executed ALL-OR-NOTHING in ONE per-scope critical section (step N sees steps 0..N), persisted in one transaction. A mid-batch check-guard violation rolls back the WHOLE batch — nothing persisted — surfaced as a structured domain refusal carrying the failing step’s 0-based batchStep. Rides RuntimeService::run_batch (lifted by #1205), with the step projection single-sourced in oxc_connection::render_batch so the /v1/batch and MCP surfaces cannot drift.

Compute (pull-plane evaluation):

  • argon_compute — evaluate a declared compute fn over the scope’s committed state (optional bitemporal as_of); returns {value, emissions, moduleHash}. A top-level payloadless enum constant renders {tag} (RFD 0027 D5). Rides RuntimeService::run_compute (lifted by #1205), with the value projection single-sourced in oxc_connection::render_compute (the same /v1 compute render, byte-for-byte).

Discovery / introspection:

  • argon_schema_lookup — look up a concept / relation / query / mutation / check by qualified path or short name, or the whole schema index, from the loaded module (scoped — never an unfiltered whole-TBox dump). (As-built: this folds in the RFD’s separate argon_list_queries + argon_describe_query — one name-or-index lookup over the schema covers list-all and describe-one.)
  • argon_epistemics — the per-construct epistemic profile: decidability tiers + standpoint lattice from the loaded artifact, construct filters to one name. (As-built addition: the tool-shaped read over the tier/standpoint surfaces the RFD only exposed as resources.)

The complete as-built tool census is eighteen: argon_check, argon_build, argon_status, argon_query, argon_derive, argon_mutate, argon_batch, argon_compute, argon_ad_hoc_query, argon_ad_hoc_mutate, argon_explain_fact, argon_expand_proof, argon_why, argon_checks_current, argon_scenario_run, argon_test, argon_epistemics, argon_schema_lookup.

Resources (stable, addressable; routed through the ArgonRuntimeHandle trait, not a local file read, so a future Remote impl serves them identically):

  • argon://diagnostics/catalog — the whole OE#### catalog (every code, severity, description, long-form explanation, reserved flag); the agent’s authority on what a code MEANS, sourced from the same OxcDiagnosticCode the compiler emits.
  • argon://diagnostics/{code} — a template: one code’s entry.
  • argon://schema/index — the loaded module’s schema index. (As-built: a single scoped index resource, not the RFD’s argon://schema/{path} per-path template — per-construct lookup is the argon_schema_lookup tool’s job; the resource is the index.)
  • argon://standpoints — the standpoint lattice (artifact standpoint-lattice section, §D.7).
  • argon://tiers — the decidability tier table (artifact tier-table section, §D.8).
  • argon://module — the active artifact’s load status + module hash. (As-built rename of the RFD’s argon://module “manifest + hashes”.)

Five resources + one template. As the RFD intended: not current-diagnostics (that is argon_check output), not the derived snapshot (that is argon_scenario_run).

Prompts (investigation playbooks; each written so the agent drives the full epistemic state, not the K3 projection, and respects the loud-gate build loop):

  • argon_investigate_fact — is this fact derived, and why / why-not? Drives argon_statusargon_explain_factargon_expand_proof, reading every row’s truth4.
  • argon_diagnose_absence — the counter-abduction loop: a query is empty / a fact is missing; inspect the hidden Can/Both counts first, then derive, explain a representative missing tuple, and propose the smallest base-fact change as a type-checked argon_ad_hoc_mutate for a human to confirm.
  • argon_audit_mutation — what would this write change (the D2 derived delta) and does it cross any check? Drives argon_mutate with includeDerivedDelta and argon_why on a refusal.

(As-built delta: three prompts — the RFD named argon_authoring_loop + argon_diagnose_absence. argon_authoring_loop is subsumed by the server instructions field, which states the loud-gate sequence verbatim; the three shipped prompts are the runtime-investigation playbooks D1 leads with — fact-provenance, absence-diagnosis, write-audit.)

Gated / follow-on (NOT in the as-built surface)

  • Remote (/v1 client) profile + streamable-HTTP transport. The backend is the ArgonRuntimeHandle trait precisely so a Remote impl slots in without reworking a handler, but it is NOT built — it is gated on the open coordination-model decision (how an agent’s scope/principal binds to a remote deployment, an Open question below). The as-built ships the embedded stdio profile only; D3’s two-profile design stands, one profile is live.
  • Fork lifecycle (argon_fork_create / _mutate / _query / _derive / _explain / _diff / _abort / _promote, D10). Forks are NOT on the transport-neutral RuntimeService surface the #1205 dispatch lift exposed — fork orchestration lives on the embedded oxc_connection::Connection and as serve-private /v1 handlers (exactly as query dispatch did before #1205). Wiring forks here would mean reimplementing that orchestration; instead it is a follow-on needing a fork-orchestration lift (analogous to #1205) plus the coordination-model decision. D10’s write model stands as design; the live surface is the declared/ad-hoc argon_mutate write path.
  • Structured check-violation why in oxc-runtime (D11). argon_why ships glass-boxing the runtime’s existing firing set; the deeper D11 build item — one unified structured trace shape (prose + structured) shared by explain_fact and the check-violation why — is a real oxc-runtime item, still to land.
  • Claude Code plugin bundle (D13). ox mcp ships with the toolchain; the reference plugin manifest registering ox mcp + the prompts as a skill is a follow-on distribution artifact.

Concurrency and isolation

(As-built reconciliation: the #1205 dispatch lift made RuntimeService Clone + Send + Sync, so the planned actor/mailbox is unnecessary — the backend holds the service directly and the rmcp handler tasks call the lifted run_query / run_mutation / run_compute / run_batch orchestration against it; the service is internally synchronized. Read-only runtime ops never hold the ServiceState lock across the CPU-bound reasoner: they take a brief guard only to deep_clone the scope store, drop it, and reason against the clone — the snapshot-then-reason discipline the serve foreign-read path uses. Only the ad-hoc mutate path holds the write guard, serialized per scope. The single-stdio-client profile means there is no second agent session to race the backend; the project-root lockfile / co-resident-LSP-watch interaction folds into the still-open watch question below. Panic isolation at the handler boundary remains the intent for the eventual Remote/HTTP profile.)

Rationale

  • A third frontend, not a new runtime. The dispatch core is already transport-agnostic (RFD 0014); the only honest place for an agent surface is beside the HTTP layer, over the same dispatch_*_core. Anything else duplicates runtime logic and invites drift.
  • RuntimeService, because coherence is the hard part. The reason to ride RuntimeService rather than the bare Connection is exactly D4: reload, the governor, mutation locks, paging, forks. Building on the embedder path would mean re-implementing reload — and the first re-implementation that drifts is a silent stale-KB bug, the worst failure mode for an agent that trusts what it queries.
  • The runtime is the value the agent cannot otherwise reach. An editor-agent already has the check loop via LSP. What it does not have is structured provenance, bitemporal reads, n-ary relations, forks, and standpoints. Leading with the runtime (D1) is what makes this surface worth building rather than a re-skin of ox lsp.
  • Honesty over a faked feature. Why-not provenance is where authors live, and it does not exist (D12). The disciplined move is to report derived:false precisely and guide the decomposition with the tools that do exist — not to synthesize a plausible-looking explanation the substrate cannot back. Genuine why-not is named as the top runtime frontier, not quietly skipped.
  • Reuse the loud-gate everywhere. The governor, the catalog, the ProofTree model, the fork machinery, paging — all exist. The server configures and frames them (D5, D6, D8, D9, D10); the only genuinely new build items are the framing layer, the coherence stamping (D4), and the structured check-violation why (D11).

Alternatives considered

  • Build on the bare embedded Connection (the Tide / RFD 0052 path). Rejected: it has no reload, so the server would either re-implement reload_if_changed (duplicate logic, the drift risk above) or serve a stale module. RuntimeService already owns coherence.
  • Author-against-remote (a uniform read+write surface across both profiles). Rejected: you do not author against a deployed knowledge base. The remote profile is read/introspect only (D3); authoring is inherently local where source, build, and reload are co-located.
  • Maturity levels (a v1 read-only surface, write later) rather than profiles. Rejected: the full surface above is committed scope. Local vs. remote is a capability distinction (what is live where), not a phasing of ambition; the fork write model (D10) is part of the design, not a deferred tier.
  • Fake why-not provenance (synthesize a “why empty” explanation). Rejected on honesty grounds (D12): the substrate cannot back it (RFD 0046 open). A confident wrong explanation is worse than a precise derived:false plus a guided decomposition.
  • Naive full ProofTree serialization. Rejected: a recursive derivation branches exponentially and would blow the agent’s context. Bounded projection + lazy expand_proof (D8) is the only viable shape.
  • Teach the loud-gate inside the server (tool descriptions, hardcoded prose). Rejected: teaching belongs in the single-source catalog (D9) so CLI, LSP, and MCP share it; duplicating it in the server is a second source that drifts.

Consequences

  • The agent lane is filled by a frontend, not a fork of the runtime. oxc-mcp couples to RuntimeService + dispatch_*_core exactly as oxc-serve does; the runtime stays one runtime.
  • A new committed build item lands in oxc-runtime: the structured check-violation why (D11) unifies the two provenance entry points — it is not MCP-only.
  • The diagnostic catalog gains fix-class remediation on the loud-gate codes (D9), improving ox explain and LSP, not only MCP.
  • ox mcp ships with the toolchain via oxup, editor-agnostic, with a Claude Code plugin bundle as the reference distribution.
  • Why-not provenance is named as the top runtime frontier (D12), scoped out of this RFD and to RFD 0046 — a legible boundary, not a silent gap.
  • This RFD is a design record. State discussion: it fixes the design rationale, not the implementation. The embedded stdio profile (increments 1–5, the read/write/introspect surface above) is built — oxc-mcp / ox mcp ship the eighteen-tool surface, five resources + one template, and three prompts reconciled above; the Remote profile, the live fork lifecycle (increments 6–7), the D11 structured check-violation why, and the Claude Code plugin bundle are the gated follow-ons. The build order below is the committed delivery shape; the surface section is reconciled to what is live.

Build order (delivery increments — the full surface above is committed scope, not a v1 subset)

  1. oxc-mcp skeleton + Backend (Local = RuntimeService + workspace) + actor + McpError + argon_status / coherence stamping.
  2. Authoring tools + catalog fix-class enrichment + inlined remediation + server instructions/prompts.
  3. Runtime read tools with paging + governor config + cancellation.
  4. explain_fact + ProofTree folding + expand_proof; structured check-violation why in oxc-runtime.
  5. Discovery tools + schema/catalog resource templates.
  6. Fork model (ephemeral + capability-gated promote with diff-summary).
  7. Remote backend profile + ox mcp subcommand + Claude Code plugin bundle.

Open questions

  • The exact rmcp API. The official Rust MCP SDK surface (server construction, tool/resource/prompt registration, the stdio transport, cancellation) must be verified against the SDK at implementation time; the decisions above are framing-level and SDK-version-independent.
  • The capability mechanism for argon_fork_promote. Per-call capability gating (D10) needs a concrete carrier — an explicit confirmation argument, a session capability grant, or a config-time enable — settled when increment 6 lands.
  • The row-cap default for the agent profile (D5). “Tighter than serve’s, to protect agent context” needs a measured default against real agent context budgets.
  • Where the project-root lockfile lives and how it interacts with ox lsp’s own watch. Two frontends (LSP + MCP) may watch the same target/<pkg>.oxbin; the lockfile (concurrency / isolation §) must not deadlock a co-resident editor session.

This design was hardened by a multi-model adversarial review — decorrelated critique across heterogeneous providers — which shaped the decisions above (notably the RuntimeService-not-Connection backend, the coherence invariant, and the honest why-not boundary).