Skip to main content
Nika follows real semver toward 1.0. Features ship incrementally across 1.x minors over years. The 1.0 architecture must accommodate later minors (memory subsystem, agent-v2; WASM plugins, observability), and features we haven’t imagined without breaking changes to the public API.
Status: LOCKED at v0.80. Every crate admitted to the Diamond workspace must comply before passing Gate 12. Patterns distilled from Rust (2015→), Tokio (0.1→1.x), Deno, Cargo, Serde (9+ years stable), Axum/Tower, Bevy.Canonical source: docs/architecture/forward-compat-invariants.md.

The 8 patterns

Define traits in nika-kernel at v0.90 for subsystems that ship later. Default methods return Err(Unsupported) until real implementations land.
Locked traits (v0.90): MemoryStore, EmbeddingProvider, ToolExecutor, WasmPluginHost, MetricsExporter + TracerProvider + AuditSink + EventSink + BillingSink, Sandbox. Stubs in src/plugin/, src/infra/.Impact: v0.95 lights up the memory subsystem by adding nika-memory-oxigraph that implements MemoryStore. Zero v0.90 code modification.
Every public type carries #[non_exhaustive] so adding a field or variant is always additive. new() constructors provide ergonomic construction without exposing struct literal syntax.
Invariant #19: every #[non_exhaustive] struct ships a new() constructor.
A workflow pins its contract with one header line · nika: v1 (a single version marker · the language name as key, the contract version as value · supersedes the older K8s apiVersion: and schema: nika/workflow@X forms). Parsers reject any other value (v1.0 · v2 …) with a clear error.
illustration · the envelope pin
v1 is the only value for the lifetime of the v1 contract: minor additions are additive and never change it. There is no nika: v2 — ever: pre-1.0 grammar changes happen inside v1 (the pre-1.0 stability contract) · after engine 1.0.0 the grammar is additive only. Non-workflow artifacts (package manifests, events) carry their own schema version field.
Public schemas reserve two namespaces: nika.* for core additions (authoritative, versioned) and x-* for community overlays (no stability guarantee, no collision with core). Scope note · in the workflow language both are RESERVED, not current: unknown top-level fields are rejected at v0.1, and the tool namespace set is closed at nika: / mcp: (engine-specific tools route through mcp:). The live x-* surface today is the pck registry.
illustration · RESERVED future extension fields (rejected today)
Two error surfaces, one rule each. The WORKFLOW-VISIBLE surface is the spec’s NIKA-<NAMESPACE>-<NNN> taxonomy ( registered codes across namespaces · reference/error-codes). Namespaces own 001-099 ranges, codes are never repurposed. The ENGINE-INTERNAL registry (nika_error::codes · NIKA-1000+ blocks per L1 effect crate) is diagnostics machinery: reserved per crate, never reassigned, and never leaked into workflow-visible errors.
Core kernel traits (e.g., Provider, EventSink, Sandbox) are sealed via a private supertrait: only Nika-owned crates can implement them. Extension traits (e.g., MemoryStore) are open for community crates to implement.
Enforced by ADR-014.
New capability = new feature flag, OFF by default. After 1-2 minor cycles of stability, flips to default-ON. Never remove a default feature (breaking change): deprecate and redirect.
Three tools on every CI run:
  • cargo public-api: detects API surface changes per crate.
  • cargo semver-checks: verifies SemVer compatibility.
  • cargo deny: enforces license + advisories + layer bans.
Gate 12 fails on any unintentional public API drift. .public-api.json snapshots are checked into the repo per crate.

The 5 locked decisions (v0.80)

The 10 rules

Every crate admission answers “yes” to each. cargo public-api + cargo semver-checks catch violations before merge.
  1. All public types carry #[non_exhaustive].
  2. All public structs with #[non_exhaustive] ship a new() constructor.
  3. All async trait methods use trait_variant::make for dynamic dispatch.
  4. All core traits seal via private supertrait.
  5. All error types expose a NIKA-XXX code via NikaError::code().
  6. All on-disk schemas carry schema: "nika/<kind>@<major>".
  7. All DTO fields reserve forward-compat extension slots (see FCI-010).
  8. All feature flags default to a stable subset: new caps ship OFF.
  9. All public API changes emit a cargo public-api diff in the PR.
  10. All breaking changes require ADR Accepted before merge.

See also

Layer registry

Six layers + L0.5, mechanical sort test, security axes.

L0 foundation decisions

Q1-Q13 locked 2026-04-16: proc macros, kernel prelude, transform crate, memory sinks.

12-gate admission

How a crate earns a seat at the workspace: SPEC through ATOMIC commit.

ADR index

35 decision records (30 Accepted + 5 Proposed).