CodeTwin is organised as a Cargo workspace. Each crate has one job and a narrow public surface. New crates are added when a real seam appears (two adapters, not one).
| Crate | Role | Depends on |
|---|---|---|
codetwin |
Published binary. main.rs only — parse argv, init tracing, dispatch. |
codetwin-cli (eventually); codetwin-legacy (today) |
codetwin-cli |
clap-derived CLI surface and subcommand dispatch. |
codetwin-config, codetwin-pipeline |
codetwin-pipeline |
Orchestration: discover → parse → merge → render → write. Owns snapshot, diff, watch. | codetwin-ir, codetwin-config, codetwin-drivers, codetwin-render |
codetwin-render |
Markdown / Mermaid builders and the Layout trait + built-in layouts. |
codetwin-ir |
codetwin-drivers |
Driver trait, auto-detection registry, and per-language tree-sitter drivers. |
codetwin-ir |
codetwin-config |
codetwin.toml schema + loader + override merging. |
(leaf) |
codetwin-ir |
Intermediate representation: CodeModel, Module, Symbol, Edge. |
(leaf) |
codetwin-legacy |
Transitional. Holds the pre-workspace monolith while modules migrate out. | (everything the monolith did) |
codetwin (bin)
└── codetwin-legacy ← today
└── (will become)
codetwin-cli
└── codetwin-pipeline
├── codetwin-render ──┐
├── codetwin-drivers ─┼── codetwin-ir
└── codetwin-config ┘
Edges only point downward. A leaf crate must never depend on a higher-level one. Adding an upward edge needs an explicit ADR.
codetwin-<role>. The bin keeps the
bare name codetwin because that is what users install.codetwin_ir, etc.) — Rust requirement.Cargo.toml
via [workspace.package]. Releases bump every crate together.[workspace.dependencies] at the root,
inherited by members with { workspace = true }. Adding a new external
dependency is a workspace-level decision (see AGENTS.md §7).[workspace.dependencies] with path =
"...". Members reference them with { workspace = true }.codetwin is published. Every other crate sets
publish = false until we have a reason to expose it.crates/<name>/ with Cargo.toml + src/lib.rs.[workspace.dependencies] at the root.codetwin-legacy is being decomposed. As modules move out:
ir/ → codetwin-irconfig/ → codetwin-configdrivers/ → codetwin-driversrender/, layouts/ → codetwin-renderpipeline/, snapshot/, diff/, watch/ → codetwin-pipelinecli/ → codetwin-cliutil/ → folded into whichever crate uses it (no cross-cutting util crate)When codetwin-legacy is empty, delete it and switch the bin to depend on
codetwin-cli. Track in ROADMAP.md Phase 0.