Skip to main content
Nika Diamond is admitted crates organized into six layers, with a half-layer (L0.5) for trait-only crates. Every workspace-local dependency points strictly downward. A CI script (check-layering.sh) fails the build on any upward import.
Canonical source: docs/architecture/crate-layer-registry.md. This page curates the layer model for readers; the authoritative manifest lives in the engine repo next to the enforcement script.

Mechanical sort test

Every new crate answers these questions in order. First hit wins.
1

Does it produce the `nika` binary?

L5 (the binary)
2

Does it expose a transport / UI surface (CLI, HTTP, MCP, LSP, SDK)?

L4 (interfaces)
3

Does it enforce runtime policy, sandboxing, or orchestration?

L3 (runtime + policy + sandbox)
4

Does it implement a verb or a domain service?

L2 (verbs + services)
5

Is it a primitive with I/O (fs, net, exec, env)?

L1 (effect impls)
6

None of the above?

L0 (pure, sync, zero I/O). If it’s trait-only but async is OK, → L0.5.

The pyramid

Arrows read “depends on”. Upward arrows are forbidden: check-layering.sh fails on any workspace-local dep that points up.

Layer table

nika-http is the L1 HTTP client (used by fetch / catalog sync). The HTTP server surface of nika serve lives inline inside nika-serve L4: no separate server crate.

Admitted today (v)

nika-types

L0 · Foundation value types. Leaf of the DAG.

nika-error

L0 · NIKA-XXX error hierarchy + miette integration.

nika-catalog

L0 · Provider / capability TOML catalog, phf lookup.

nika-kernel

L0.5 · 40 ISP traits, sealed supertrait, prelude re-export hub.

nika-kernel-mock

L0.5 · Pure-memory trait mocks for testing.

nika-catalog-verify

L4 · Build-only catalog validation tool.
WIP: nika-schema (parser scaffolding, Round 4 admission gate).

Security axes

Every L1 crate declares the capabilities it exercises in docs/architecture/security-axes.toml. Reserving an axis costs nothing today and forbids its silent later use.
Three CI vectors enforce layer discipline:
  • check-layering.sh (hygiene vector 11, P0, fail on violation): reads layer membership from [workspace.metadata.diamond.layers] and verifies every workspace-local dependency is equal or lower layer.
  • check-security-axes.sh (vector 12, P1): cross-checks declared axes against static analysis of the source tree.
  • check-no-async-in-l0.sh (vector 16, P1): greps async fn / async { in L0 source trees; fails on any match.

Forward compatibility

  • The Connectome: 1 L2 orchestrator (nika-connectome) + 10 L1 satellites (hnsw, bm25, rrf, rerank, fsrs, rdfs-reasoner, temporal, graph-algos, autodesc-minimal, autodesc-full). No renumber: they slot into L1 / L2 naturally.
  • v0.100 WASM plugin host + sandbox: L3 crates alongside nika-runtime. No renumber.

Anti-patterns

Seven patterns that tank the layer contract. If you catch yourself writing one, stop and re-ask the mechanical sort test.
  1. Kitchen-sink crate: “I’ll just add this utility to nika-error” leads to a 10k-LOC bag-of-tricks every crate transitively pulls in. One caller = stays in the caller.
  2. Facade mega-crate: “Re-export everything from nika for convenience” collapses the layer contract and tanks compile time.
  3. Upward re-exports: an L1 crate pub use nika_pck::... turns its API into an L2 consumer and breaks mechanical sorting.
  4. async in L0: forces a runtime choice on every L1 / L2 consumer; makes the crate unusable in build scripts.
  5. anyhow::Error in library code: L5 binary only. L0..L4 uses the typed error hierarchy.
  6. Box<dyn Error> in public API: hygiene vector 19 bans it. Swap to the typed error hierarchy.
  7. Runtime imports in L0: tokio::spawn in nika-error is a layer violation even if it compiles.

See also