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

ADR-0002: Rewrite Caproni in Rust as Xianyun

Status: accepted · Date: 2026-09-28 · Decision makers: James Hebden

Context and Problem Statement

Caproni is a Go CLI that orchestrates local Kubernetes development environments. The fork’s goal is narrower than the original: a developer-focused validation tool and verification driver that an AI agent can run in a loop, read structured results from, and act on without a person parsing terminal text in between. Go’s error strings and best-effort goroutines make that contract harder to guarantee than Rust’s typed errors and join-before-return task sets.

Behaviour that existing users depend on (config files, CLI surface, cluster profile names) has to survive the change.

Decision Drivers

  • Typed results and specific error variants that callers can match on
  • Concurrency with a guarantee that every supervised task finished before success is reported
  • A test-first compatibility contract: each ported behaviour has a test proving the same thing the Go test proved
  • Zero migration cost for existing caproni.yaml projects
  • Ability to build and test hermetically with Nix

Considered Options

  1. Rewrite in Rust as a new workspace beside the Go code, keeping the Go tree as the reference
  2. Keep Go and add a structured-output mode and an MCP server to the existing code
  3. Wrap the Go binary from a thin Rust or Python agent shim

Decision Outcome

Chosen option: “Rewrite in Rust beside the Go tree”, because the typed-error and concurrency properties are the point of the fork, and a wrapper (option 3) would inherit Go’s untyped failures. Option 2 is the cheapest, and its main weakness is that join-before-return and exhaustive error matching are conventions in Go rather than properties of the language.

The rewrite proceeds in phases: port the Go test suite as ignored tests (red), implement crate by crate until they pass (green), then add agent-first interface work (structured output, tool surface) once behavioural parity is solid.

Consequences

Good:

  • On Linux, 1,119 tests pass, 0 fail, and 23 are ignored (measured 2026-10-13 with cargo test --workspace); 22 of the ignored have a documented reason and one, compile_schema_lazy_loading, is an unimplemented! stub
  • The MCP server, typed errors, and JoinSet supervision in xianyun run were possible because of the rewrite

Bad:

  • Two implementations live in one repository. Documentation still describes the Go binary almost everywhere (see the all-aboard report for the list).
  • Parity isn’t complete: edit-mode-process-supervisor is a stub; doctor has 2 of the Go tool’s 5 diagnostics.
  • The serde_yaml crate used for parsing is deprecated

Neutral:

  • The binary was renamed from caproni to xianyun; see ADR-0003

Implementation Location

  • crates/xianyun-core/src/lib.rs
  • crates/xianyun-cli/src/main.rs
  • crates/README.md
  • book/src/project/vision.md

More Information

  • Retroactively documented on 2026-10-13. The date is that of the first workspace commit, feat(rust-rewrite): scaffold Xianyun Rust workspace.
  • Related: FR-001, NFR-001, ADR-0018 (the Go tool’s telemetry wasn’t carried over).