[workspace] resolver = "3" members = ["crates/nika-types", "crates/nika-error", "crates/nika-catalog", "crates/nika-catalog-codegen", "crates/nika-catalog-verify", "crates/nika-chart", "crates/nika-cadence", "crates/nika-arm", "crates/nika-kernel", "crates/nika-kernel-ai", "crates/nika-kernel-core", "crates/nika-kernel-runtime", "crates/nika-kernel-plugin", "crates/nika-kernel-mock", "crates/nika-schema", "crates/nika-check", "crates/nika-check-analyzer", "crates/nika-check-wasm", "crates/nika-source", "crates/nika-store", "crates/nika-vocab", "crates/nika-lints", "crates/nika-graph", "crates/nika-bm25", "crates/nika-screen", "crates/nika-event", "crates/nika-extract", "crates/nika-exec-runner", "crates/nika-sandbox-seatbelt", "crates/nika-sandbox-landlock", "crates/nika-blob", "crates/nika-clock", "crates/nika-fs", "crates/nika-fx", "crates/nika-http", "crates/nika-ocr", "crates/nika-a11y", "crates/nika-input", "crates/nika-browser", "crates/nika-pack", "crates/nika-proof", "crates/nika-providers", "crates/nika-providers-access", "crates/nika-infer-local", "crates/nika-verb-infer", "crates/nika-verb-exec", "crates/nika-verb-invoke", "crates/nika-verb-agent", "crates/nika-builtin", "crates/nika-cel", "crates/nika-registry-client", "crates/nika-runtime", "crates/nika-runtime-laws", "crates/nika-execution", "crates/nika-service-execution", "crates/nika-cli", "crates/nika-cli-host", "crates/nika-cli-host-typesafe", "crates/nika-session", "crates/nika-session-change", "crates/nika-session-agent", "crates/nika-session-host", "crates/nika-session-intelligence", "crates/nika-trace", "crates/nika-tui-core", "crates/nika-tui", "crates/nika-tui-view", "crates/nika-lsp", "crates/nika-mcp", "crates/nika-dap", "crates/nika-display", "crates/nika-onboard", "crates/nika-onboard-knowledge", "crates/nika-compile", "crates/nika-compile-reader", "crates/nika-compile-cognition", "crates/nika-compile-fidelity", "crates/nika-compile-trigger", "crates/nika-compile-clauses", "crates/nika-compile-seats", "crates/nika-compile-behavior", "crates/nika-models", "crates/nika-cap", "crates/nika-pck-manifest", "crates/nika-tmpl", "crates/nika-migrate", "crates/nika-harness", "crates/nika-secret", "crates/nika-dataflow", "crates/nika-serve"] # Excluded so cargo does not try to descend into untracked main-leftover # manifests under crates/ (the orphan working tree carries them but they # are not part of the diamond workspace). exclude = [ "crates/nika-acp", "crates/nika-core", "crates/nika-daemon", "crates/nika-display", "crates/nika-engine", "crates/nika-init", "crates/nika-lsp-core", "crates/nika-macros", "crates/nika-media", "crates/nika-policy", "crates/nika-sdk", "crates/nika-security", "crates/nika-storage", "crates/nika-vault", "crates/nika-verb-fetch", "crates/nika", ] [workspace.package] version = "0.124.3" edition = "2024" license = "AGPL-3.0-or-later" authors = ["Thibaut Melen "] rust-version = "1.91" repository = "https://github.com/supernovae-st/nika" homepage = "https://supernovae.studio" # ───────────────────────────────────────────────────────────────────────────── # Diamond layer assignments — enforced by scripts/ci/check-layering.sh. # L0 = zero I/O, zero async. L0.5 = trait-only. L4 = interface crates. # See docs/architecture/crate-layer-registry.md for the full discipline. # ───────────────────────────────────────────────────────────────────────────── [workspace.metadata.diamond] # WIP crates: in the workspace but pre-admission (no complete 12-gate table # yet). SINGLE SOURCE for the admitted-vs-WIP split — scripts/crate-metrics.sh # is the projector that reads this; refresh-status.sh + check-crate-specs.sh # query the projector (never re-hardcode the list). When a crate is admitted, # remove it from this array — one edit, here, period. wip = ["nika-chart", "nika-fx", "nika-proof", "nika-store", "nika-harness", "nika-execution", "nika-service-execution", "nika-serve", "nika-session", "nika-session-change", "nika-session-agent", "nika-session-host", "nika-session-intelligence", "nika-tui", "nika-tui-view"] # nika-pack · the embedded language pack (spec snapshot + manifest hashes · # proposal branch feat/nika-pack · pure data · include_dir · zero I/O). layers.nika-chart = "L0" # nika-chart · deterministic chart artifacts (CHT master plan · stdlib §Media # graduate #3 candidate · zero-dep · byte-identical SVG → trace chain). # nika-cadence · the arming-registry grammar (the arm: block of nika.yaml, # D-2026-08-10-N3) + the pure next-slot calculator · hand-counted 5-field # cron (zero cron library — the count is the TYPE) · embedded IANA tzdb · # the DST shift DECLARED in the Slot type (N1) · WIP (the 12-gate admission # lands at V3⑪ of the arming-registry plan). layers.nika-cadence = "L0" # nika-tui-core · the TUI session LAW (session model · derivation · plan # seating · claims) in one crate, native + WASM (D-2026-08-11-N6 · T28) · # the parity proof rides the studio's fixtures bit-exact · WIP (gates # 1-6+8 green · swarm + consumer swap owed). layers.nika-tui-core = "L4" # nika-tui · the Ratatui renderer of the session · inline-first · one terminal owner (ADR-139) layers.nika-tui = "L4" # nika-tui-view · the viewers of the object in view (pure · typed facts and bytes in, styled # lines out) · size-cap member of the nika-tui unit (D-2026-07-09-N1 · ADR-143 · 2026-09-30) · # lateral L4→L4 edge nika-tui → nika-tui-view, never back. layers.nika-tui-view = "L4" layers.nika-pack = "L0" # nika-proof · the spec-15 proof layer's hash primitives + the one receipt · # split from nika-runtime 2026-07-29 (the 15k crate-size cap · the # nika-dap/nika-cap precedent) · nika_runtime::proof re-exports it whole, so # every consumer path (`…::proof::{preimage, receipt, …}`) holds unchanged. layers.nika-proof = "L0" # nika-cli · the operator surface (D-2026-06-10-N6 first-15-min suite) · seeded # 2026-06-11 with the display fold + trace verbs per docs/crate-specs/nika-cli.md. layers.nika-cli = "L4" layers.nika-cli-host = "L4" # nika-cli-host-typesafe · the TypeSafe System One decision seat · size-cap member of the nika-cli # unit (D-2026-07-09-N1 · the ADR-110 amendment) · lateral L4→L4 edge nika-cli-host → # nika-cli-host-typesafe, never back. layers.nika-cli-host-typesafe = "L4" # nika-arm · the descriptor-rooted ARM custody and one firer shared by # the CLI and every later execution interface (ADR-114/117). layers.nika-arm = "L4" # nika-serve · the L4 remote execution projection. W05 admitted its durable # descriptor-rooted state plane; W06 stages authenticated loopback HTTP. # SSE, OpenAPI/SDK, and full crate admission remain later carriers. layers.nika-serve = "L4" # nika-trace · the flight-recorder reader (the trace verbs · evidence · # receipt · the learned-truth forecast · the bin's trace arm) · split from # nika-cli 2026-08-11 (the 15k crate-size cap · D-2026-07-09-N1 one unit, # two members · the ADR-110 cli-host precedent) — re-exported at the # historical verbs:: paths, so every consumer reads unchanged. layers.nika-trace = "L4" # nika-dap · the DAP replay server + the shared forensic seams (recover · # chain) · split from nika-cli's verbs/dap 2026-07-09 (the # crate-size cap · the nika-cap precedent) · source_id re-homed to # nika-event 2026-07-22 (the run-composer descent needed the hash at L≤3). layers.nika-dap = "L4" layers.nika-display = "L4" layers.nika-onboard = "L4" # nika-onboard-knowledge · the knowledge door: the strict admission of a Foundry release, the # embedded releases, the catalogue and the authoring pack · size-cap member of the nika-onboard # unit (D-2026-07-09-N1 · the ADR-137 amendment) · lateral L4→L4 edge nika-onboard → # nika-onboard-knowledge, never back. layers.nika-onboard-knowledge = "L4" # nika-compile · the stateless Compile core · size-cap member of the nika-onboard unit # (D-2026-07-09-N1 · ADR-137 · 2026-09-21) · lateral L4→L4 edge nika-onboard → nika-compile, # never back. layers.nika-compile = "L4" # nika-compile-reader · the frozen deterministic reader and the typed plan it produces · # size-cap member of the same unit (D-2026-07-09-N1 · the ADR-137 precedent · 2026-09-21) · # lateral L4→L4 edge nika-compile → nika-compile-reader, never back. layers.nika-compile-reader = "L4" # nika-compile-cognition · the seats' doors (COLD · native · sketch · transform · knowledge · # decision seats) · size-cap member of the same unit (D-2026-07-09-N1 · ADR-140 · 2026-09-23) · # lateral L4→L4 edges cognition → core, fidelity and reader; none points back to cognition. layers.nika-compile-cognition = "L4" # nika-compile-fidelity · the laws a candidate document is judged by, the seat's sketch and the # plan a candidate states · size-cap member of the same unit (D-2026-07-09-N1 · ADR-141 · # 2026-09-24) · lateral L4→L4 edges nika-compile → nika-compile-fidelity → nika-compile-reader, # never back. layers.nika-compile-fidelity = "L4" # nika-compile-trigger · the trigger reading of a request (its words, cadence, time of day, # multiples, cron fields and clause form) · size-cap member of the same unit (D-2026-07-09-N1 · # ADR-142 · 2026-09-30) · lateral L4→L4 edges nika-compile → nika-compile-trigger → # nika-compile-reader, never back. layers.nika-compile-trigger = "L4" # nika-compile-clauses · how one clause of a request reads above the reader (the parts a verifier # asks alone, the prohibition reading, the clause key, the stated spellings) · size-cap member of # the same unit (D-2026-07-09-N1 · ADR-145 · 2026-10-07) · lateral L4→L4 edges # nika-compile-cognition → nika-compile-clauses → nika-compile-reader, never back. layers.nika-compile-clauses = "L4" # nika-compile-seats · the decision seats and the rehearsal port a host lends a preparation, with # the reasoning record their calls share · size-cap member of the same unit (D-2026-07-09-N1 · # ADR-146 · 2026-10-07) · lateral L4→L4 edges nika-compile-cognition → nika-compile-seats → # nika-compile, never back. layers.nika-compile-seats = "L4" # nika-compile-behavior · the behavioural contract a request states and its typed judgment over # rehearsals, with the date-time shape classifier the judge and the candidate laws both read · # size-cap member of the same unit (D-2026-07-09-N1 · ADR-149 · 2026-10-09) · lateral L4→L4 # edges nika-compile-fidelity → nika-compile-behavior → nika-compile-reader, never back. layers.nika-compile-behavior = "L4" # nika-models · the local-models unit (ONE canonical dir · Hub pull · serve # glue) · split from nika-cli's verbs/model 2026-07-12 (the crate-size cap · # the nika-onboard/nika-display precedents). layers.nika-models = "L4" layers.nika-lsp = "L4" layers.nika-check-wasm = "L4" # nika-check-wasm · the static check surface compiled to the browser (parse + # conformance over nika-schema/nika-check · wasm-bindgen transport · # differential-gated vs the CLI · admitted ADR-107 · npm via the release train). # nika-mcp · the in-binary MCP server (announce floor `nika mcp`) · hand-rolled # newline-delimited JSON-RPC 2.0 over stdio (serde_json only · zero SDK) · # exposes the static read-only surface (nika_check · nika_explain) as MCP tools. layers.nika-mcp = "L4" # nika-session · the native session (bare `nika` on a terminal · ADR-125) · a host # runtime over the installed engine — the snapshot, the chosen intelligence, the # context broker, the hallucination guard — never a workflow. layers.nika-session = "L4" # nika-session-change · the project change a proposal writes, its review, its outcome and the # consent record · size-cap member of the nika-session unit (D-2026-07-09-N1 · ADR-144 · # 2026-10-06) · lateral L4→L4 edge nika-session → nika-session-change, never back. layers.nika-session-change = "L4" # nika-session-agent · the conversation the Session's selected intelligence leads: the loop over # one model and the Session's tools (no step, turn or token quota), the person's steering and # follow-up lines, the Session tree and its compaction · member of the nika-session unit # (ADR-153 · the ADR-144 pattern) · lateral L4→L4 edges nika-session → nika-session-agent → # nika-session-change, never back. layers.nika-session-agent = "L4" # nika-session-host · the native Session over a wire: one host adapter around the actual # SessionRuntime, its NDJSON machine door and its HTTP routes · size-cap member of the # nika-session unit (D-2026-07-09-N1 · ADR-144 pattern) · lateral L4→L4 edge # nika-session-host → nika-session, never back. layers.nika-session-host = "L4" # nika-session-intelligence · the intelligence a session reasons, routes and authors with: the # census and the choice, the reasoners, the line router and the authoring door (the seat, its # context and the round) · size-cap member of the nika-session unit (D-2026-07-09-N1 · ADR-150 · # 2026-10-09) · lateral L4→L4 edge nika-session → nika-session-intelligence, never back. layers.nika-session-intelligence = "L4" layers.nika-types = "L0" layers.nika-error = "L0" layers.nika-event = "L0" layers.nika-cap = "L0" layers.nika-pck-manifest = "L0" layers.nika-tmpl = "L0" layers.nika-clock = "L1" # nika-fs · Phase-B slice step 4 (announce ladder · D-2026-06-10-N6 cascade) · # implements kernel io::fs {FsRead,FsWrite,FsMeta,FsList} · tokio::fs + globset · # atomic write (temp+rename per kernel CANCEL SAFETY contract) · typed FsError # (Pattern A · FCI-023bis · NIKA-110..119). layers.nika-fs = "L1" # nika-fx · deterministic artistic image effects (dither · palette · duotone · # halftone · retro · glitch · ascii) · pure-algo zero-dep · byte-identical # artifacts (attested styled media) · behind nika:image_fx · FX master plan. layers.nika-fx = "L1" # nika-blob · Phase-B slice step 6 (announce ladder · D-2026-06-10-N6 cascade) · # implements kernel io::blob BlobStore via blake3 CAS · sharded fs layout · # atomic temp+rename (unique temp) · sidecar .mime (put/stat round-trip) · size cap. layers.nika-blob = "L1" # nika-exec-runner · Phase-B slice step 7 (announce floor `exec` · D-2026-06-10-N6) · # implements kernel io::process {ShellRun,ShellCancel} via tokio::process · command # blocklist (NFKC + zero-width + quote/basename bypass defenses) · kill_on_drop + concurrent drain. layers.nika-exec-runner = "L1" # nika-sandbox-seatbelt · macOS CommandSandbox impl (ADR-095 Layer 6 · the # per-platform sandbox pair named by plugin::sandbox) · wraps a command in # sandbox-exec with an SBPL profile from permits · no unsafe, no FFI. layers.nika-sandbox-seatbelt = "L1" # nika-sandbox-landlock · Linux CommandSandbox impl (ADR-095 Layer 6 · the # Linux half of the per-platform sandbox pair) · wraps a command in bwrap with a # namespace jail from permits · no unsafe, no FFI · Landlock LSM hardening owed. layers.nika-sandbox-landlock = "L1" # nika-http · Phase-B slice step 5 (announce ladder · D-2026-06-10-N6 cascade) · # implements kernel io::http {HttpGet,HttpPost} via reqwest · SSRF defense # (static + DNS-resolve + per-hop redirect re-check) · response size cap. layers.nika-http = "L1" # nika-harness · the harness access class client (D-2026-08-04-N1 P3 · Lane A) · # hand-rolled ACP wire-v1 over JSON lines · impl of the kernel AgentBackend seam · # docs/crate-specs/nika-acp.md §2bis (the SDK stays quarantined · never linked). layers.nika-harness = "L1" # nika-secret · workflow secret RESOLUTION (descended from nika-runtime # 2026-08-06 at the 15k wall · pure · the scrub half stays behind). layers.nika-secret = "L1" # nika-dataflow · the run's pure dataflow — TaskRecord + the ${{ }}/CEL/jq # evaluation over it (descended from nika-runtime in the v0.115 development # line · zero I/O, zero async, zero clock). Mechanical sort makes pure logic # L0; ADR-027's explicit fanout policy records why the five sibling inputs are # one cohesive evaluation unit rather than disguising the crate as an effect. layers.nika-dataflow = "L0" # nika-providers · Phase-B slice step 8.5 (announce ladder · D-2026-06-10-N6) · # implements kernel ai::provider {ProviderInferDyn,ProviderStreamDyn,ProviderMeta} · # 14 canonical profiles over 3 wire formats · transport via kernel http (no reqwest here). layers.nika-providers = "L1.5" # nika-providers-access · the probe facts, the access plan and the route identity · size-cap # member of the nika-providers unit (D-2026-07-09-N1 · the ADR-122 member note) · lateral L1.5 # edge nika-providers → nika-providers-access, never back. layers.nika-providers-access = "L1.5" # nika-infer-local · sovereign local inference sidecar (ADR-091) · all-Rust # replacement for the ollama dependency · OpenAI-compat surface (reuses the # nika-providers wire) · subprocess-isolated · candle backend feature-gated # off (`local-infer`) · v1 scaffold = protocol + Backend seam + MockBackend. layers.nika-infer-local = "L1.5" # nika-verb-infer · Phase-B slice step 9 (announce ladder · D-2026-06-10-N6) · # FIRST L2 verb crate · one-shot inference per spec 02-verbs.md §infer · # resolves provider/model via nika-providers · structured-output floor # (ResponseFormat + bounded schema-validation retry) · NIKA-430..433. layers.nika-verb-infer = "L2" # nika-verb-exec · announce-ladder s10 · the exec verb per spec 02-verbs.md §exec · # kernel ShellRunDyn injected (TokioShell prod · MockShell test) · pre_validated # never set (s7 blocklist floor) · capture one-obvious-way split · NIKA-440..442. layers.nika-verb-exec = "L2" # nika-verb-invoke · announce-ladder s11 · the invoke verb per spec 02-verbs.md §invoke · # kernel ToolExecuteDyn injected (engine builtin+MCP dispatcher) · closed nika:/mcp: # namespace validated before dispatch · NIKA-450..452. layers.nika-verb-invoke = "L2" # nika-verb-agent · the 4th verb (s12 · multi-turn ReAct loop · D-2026-05-22-N18) · seeded # 2026-06-11 against the ToolDefinitionProvider seam per docs/crate-specs/nika-verb-agent.md. layers.nika-verb-agent = "L2" layers.nika-registry-client = "L2" layers.nika-runtime = "L3" layers.nika-runtime-laws = "L3" # nika-execution · the one descriptor-rooted admission boundary shared by # every interface: captures root/child/skill/import bytes once, checks the # immutable closure, then gives runners no filesystem capability. layers.nika-execution = "L3" # nika-service-execution · the ONE shared production execution driver over an # admitted world: it joins nika-runtime (generic wave-ordered execution) and # nika-execution (byte admission) so the local CLI/ARM surface and the service # surface run the SAME composition root and the SAME child-composition # decisions. Descended out of nika-runtime at the 15k prod-LOC wall # (nika-proof/nika-secret precedent · runtime measured 16024 > 15000 before # the split). Same-layer L3 by the mechanical sort — it consumes two L3 peers # and no interface. layers.nika-service-execution = "L3" # nika-builtin · announce-ladder s16 · the 22 stdlib v0.1 builtins behind ONE dispatcher # implementing the three kernel tool seams (ToolExecuteDyn+ToolBatchDyn+ToolDefinitionProviderDyn) · # composes the L1 effects (fs · http · clock · event-sink) · spec docs/crate-specs/nika-builtin.md. layers.nika-builtin = "L1.5" # nika-extract · the 9 fetch extract modes (pure byte→structured transform · zero # I/O · consumed by nika-builtin nika:fetch per admission steps 12+13). layers.nika-extract = "L1.5" layers.nika-catalog = "L0" layers.nika-catalog-codegen = "L0" layers.nika-catalog-verify = "L4" layers.nika-schema = "L0" # nika-check · the static judgment crate (the workflow analyzer — Core # conformance + the derived DAG edges — plus the `nika check` pre-flight # ladder: cost ceiling · secret-leak IFC · capability-escape fit · trifecta # · policy · gate reachability · RunCertificate) · split from nika-schema # 2026-07-21 (the 15k crate-size wall · the nika-graph/nika-dap precedents) # — L0 not L1: pure/sync/zero-I/O, and THREE L0 consumers (nika-lints · # nika-graph · nika-schema's own skill.rs) make any higher layer an # upward-dep violation per check-layering.sh. Parser there, judgment here. layers.nika-check = "L0" layers.nika-check-analyzer = "L0" layers.nika-source = "L0" # nika-vocab · the .nika configuration vocabulary (capture/decode/retry/ # duration/secret/var+output declarations) · third member of the nika-schema # architectural unit (size-cap split · D-2026-07-09-N1 · the nika-source # precedent) — re-exported wholesale at nika_schema::types. layers.nika-vocab = "L0" # nika-migrate · the .nika envelope migrations (W1 map · W2 equivalence- # or-stop flow) · the repairs `check --fix` applies · split from nika-cli's # src/migrate.rs 2026-07-15 (the crate-size cap · the nika-source/nika-vocab # precedent) — pure std, zero deps, consumed by nika-cli's fix verb. layers.nika-migrate = "L0" layers.nika-lints = "L0" # nika-graph · the canonical graph projection (graph_format: 2 · spec 03 # §graph-projection) · split from nika-schema 2026-07-13 (the crate-size # cap · the nika-dap/nika-models precedents) — one projector, every surface. layers.nika-graph = "L0" # nika-cel · the cel-subset/0.1 expression engine (lexer · parser · typed computer # over a Resolver) · the ONE CEL surface shared by nika-schema (static shape) + # nika-runtime (the expr seam) · spec docs/crate-specs/nika-cel.md. layers.nika-cel = "L0" layers.nika-kernel = "L0.5" layers.nika-kernel-ai = "L0.5" layers.nika-kernel-core = "L0.5" layers.nika-kernel-runtime = "L0.5" layers.nika-kernel-plugin = "L0.5" layers.nika-kernel-mock = "L0.5" # nika-bm25 · W3 admission target · single-crate-feature-gated per devil's # advocate 2026-05-12 audit (Option E supersedes 2-crate split) · ADR-038 # binding · spec docs/crate-specs/nika-bm25.md · `kernel` feature default-on # Diamond-internal · external crates.io consumers `--no-default-features` layers.nika-bm25 = "L1" # nika-store · F-P8 signed-memory substrate (SMSR · spec docs/crate-specs/nika-store.md) · # signed-write/verified-recall over `.nika/memory//` · minisign over the JCS # envelope · the run-signing key INJECTED (custody stays L4) · NIKA-605. layers.nika-store = "L1" # nika-screen · M2.1 first computer-use L1 effect crate (ADR-081 guards 6+7) · # implements kernel io::screen ScreenCapture · xcap backend (B.3) · NIKA-1000..1099. layers.nika-screen = "L1" # nika-ocr · M2.2 second computer-use L1 effect crate (no mandatory guard) · # implements kernel io::ocr OcrEngine · ocrs pure-Rust backend (B.3) · NIKA-1100..1199. layers.nika-ocr = "L1" layers.nika-a11y = "L1" # nika-input · M2.4 fourth computer-use L1 effect crate · FIRST write-side · # implements kernel io::input InputDeviceDyn · enigo cross-platform backend · # ADR-081 Guards 1+2 MANDATORY · NIKA-1300..1399. layers.nika-input = "L1" # nika-browser · M2.5 fifth computer-use L1 effect crate · CDP web arm · # implements kernel io::browser BrowserAutomationDyn · chromiumoxide backend (B.3) · # ADR-081 Guard 5 MANDATORY (selector clickjacking) · NIKA-1400..1499. layers.nika-browser = "L1" # ───────────────────────────────────────────────────────────────────────────── # Per-layer banned external deps (runtime-binding crates forbidden at layers # that must stay runtime-agnostic). Enforced by # scripts/hygiene/check-layer-deps.sh (vector 33). # # L0 = pure data + logic, no async runtime, no I/O binding. # L0.5 = trait-only surface, uses `trait_variant` for async-fn desugaring # (no direct tokio/futures dep in the trait crate itself). # L1+ = effect impls may bind to tokio and its ecosystem. # ───────────────────────────────────────────────────────────────────────────── layer-bans.L0 = ["tokio", "tokio-util", "tokio-stream", "tokio-macros", "rayon", "async-std", "smol", "futures", "futures-util", "futures-core", "futures-channel", "async-channel", "reqwest", "hyper", "h2", "axum", "actix-web"] layer-bans."L0.5" = ["tokio", "tokio-util", "tokio-stream", "rayon", "async-std", "smol", "reqwest", "hyper", "h2", "axum", "actix-web"] # ───────────────────────────────────────────────────────────────────────────── # Workspace-wide lint policy. Every member crate MUST opt in via: # [lints] # workspace = true # ───────────────────────────────────────────────────────────────────────────── [workspace.lints.rust] unsafe_code = "forbid" unused_must_use = "deny" elided_lifetimes_in_paths = "warn" unreachable_pub = "warn" explicit_outlives_requirements = "warn" unused_extern_crates = "warn" # Declare `cfg(loom)` as a known config flag so `#[cfg(loom)]` in # nika-types::cancel (and any future concurrent primitive) doesn't # emit `unexpected_cfgs` warnings on normal `cargo build`. Loom tests # run explicitly via `RUSTFLAGS="--cfg loom"`. unexpected_cfgs = { level = "warn", check-cfg = ['cfg(loom)'] } [workspace.lints.clippy] # Group levels (priority = -1 so individual lints below win) correctness = { level = "deny", priority = -1 } suspicious = { level = "warn", priority = -1 } perf = { level = "deny", priority = -1 } pedantic = { level = "warn", priority = -1 } # Core "diamond" lints — zero tolerance on production src/ unwrap_used = "deny" expect_used = "warn" panic = "deny" todo = "warn" unimplemented = "warn" unreachable = "warn" dbg_macro = "deny" # Iterating a HashMap/HashSet is ordering-nondeterminism by construction — # poison for an engine whose outputs, manifests and goldens must be # byte-stable. BTree/sorted structures everywhere (measured: 0 violations # across 40 crates when adopted · the ruff workspace carries the same lint). iter_over_hash_type = "deny" print_stdout = "warn" print_stderr = "warn" # Per-function 100-LOC soft cap (ADR-023). Function modularity discipline. too_many_lines = "warn" # World-class discipline (post-blueprint v1.1 audit · 2026-05-12) # `must_use_candidate` + `let_underscore_must_use` DEFERRED to ratchet sprint · # existing codebase ships 126 candidate sites · enabling either at warn breaks # `-D warnings` CI gate · queue as standalone refactor with `#[expect(...)]` # baseline per uv pattern · v0.85 milestone target. [workspace.lints.rustdoc] # Compile-time doc discipline (was script-only via check-doc-private-items.sh) broken_intra_doc_links = "deny" private_intra_doc_links = "warn" invalid_codeblock_attributes = "deny" bare_urls = "warn" # ───────────────────────────────────────────────────────────────────────────── # Shared dependencies. Populated when Phase 1 extract-ready crates land. # Rule (RUST_ENFORCEMENT §2): pin once here, downstream = `.workspace = true`. # ───────────────────────────────────────────────────────────────────────────── [workspace.dependencies] # Pin once here, downstream uses `.workspace = true` (RUST_ENFORCEMENT §2). thiserror = "2.0" minisign = { version = "0.9", default-features = false } # the seal/signature primitive (nika-dap custody · nika-store F-P8 envelopes) regex = "1.11" # nika-builtin L1.5 — nika:grep pattern engine (RE2-class · no backrefs · the portable subset) include_dir = "0.7" # nika-pack L0 · compile-time spec-pack embedding sha2 = "0.10" # nika-pack dev · manifest integrity hashing + nika-event L0 · the source-identity hash hmac = "0.12" # nika-cli L4 — ADR-111 Standard Webhooks signature (RustCrypto · pairs with sha2) miette = "7.6" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" toml_edit = "0.25" # nika-cli L4 — `nika wire codex` patches ~/.codex/config.toml (comment-preserving) marked-yaml = "0.8" serde-saphyr = { version = "1.0.0", features = ["miette"] } phf = { version = "0.14", features = ["macros", "unicase"] } unicase = "2.9" trait-variant = "0.1" bytes = { version = "1", features = ["serde"] } http-body-util = "0.1" # nika-serve L4 — bounded HTTP body collection for the W06 listener hyper = { version = "1", features = ["http1", "server"] } # nika-serve L4 — HTTP/1.1 loopback listener (no TLS) hyper-util = { version = "0.1", features = ["tokio"] } # nika-serve L4 — Tokio IO adapter for Hyper subtle = "2.6" # nika-serve L4 — constant-time Bearer digest compare blake3 = "1" # nika-blob L1 — content-addressed hashing (CC0-1.0 OR Apache-2.0 · allowlisted) serde_json_canonicalizer = "0.3" # nika-runtime L3 — RFC 8785 JCS bytes under the ADR-099 resume keys (MIT · rides the existing serde_json/ryu stack) annotate-snippets = "0.12" # nika-cli L4 — rustc-grade painted diagnostics (rust-lang org · cargo depends on it · MIT OR Apache-2.0) anstyle = "1" # nika-cli L4 — the Style type annotate-snippets' renderer consumes (colour stays OUR seam mapping) unicode-normalization = { version = "0.1", default-features = false } # nika-types L0 (the shared argv exec-floor predicate · #605) — NFKC confusable-bypass defense in the command blocklist · no_std-compatible (the L0 leaf's no-std seam stays intact) · MIT OR Apache-2.0 nix = { version = "0.31", default-features = false, features = ["signal"] } # nika-exec-runner L1 (unix) — safe killpg wrapper for process-group kill (encapsulates the unsafe signal FFI → crate stays unsafe_code = forbid · MIT) futures-core = "0.3" parking_lot = "0.12" tokio = { version = "1", features = ["rt", "macros", "time", "signal"] } # signal: nika-cli L4 — `nika serve` (W5) stops clean on ctrl-c/SIGTERM (signal-hook-registry already vendored via the tree) rustix = { version = "=1.1.4", default-features = false, features = ["std", "process"] } # safe waitid(WNOWAIT) on Linux/macOS; already locked cap = { version = "=0.1.2" } # nika-cli L4: the isolated jq helper caps its heap allocations (safe API over GlobalAlloc · keeps unsafe forbid · ROOT review control/e02-cap-dependency-review.root.json) stacker = { version = "=0.1.25" } # nika-runtime-laws L3: a nested run's guaranteed native stack, grown on the same thread (rust-lang/stacker · safe API over psm · keeps unsafe forbid · MIT OR Apache-2.0) globset = "0.4" # nika-fs L1 — FsList::glob matcher (literal_separator · MIT OR Unlicense) reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "gzip", "brotli", "deflate", "http2"] } # nika-http L1 + nika-catalog-verify L4 — pin once (RUST_ENFORCEMENT §2) · rustls (no openssl) · transparent gzip/br/deflate decode + h2 ALPN (the web compresses · pure-Rust miniz_oxide/brotli-decompressor/h2 · zstd SKIPPED: C dep) url = "2" # nika-http L1 — SSRF URL parsing (also transitive via reqwest · pinned aligned) base64 = "0.23" # nika-cli L4 — the trace anchor's Rekor/RFC 3161 wire encoding (also transitive via minisign · pinned aligned) ed25519-dalek = { version = "2", default-features = false, features = ["alloc", "digest", "hazmat"] } # nika-cli L4 — raw RFC 8032 sign/verify for the Rekor v2 entry signature (Ed25519ph — the server refuses pure ed25519) + checkpoint verification (BSD-3-Clause · pure Rust) der = { version = "0.7", default-features = false, features = ["alloc", "derive", "oid"] } # nika-cli L4 — RFC 3161 TimeStampReq build + TimeStampResp/TSTInfo parse (RustCrypto · Apache-2.0 OR MIT) cms = { version = "0.2", default-features = false, features = ["alloc"] } # nika-cli L4 — the TSA token's CMS SignedData verification (RustCrypto · Apache-2.0 OR MIT) p384 = { version = "0.14", default-features = false, features = ["ecdsa", "sha384"] } # nika-cli L4 — the Sigstore TSA leaf is ECDSA P-384/SHA-384 (RustCrypto · Apache-2.0 OR MIT) # Forward-pinned shared deps (used by Phase 1+ crates). # Pinning here keeps versions aligned when downstream crates opt in via # `.workspace = true`. Per RUST_ENFORCEMENT §2. strsim = "0.11" # nika-error Phase C suggest() — Levenshtein for "did you mean" smallvec = "1.13" # SmallVec adoption per RUST_2026_BEST_PRACTICES (hot-path vecs) tracing = "0.1" # L1+ effect crates (fs/http/process/...) structured logging ocrs = "0.12" # nika-ocr L1 (M2.2) — pure-Rust OCR engine (rten runtime · no C dep · keeps unsafe forbid) rten = "0.24" # nika-ocr L1 — Model::load_file for .rten weights (ocrs ^0.24 normal dep · pinned aligned) accessibility = "0.2" # nika-a11y L1 (M2.3 · macOS-gated) — safe AXUIElement API (TreeWalker · encapsulated ApplicationServices unsafe · keeps unsafe forbid) core-foundation = "0.10" # nika-a11y L1 (M2.3 · macOS-gated) — CFString/CFType for AXAttribute generic reads (value · subrole) atspi = "0.30" # nika-a11y L1 (M2.3-bis · Linux-gated · ADR-083) — pure-Rust async AT-SPI2 D-Bus client (root_accessible_on_registry · get_children · get_role · State::Sensitive) · CI-pending verify on a Linux/AT-SPI host enigo = "0.6" # nika-input L1 (M2.4 · ADR-083 cross-platform) — synthetic pointer+keyboard (macOS CGEvent · Windows SendInput · Linux X11/Wayland · per-OS unsafe encapsulated → keeps unsafe forbid) · API tarball-verified 0.6.1 chromiumoxide = { version = "0.9", default-features = false, features = ["bytes"] } # nika-browser L1 (M2.5 · ADR-083) — CDP browser automation (tokio-native · kill_on_drop child per INV-011) · fetcher EXPLICITLY out (default-features=false pins the sovereign surface · a future default-flip is caught by cargo, not silently activating a browser download) · API tarball-verified 0.9.1 png = "0.18" # nika-browser L1 — Page.captureScreenshot PNG → RGBA8 kernel Frame decode (pure · headless-testable) futures-util = { version = "0.3", default-features = false, features = ["std"] } # nika-browser L1 — StreamExt::next to drain the CDP Handler stream (one owned task per session) jsonschema = { version = "0.49", default-features = false } # nika-verb-infer L2 — structured-output schema validation (draft 2020-12 · no network resolver per sovereignty floor) jaq-core = "3.1" # nika-builtin L1.5 — nika:jq · THE data language (jq parser+compiler+interpreter · MIT · API source-verified 2026-06-11) jaq-std = "3.0" # nika-builtin L1.5 — jq stdlib filters (map · select · group_by …) jaq-json = { version = "2.0", features = ["serde"] } # nika-builtin L1.5 — jq Val type + serde bridge to serde_json::Value json-patch = "4.2" # nika-builtin L1.5 — nika:json_diff (RFC 6902 diff) + nika:json_merge_patch (RFC 7396 · null-deletes) jiff = "0.2" # nika-builtin L1.5 — nika:date · strftime grammar · Unlicense OR MIT · named tz resolved via jiff-tzdb below (NOT jiff's system-preferring .in_tz) jiff-tzdb = "0.1" # nika-builtin L1.5 — the EMBEDDED IANA tzdb · nika:date resolves named zones from THIS (bundled · deterministic · zero system read), never jiff's default which prefers /usr/share/zoneinfo on Unix · CC-BY-4.0 OR ... (tzdata public-domain) serde_yaml_bw = "2.5" # nika-builtin L1.5 — nika:convert yaml leg + nika:validate format:yaml (panic-free fork · spec-named reference impl) toml_convert = { package = "toml", version = "1.1" } # nika-builtin L1.5 — nika:convert toml leg (alias avoids clash if a config-toml dep lands later) csv = "1.4" # nika-builtin L1.5 — nika:convert csv leg (quoting-aware · spec-named reference impl) htmd = "0.5" # nika-extract L1.5 — mode markdown|article HTML→Markdown (Apache-2.0 · API source-verified 2026-06-12) dom_smoothie = "0.18" # nika-extract L1.5 — mode article Readability (MIT · Article fields content+text_content verified docs.rs) scraper = "0.27" # nika-extract L1.5 — modes text|selector|metadata|links CSS-select DOM (ISC) feed-rs = "2.3" # nika-extract L1.5 — mode feed RSS/Atom/JSON-Feed normalize (MIT) quick-xml = "0.41" # nika-extract L1.5 — mode sitemap urlset+index parse (MIT) encoding_rs = "0.8" # nika-builtin L1.5 — nika:fetch charset-aware decode for extraction modes (Apache-2.0/MIT/BSD-3 · the encoding the web actually uses · same crate reqwest text() uses) ego-tree = "0.11" # nika-extract L1.5 — scraper public tree API (Edge traversal for the text-mode walk · ISC · pinned aligned with scraper 0.27) wasm-bindgen = "0.2" # nika-check-wasm L4 — the browser transport boundary (bindgen CLI pinned to the lock minor at build) getrandom = "0.3" # nika-check-wasm L4 — wasm32 entropy backend door (features chosen crate-side per target) getrandom-02 = { package = "getrandom", version = "0.2" } # nika-check-wasm L4 — the OLDER getrandom generation still in the graph, same door uuid = { version = "1", features = ["v7", "v4", "serde"] } # ADR-033 UUIDv7 IDs (nika-error L0) · v4 for nika:builtin nika:uuid clap = { version = "4.5", features = ["derive"] } # L4 CLI surface (completions + man derive from this tree) ratatui = { version = "0.30", features = ["scrolling-regions"] } # nika-tui L4 · the inline viewport with scroll regions (ADR-139) crossterm = { version = "0.29", features = ["event-stream", "bracketed-paste"] } # nika-tui L4 · one reader thread on poll slices · paste as data (ADR-139) ratatui-textarea = "0.9" # nika-tui L4 · the composer spike behind a wrapper (ADR-139 · exit criterion written) clap_complete = "4.5" # L4 CLI — shell completions generated from the clap tree (nika-cli spec §9) lsp-server = "0.10" # nika-lsp L4 — sync stdio JSON-RPC message loop (rust-analyzer's · MIT) lsp-types = "0.97" # nika-lsp L4 — LSP 3.17 protocol types (Diagnostic · Position · CompletionItem · MIT) zeroize = "1.8" # ADR-034 Secret zeroize-on-drop (nika-kernel L0.5) — 1.8 adds heap-String zeroing # Dev / test deps criterion = { version = "0.8", features = ["html_reports"] } proptest = "1.6" insta = { version = "1.42", features = ["yaml"] } tempfile = "3" # nika-ocr dev — model-load error-path fixtures (with_models headless tests) rstest = "0.27" expect-test = "1.5" # inline snapshots, see ADR-015 expectrl = "0.9" # PTY e2e — the wizard's TTY-gated conversation (unix-only tests) # ───────────────────────────────────────────────────────────────────────────── # Release profile (post rust-perf audit 2026-05-12 · BLUEPRINT v1.2 §4 ship-now) # ───────────────────────────────────────────────────────────────────────────── # LTO=fat + codegen-units=1 unlock ~5-10% on hot loops (BGE-M3 cosine, BM25 # scoring, RRF fusion) per cargo-pgo + rust-compiler-team Kobzol research. # Cost · 2× build time at release · `cargo build --release` only · dev builds # unaffected. strip=symbols matches ADR-061 SLSA L3 byte-determinism target. # panic=unwind KEPT · panic=abort breaks `cargo test` panic-catching + violates # the propagate-errors discipline (forbidden for the surrounding tooling · # ambiguous for the engine · default unwind is the conservative choice). debug=line-tables-only # preserves enough symbols for `cargo flamegraph` without bloating release binary. [profile.release] lto = "fat" codegen-units = 1 strip = "symbols" panic = "unwind" debug = "line-tables-only" incremental = false [profile.bench] inherits = "release" debug = true # The browser artifact's own profile (nika-check-wasm · additive, harms no # other build): the workspace release keeps debuginfo for native profiling, # which a served .wasm must not carry — measured 4.6M with it, and the fat # LTO + size-opt pass exists to prune the L0 judgment hub's heavy corners # (jaq · jsonschema) out of a parse+conform artifact. [profile.wasm-release] inherits = "release" strip = "debuginfo" debug = false lto = true opt-level = "z" codegen-units = 1 # A trapped wasm instance never comes back (the jq-bomb work made that # literal — the shadow stack does not restore), so unwinding machinery in # the artifact would be dead weight implying a recovery the crate refuses # to promise. No catch_unwind exists anywhere in the wasm dependency tree. panic = "abort" [patch.crates-io] # dom_smoothie 0.18.0 breaks candidate score ties by its hash map's per-process # iteration order: the same page yielded two different articles (nika PR 1503 · 2026-09-06 · # 40 identical runs → 30/10). The pinned rev carries the upstream-shaped fix (the # candidates keep their first-scored order · readability.js parity); it drops the # day upstream releases it. dom_smoothie = { git = "https://github.com/supernovae-st/dom_smoothie", rev = "fd6db004615af3c14d20f90bfb43ca514db4e57d" }