ADR-022
Foundation crate layout v0.81: 14 crates, publish = false, 5 renames + extracts
accepted · 2026-04-16 · L0 L0.5 L4 · cites 11
0ADR-022: Foundation crate layout v0.81 #
Context #
After multi-agent architectural review (rust-architect + web-researcher SOTA
workspaces + rust-pro + Explore file audit, 2026-04-16), the v0.80 foundation
layout (10 crate plan, 7 in workspace) is replaced by a 14-crate layout with
strict tier discipline, publish = false strategy, and 5 structural changes.
Decision #
The 14-crate constellation #
L0-tier-0 (LEAVES — zero nika-* deps): nika-core [RENAME from nika-types] nika-macros [NEW proc-macro stub]L0-tier-1 (depend on tier-0): nika-error [DROP nika-types re-export facade] nika-envelope [NEW — apiVersion+Kind+Metadata+multi-doc+PckSpec]L0-tier-2 (depend on tier-0+1): nika-event [22 scoped sub-enums] nika-binding-transform [NEW — 65 pure transforms extracted] nika-catalog-codegen [extract from catalog/build.rs] nika-schema-ast [NEW — Raw + Analyzed AST types]L0-tier-3: nika-catalog [internal split data/models.rs + build/] nika-binding [template engine + dispatch] nika-schema [parser + analyzer + DAG + taint + jsonsubset]L0.5: nika-kernel [40 traits, NO split forever per ADR-006-amend] nika-kernel-mockL4: nika-catalog-verify [RELABEL from L0]`publish = false` for ALL foundation crates #
Every foundation crate (13 internal + 1 L4) carries publish = false. Only
nika (binary) and future nika-sdk ever ship to crates.io.
5 structural changes #
- Rename `nika-types` → `nika-core` (matches helix/bevy/ra/polkadot
convention;
[email protected]legacy on crates.io gets yanked) - Extract `nika-envelope` (single highest-ROI move — shared by 9 doc kinds)
- Drop `nika-error → nika_types::*` facade (re-export pollution gone with 0 users)
- Split `nika-schema` into 2 (
nika-schema-ast+nika-schema) — circular- dep concern from original spec was wrong (analyzer reads raw, writes analyzed) - Split `nika-binding` into 2 (
nika-binding-transform+nika-binding) — 65 pure transforms have known 2nd consumer (verb-exec basename)
`nika-pck-manifest` MERGES into `nika-envelope` #
A pck manifest IS an envelope document (Envelope<PckSpec>). Eliminates 1
crate, conceptually cleaner.
`nika-catalog-verify` RELABEL L0 → L4 #
Already does HTTP. Wrong layer assignment. Free fix.
`nika-macros` proc-macro stub now (empty) #
Per Agent 2 SOTA finding: every surveyed Rust workspace (rust-analyzer, biome,
ruff, uv, bevy, oxc) has a companion *_macros crate. Adding it later requires
L0 shuffle; adding empty now is free insurance.
Consequences #
- ✅ 14 crates with crystal-clear single-responsibility
- ✅ Tier discipline enables
cargo public-apisnapshots without churn - ✅
publish = falsefrees rename/refactor velocity forever - ✅ Renames legitimate (no users)
- ❌ ~7 commits of refactor work in Phase D (nuke + redo)
- ❌ Existing nika-types imports across all admitted crates need update (mechanical — find/replace + cargo check)
- ⚠️ The legacy
crates/nika-core/excluded directory (v0.79 main-leftover) must be deleted before the rename — handled in Phase D.1
Alternatives considered #
- Keep nika-types (no rename) — name is weak placeholder, every other improvement depends on knowing canonical name
- Split nika-schema into 4 (types + parser + analyzer + jsonsubset) — over-fragmented, 2 is the right number per cohesion analysis
- Polkadot-style 14 micro-crates for nika-core (nika-id, nika-cost, ...) — Q2 anti-pattern, no consumer-side benefit
- Publish all foundation crates — 0 users, no value, locks API surface prematurely
Reference #
~/.claude/.../memory/project_foundation_v081_constellation.md~/.claude/.../memory/feedback_publish_false_foundation_strategy.md
read at v0.107.0 · the decision record ships with the engine