# Changelog All notable changes to ontoref are documented here. ADRs referenced below live in `adrs/` as typed Nickel records. --- ## [Unreleased] ### Config Surface — typed config, NCL contracts, override-layer mutation Per-project config introspection, coherence verification, and audited mutation. NCL contracts are the single validation gate; config mutation never modifies source NCL files. #### `crates/ontoref-daemon/src/config.rs` — typed `DaemonNclConfig` (parse-at-boundary) - `DaemonNclConfig` — top-level deserialize target for `nickel export .ontoref/config.ncl | daemon --config-stdin`; fields: `nickel_import_paths`, `ui: UiConfig`, `log: LogConfig`, `mode_run: ModeRunConfig`, `nats_events: NatsEventsConfig`, `actor_init: Vec`, `quick_actions: Vec`, `daemon: DaemonRuntimeConfig`. `#[cfg(feature = "db")] db: DbConfig`. All `#[serde(default)]`. - Each section struct derives `#[derive(Deserialize, ConfigFields)]` + `#[config_section(id, ncl_file)]` — emits `inventory::submit!(ConfigFieldsEntry{...})` at link time. - `DaemonRuntimeConfig` — optional port, timeouts, sweep intervals, `notification_ack_required: Vec`. #### `crates/ontoref-daemon/src/main.rs` — 3-tuple bootstrap block - Bootstrap block changed to `(nickel_import_path, loaded_ncl_config, stdin_raw)` — `loaded_ncl_config: Option` replaces raw `Option`. `stdin_raw: Option` retained only for service-mode `projects` extraction. - `apply_stdin_config` now deserializes JSON to `DaemonNclConfig` before applying CLI overrides; `apply_ui_config` signature changed from `&serde_json::Value` to `&UiConfig`. - `load_config_overrides` returns `(Option, Option)` — all `.get("daemon").and_then(...)` chains replaced with typed field access (`ncl.daemon.port`, etc.). - NATS call site updated to `loaded_ncl_config.as_ref().map(|c| &c.nats_events)`. - `resolve_asset_dir` gated with `#[cfg(feature = "ui")]`; `#[allow(unused_variables)]` on bootstrap tuple for `--no-default-features`. #### `crates/ontoref-derive/src/lib.rs` — `#[derive(ConfigFields)]` macro - New `proc_macro_derive` `ConfigFields` with helper attribute `config_section(id, ncl_file)`. Extracts serde-renamed field names; emits `inventory::submit!(ConfigFieldsEntry{section_id, ncl_file, struct_name, fields})`. - Extracted `serde_rename_of(field)` helper to fix `clippy::excessive_nesting` (depth was 6). Field names collected via `.iter().map(|f| serde_rename_of(f).unwrap_or_else(|| f.ident...)).filter(|s| !s.is_empty())`. #### `crates/ontoref-daemon/src/config_coherence.rs` — clippy fixes - `and_then(|_| full_export.as_ref())` → `.and(full_export.as_ref())` (unnecessary lazy evaluation). - Extracted `merge_meta_into_section` helper to reduce nesting depth for `_meta_*` record merging. #### `crates/ontoref-daemon/src/api.rs` — `index_section_fields` helper - Extracted `index_section_fields` to fix `clippy::excessive_nesting` at the cross-project field indexing loop. Skips `_meta_*` and `_overrides_meta` keys; indexes `(section_id, field) → Vec<(slug, value)>`. #### `.ontoref/contracts.ncl` — new file NCL contracts for ontoref's own config sections using `std.contract.from_validator` (not the deprecated `fun label value =>` pattern): - `LogLevel` — enum validator: `error | warn | info | debug | trace` - `LogRotation` — enum validator: `daily | hourly | never` - `PositiveInt` — `value > 0 && is_number` - `Port` — `value >= 1 && value <= 65535` - `LogConfig` — applies per-field contracts + defaults (`level = "info"`, `rotation = "daily"`, `max_files = 7`) - `DaemonConfig` — all fields optional (override-only); port, timeouts, intervals, `notification_ack_required` #### `.ontoref/config.ncl` — contracts applied - `let C = import "contracts.ncl"` added at top. - `log | C.LogConfig = { ... }` — contract enforced before JSON reaches Rust. #### `.ontology/manifest.ncl` — config surface enriched - `contracts_path = ".ontoref"` added to `config_surface`. - `log` section: `contract = "contracts.ncl → LogConfig"` added. - New `daemon` section: `contract = "contracts.ncl → DaemonConfig"`, consumer `daemon-config` pointing to `crates/ontoref-daemon/src/config.rs → DaemonRuntimeConfig` with 7 declared fields. ### Protocol - ADR-007 extended: `#[derive(ConfigFields)]` is a second application of the `inventory::submit!` / `inventory::collect!` linker registration pattern first established by `#[onto_api]`. Both are now referenced from the `config-surface` node. - ADR-008 accepted: NCL-first config validation and override-layer mutation. NCL contracts are the single validation gate; Rust structs are contract-trusted with `#[serde(default)]`. Config mutation writes `{section}.overrides.ncl` with `_overrides_meta` audit record; original NCL source files are never modified. nickel export validates the merged result before commit; contract violations revert the override file. ([adr-008](adrs/adr-008-ncl-first-config-validation-and-override-layer.ncl)) ### Self-Description — on+re Update `.ontology/core.ncl` — new Practice node, updated nodes, 6 new edges: | Change | Detail | | --- | --- | | New node `config-surface` | Yang — typed DaemonNclConfig, ConfigFields inventory registry, override-layer mutation API, NCL contracts, multi-consumer manifest schema; `adrs = ["adr-007", "adr-008"]` | | Updated `adr-lifecycle` | ADR-007 + ADR-008 added to `artifact_paths` and `adrs` list (now 8 ADRs) | New edges: `config-surface → ontoref-daemon` (ManifestsIn/High), `config-surface → ontoref-ontology-crate` (DependsOn/High — ConfigFieldsEntry lives in zero-dep crate), `config-surface → api-catalog-surface` (Complements/High — shared inventory pattern), `config-surface → dag-formalized` (ManifestsIn/High), `config-surface → self-describing` (Complements/High — ontoref validates its own config with its own contracts), `config-surface → adopt-ontoref-tooling` (Complements/Medium). `.ontology/state.ncl` — `protocol-maturity` blocker updated to record config surface completion. `self-description-coverage` catalyst updated with session 2026-03-26 additions. Previous: 4 axioms, 2 tensions, 27 practices. Current: 4 axioms, 2 tensions, 28 practices. --- ### API Catalog Surface — `#[onto_api]` proc-macro Annotated HTTP surface discoverable at compile time via `inventory`. - `crates/ontoref-derive/src/lib.rs` — `#[proc_macro_attribute] onto_api(method, path, description, auth, actors, params, tags)` emits `inventory::submit!(ApiRouteEntry{...})` for each handler; auth validated at compile time (`none | viewer | admin`); param entries parsed as `name:type:constraint:description` semicolon-delimited - `crates/ontoref-daemon/src/api_catalog.rs` — `ApiRouteEntry` + `ApiParam` structs (`&'static str` fields for process lifetime); `inventory::collect!(ApiRouteEntry)`; `catalog()` returns sorted `Vec<&'static ApiRouteEntry>` - `GET /api/catalog` — annotated with `#[onto_api]`; returns all registered routes as JSON sorted by path+method; no auth required - `GET /projects/{slug}/ontology/versions` — per-file reload counters as `BTreeMap`; counter bumped on every watcher-triggered NCL cache invalidation - `describe api [--actor] [--tag] [--auth] [--fmt json|text]` — queries `/api/catalog`, groups by first tag, renders auth badges, param detail per route; available as `onref da` alias - `describe diff [--file ] [--fmt json|text]` — semantic diff of `.ontology/` files vs HEAD via `git show HEAD: | mktemp | nickel export`; diffs nodes by id, edges by `from→to[kind]` key; available as `onref df` alias - `ontoref_api_catalog` MCP tool — calls `api_catalog::catalog()` directly; filters by actor/tag/auth; returns `{ routes, total }` - `ontoref_file_versions` MCP tool — reads `ProjectContext.file_versions` DashMap; returns per-filename counters - Web UI: `/{slug}/api` page — table with client-side filtering (path, auth, method) + expandable detail panel; linked from nav and dashboard - Dashboard: "Ontology File Versions" section showing per-file counters; "API Catalog" card - `insert_mcp_ctx` in `handlers.rs` updated: 15 → 28 tools (previously stale for qa, bookmark, action, ontology extensions, validate, impact, guides) - `HelpTool` JSON updated: 8 entries added (validate_adrs, validate, impact, guides, bookmark_list, bookmark_add, api_catalog, file_versions) - `MCP ServerHandler::get_info()` instructions updated to mention `ontoref_guides`, `ontoref_api_catalog`, `ontoref_file_versions`, `ontoref_validate` ### Protocol Update Mode - `reflection/modes/update_ontoref.ncl` — new mode bringing existing ontoref-adopted projects to protocol v2; 9-step DAG: 5 parallel detect steps (manifest, connections, ADR check_hint scan, ADRs missing check, daemon /api/catalog probe), 2 parallel update steps (add-manifest, add-connections — both idempotent via `test -f || sed`), 2 validate steps (nickel export with explicit import paths), 1 aggregate report step - `templates/ontology/manifest.ncl` — consumer-project stub; imports `ontology/defaults/manifest.ncl` via import-path-relative resolution - `templates/ontology/connections.ncl` — consumer-project stub; imports `connections` schema; empty upstream/downstream/peers with format docs - `reflection/modes/adopt_ontoref.ncl` — updated: adds `copy_ontology_manifest` and `copy_ontology_connections` steps (parallel, `'Continue`, idempotent); `validate_ontology` depends on both with `'Always` - `reflection/templates/update-ontology-prompt.md` — 8-phase reusable prompt for full ontology enrichment: infrastructure update, audit, core.ncl nodes/edges, state.ncl dimensions, manifest.ncl assets, connections.ncl cross-project, ADR migration, final validation ### CLI — `describe` group extensions and aliases - `main describe diff` and `main describe api` wrappers in `reflection/bin/ontoref.nu` - `main d diff`, `main d api` — short aliases within `d` group - `main df`, `main da` — toplevel aliases (consistent with `d`, `ad`, `bkl` pattern) - QUICK REFERENCE: `describe diff`, `describe api`, `run update_ontoref` entries added - `help describe` description updated to include `diff, api surface` ### Self-Description — on+re Update `.ontology/core.ncl` — 1 new Practice node, 3 updated nodes, 3 new edges: | Change | Detail | | --- | --- | | New node `api-catalog-surface` | Yang — #[onto_api] proc-macro + inventory catalog; GET /api/catalog; describe api; ApiCatalogTool; /ui/{slug}/api page | | Updated `describe-query-layer` | Description extended: describe diff (semantic vs HEAD) and describe api (annotated surface) | | Updated `adopt-ontoref-tooling` | Description extended: update_ontoref mode, manifest/connections templates, enrichment prompt; artifact_paths updated | | Updated `ontoref-daemon` | 11 pages, 29 MCP tools, per-file versioning, API catalog endpoint; artifact_paths: api_catalog.rs, api_catalog.html, crates/ontoref-derive/ | | New edge `api-catalog-surface → ontoref-daemon` | ManifestsIn/High | | New edge `api-catalog-surface → describe-query-layer` | Complements/High | | New edge `api-catalog-surface → protocol-not-runtime` | Complements/Medium — catalog is link-time, no runtime | `.ontology/state.ncl` — `self-description-coverage` catalyst updated (session 2026-03-23). `protocol-maturity` blocker updated to reflect protocol v2 completeness. Previous: 4 axioms, 2 tensions, 20 practices. Current: 4 axioms, 2 tensions, 21 practices. --- ### Personal Ontology Schemas & Content Modes Three new typed NCL schema families added to `ontology/schemas/` and `ontology/defaults/`: | Schema | Types exported | | --- | --- | | `career.ncl` | `Skill`, `WorkExperience`, `Talk`, `Positioning`, `CompanyTarget`, `PublicationCard`, `CareerConfig` | | `personal.ncl` | `Content` (BlogPost / ConferenceProposal / CV / Application / Email / Thread), `Opportunity` (Job / Conference / Grant / Collaboration / Podcast), `PersonalConfig` | | `project-card.ncl` | `ProjectCard` — canonical display metadata (name, tagline, status, tags, tools, features, sort_order) for portfolio and cv_repo publication | All types carry `linked_nodes | Array String` referencing `.ontology/core.ncl` node IDs. `PublicationCard` is a career overlay referencing a canonical `project_node` from the portfolio repo. Five NCL DAG reflection modes added to `reflection/modes/`: | Mode | Purpose | | --- | --- | | `draft-application` | Job/grant/collaboration application anchored in personal ontology — gate alignment check, node selection, career trajectory render, status update | | `draft-email` | Context-grounded email composition using ontology nodes as evidence | | `generate-article` | Blog post / thread generation from project nodes and tensions | | `update-cv` | CV refresh loop querying current career.ncl and core.ncl state | | `write-cfp` | Conference proposal from Practice/Project nodes with gate alignment check | ### Search Bookmarks Bookmark persistence for search results over the ontology graph. Mirrors Q&A NCL pattern (ADR-003). - `reflection/schemas/search_bookmarks.ncl` — `BookmarkEntry` (id, node_id, kind, title, level, term, actor, created_at, tags) and `BookmarkStore` contracts - `reflection/search_bookmarks.ncl` — typed store file; conforms to `BookmarkStore` contract - `crates/ontoref-daemon/src/ui/search_bookmarks_ncl.rs` — `add_entry` / `remove_entry` via line-level NCL surgery; auto-incremented `sb-NNN` ids; concurrency-safe via `NclWriteLock` Tests: `next_id_empty`, `next_id_increments`, `insert_into_empty_store`, `delete_first_entry`, `delete_second_entry`, `delete_missing_id_errors`, `escape_quotes_and_backslashes`, `concurrent_add_produces_unique_ids` (tokio, 6 concurrent tasks, asserts unique ids). ### Protocol - ADR-006 accepted: Nushell 0.111 string interpolation compatibility fix. Four print statements in `reflection/bin/ontoref.nu` used `(identifier: expr)` patterns inside `$"..."` — parsed as command calls by Nu 0.111 parser. Fix: bare `identifier: (expr)` for label-value pairs; plain strings (no `$`) for zero-interpolation prints. Hard constraint: no `(label: expr)` inside `$"..."` in any `.nu` file. Soft constraint: zero-interpolation strings must not use `$"..."`. ([adr-006](adrs/adr-006-nushell-0111-string-interpolation-compat.ncl)) ### Self-Description — on+re Update `.ontology/core.ncl` — 3 new Practice nodes, updated `adr-lifecycle` and `ontoref-daemon` nodes: | Change | Detail | | --- | --- | | New node `personal-ontology-schemas` | Yin — career/personal/project-card typed NCL schemas with linked_nodes DAG bridges | | New node `content-modes` | Yang — 5 NCL DAG modes for personal content and career operations | | New node `search-bookmarks` | Yin — bookmark persistence layer; NCL surgery via search_bookmarks_ncl.rs | | `adr-lifecycle` | ADR-006 added to `artifact_paths` and `adrs` list | | `ontoref-daemon` | `search_bookmarks_ncl.rs` added to `artifact_paths` | New edges: `personal-ontology-schemas → dag-formalized` (ManifestsIn/High), `personal-ontology-schemas → self-describing` (Complements/Medium), `content-modes → reflection-modes` (ManifestsIn/High), `content-modes → personal-ontology-schemas` (DependsOn/High), `search-bookmarks → qa-knowledge-store` (Complements/High), `search-bookmarks → ontoref-daemon` (ManifestsIn/High), `ontoref-daemon → search-bookmarks` (Contains/High). `.ontology/state.ncl` — `self-description-coverage` catalyst updated to include 2026-03-15 session additions. `protocol-maturity` blocker updated to reflect Nu 0.111 fix and personal schema layer completion. Previous: 4 axioms, 2 tensions, 17 practices. Current: 4 axioms, 2 tensions, 20 practices. --- ### ADR–Node Declared Linkage - `Node` schema extended with `adrs | Array String | default = []` (Nickel `ontology/schemas/core.ncl` and inline `CoreConfig` type). - Rust `Node` struct gains `artifact_paths: Vec` and `adrs: Vec`, both `#[serde(default)]` — zero migration cost for existing nodes that omit the fields. - `describe.nu` `build-howto` populates `adrs` from the node record; `render-howto` (ANSI), `render-howto-md`, and `howto-to-md-string` (clipboard) all emit a **Validated by** section when `adrs` is non-empty. - New `GET /api/adr/{id}?slug=` endpoint — reads `adrs/.ncl`, exports via NCL cache, returns JSON. No auth required (read-only, loopback boundary). - Graph UI (`graph.html`): `adrs` field passed into Cytoscape node data. Detail panel renders "Validated by" section with clickable `◆ ` buttons that open a DaisyUI modal fetching full ADR content via the new endpoint. - Fixed glob pattern error in `describe.nu:build-howto`: `glob $"($full)/*.rs"` replaced with `glob ($full | path join "*.rs")` — eliminates `//` in pattern when path has trailing separator. ### Self-Description — on+re Update `.ontology/core.ncl` — new node, updated nodes, new edges: | Change | Detail | | --- | --- | | New node `adr-node-linkage` | Practice: declares `adrs` field pattern, lists all 5 modified artifacts | | `adr-lifecycle` | Description updated; `adrs = ["adr-001"…"adr-005"]` declared | | `describe-query-layer` | Description updated to mention Validated by rendering | | `ontoref-ontology-crate` | Description updated to mention `artifact_paths` + `adrs` fields; `adrs = ["adr-001"]` | | New edge `adr-node-linkage → adr-lifecycle` | ManifestsIn/High | | New edge `adr-node-linkage → describe-query-layer` | Complements/High | Previous: 4 axioms, 2 tensions, 16 practices. Current: 4 axioms, 2 tensions, 17 practices. ### Ontology Three-File Split - New Practice node `ontology-three-file-split` in `.ontology/core.ncl`: documents the `core.ncl` (what IS) / `state.ncl` (where we ARE vs want to BE) / `gate.ncl` (when READY to cross a boundary) separation and the role of `reflection/` in answering self-knowledge queries without reading code. - `assets/presentation/slides.md` speaker note updated to English with reflection mention. - `assets/web/src/index.html` "Scattered Project Knowledge" solution bullets updated (bilingual) to express the three-file split and `reflection/` self-knowledge layer. ### Auth & Session Model (ADR-005) Unified key-to-session token exchange across all surfaces. All work gated on `#[cfg(feature = "ui")]`. - `KeyEntry` gains `label: String` (`#[serde(default)]`) — audit trail for key-based sessions. NCL schema `install/resources/schemas/ontoref-project.ncl` updated accordingly. - `verify_keys_list` returns `Option` instead of `Option`. - `SessionEntry` gains `id: String` — stable public identifier distinct from the bearer token, safe to expose in list responses. Prevents session enumeration by admins. - `SessionStore` gains secondary `id_index: DashMap` for O(1) `revoke_by_id`. - New `SessionStore` methods: `list_for_slug`, `list_all`, `revoke_all_for_slug`, `revoke_by_id(id, acting_slug, acting_role) -> RevokeResult`. - `POST /sessions` — key → UUID v4 token exchange. Accepts project keys or daemon admin password (`project: "_daemon"`). Rate-limited. No authentication required (it is the credential exchange endpoint). - `GET /sessions?project=slug` — list active sessions for a project (viewer+). Without `?project=` param requires daemon admin and returns all sessions. - `DELETE /sessions/{id}` — revoke by public id. Project admin: own project only. Daemon admin: any. - `require_session()` helper: validates UUID v4 Bearer → `SessionEntry`, error boxed (`Box`) to satisfy `clippy::result_large_err`. - `check_primary_auth` fast-path: UUID v4 bearer → session lookup (O(1)) before argon2 fallback (~100ms). - `project_update_keys` (`PUT /projects/{slug}/keys`) now calls `sessions.revoke_all_for_slug` in addition to actor deregistration. All in-flight UI sessions for the rotated project are immediately invalidated. - Daemon admin: `ONTOREF_ADMIN_TOKEN_FILE` (preferred — hash not visible in `ps aux`) or `ONTOREF_ADMIN_TOKEN`. Sessions use virtual slug `"_daemon"`. - `manage_login_page` / `manage_login_submit` / `manage_logout` handlers for `/ui/manage/login` and `/ui/manage/logout`. - `AdminGuard` redirects to `/ui/manage/login` when `daemon_admin_hash` is set. ### CLI Bearer Token - `bearer-args` exported from `reflection/modules/store.nu`: returns `["-H" "Authorization: Bearer $token"]` when `ONTOREF_TOKEN` is set, `[]` otherwise. - `http-get`, `http-post-json`, `http-delete` (new) in `store.nu` use `...$auth` — Bearer injected transparently, no behavior change when `ONTOREF_TOKEN` is unset. - `notify-daemon-project-add` and `notify-daemon-project-remove` in `reflection/bin/ontoref.nu` use `bearer-args`. ### Project Setup & Onboarding - `ontoref setup` is now the primary onboarding command (replaces manual `cp templates/` pattern). - `--kind ` flag: `Service` (default) | `Library` | `DevWorkspace` | `PublishedCrate` | `AgentResource` | `Mixed`. - `--parent ` flag: generates manifest with `implementation` layer + `-framework` layer and `-browse` op mode for implementation children. - Logo auto-detection: `setup` scans `assets/` for `-logo.svg`, `.svg`, `logo.svg` (and `.png` variants); inserts `ui.logo` into generated `config.ncl` when found. - `--gen-keys ["admin:label" "viewer:label"]` flag: idempotent bootstrap — skips if `role =` already present in `project.ncl`. Hashes via `ontoref-daemon.bin --hash-password`; prints passwords once to stdout. - All `mkdir` calls in setup guarded by `if not (path | path exists)`. ### Self-Description — on+re Update `.ontology/core.ncl` — 3 new Practice nodes, updated `ontoref-daemon` description and `artifact_paths`: | Node | Pole | Description | | --- | --- | --- | | `unified-auth-model` | Yang | Key→session token exchange; session.id ≠ bearer; revoke on key rotation | | `project-onboarding` | Yang | `ontoref setup` — idempotent scaffold, `--kind`, `--parent`, `--gen-keys` | `ontoref-daemon` node updated: auth/session management added to description and `artifact_paths` (`session.rs`, `auth.rs`, `login.rs`). New edges: `unified-auth-model → ontoref-daemon`, `unified-auth-model → no-enforcement` (Contradicts/Low — auth is opt-in), `ontoref-daemon → unified-auth-model` (Contains), `project-onboarding → unified-auth-model` (DependsOn), `project-onboarding → adopt-ontoref-tooling` (Complements), `project-onboarding → daemon-config-management` (DependsOn). `.ontology/state.ncl` — `self-description-coverage` transitions to `current_state = "fully-self-described"`. Blocker resolved: `reflection/backlog.ncl` created, ADR-005 recorded. `reflection/backlog.ncl` — created with 6 items: bl-001 (ontoref.dev), bl-002 (first external project), bl-003 (`ontoref keys` CLI), bl-004 (session UI views), bl-005 (Syntaxis migration), bl-006 (ADR-001 acceptance). Previous state: 4 axioms, 2 tensions, 13 practices. Current: 4 axioms, 2 tensions, 15 practices. ### Protocol - ADR-004 accepted: NCL pipe bootstrap pattern — `nickel export config.ncl | ontoref-daemon.bin --config-stdin`. Stages: Nickel evaluation → optional SOPS/Vault merge → binary via stdin. ([adr-004](adrs/adr-004-ncl-pipe-bootstrap-pattern.ncl)) - ADR-005 accepted: unified key-to-session auth model across CLI, UI, and MCP. Opaque UUID v4 tokens, `session.id ≠ bearer`, revocation on key rotation, daemon admin via `_daemon` slug. ([adr-005](adrs/adr-005-unified-auth-session-model.ncl)) --- ### Install Infrastructure - `install/` directory reorganized: binaries, bootstrapper, global CLI, resources, and validation scripts co-located. - Binary installed as `ontoref-daemon.bin`; public entrypoint bootstrapper installed as `ontoref-daemon`. Users never call `.bin` directly. - `install/ontoref-daemon-boot` (renamed from `ontoref-daemon-start`) — NCL pipe bootstrapper implementing ADR-004. Stages: `nickel export config.ncl` → optional SOPS/Vault secret merge → `ontoref-daemon.bin --config-stdin`. Supports `--dry-run`, `--sops`, `--vault`. - `install/ontoref-daemon-boot` sets `NICKEL_IMPORT_PATH` (config dir + platform data dir schemas) and `NATS_STREAMS_CONFIG` (default `~/.config/ontoref/streams.json`) before launching the binary. - `install/install.nu` — installs binary, bootstrapper, global `ontoref` CLI (ONTOREF_ROOT baked in at install time), UI assets, config skeleton, and global NATS topology. Hash-checked — unchanged files are not overwritten. - `install/config-setup.nu` — standalone validation script: `nickel typecheck` + `nickel export`, path existence checks, DB and NATS liveness probes (`nc -z -w2`). - `install/check-config-sync.nu` — CI guard asserting that every `nickel_path`-bearing field in `reflection/forms/config.ncl` has a matching `{{ name }}` reference in `reflection/forms/config.ncl.j2`, and vice versa. Wired into `just ci-lint` and `just ci-full`. ### Config Management - `install/resources/config.ncl` — default global config skeleton with full Nickel contracts (`Port`, `LogLevel`, `Rotation`, `Actor`, `Severity`). Covers: daemon, db, nats_events, log, cache, ui, mode_run, actor_init, quick_actions, nickel_import_paths. - `install/resources/streams.json` — global default NATS JetStream topology: ECOSYSTEM stream (`ecosystem.>`, 30-day retention), no project-specific consumers. Installed to `~/.config/ontoref/streams.json`. - `nats/streams.json` — ontoref project-local topology with `daemon-ontoref` and `cli-notifications` consumers on ECOSYSTEM stream. - `reflection/forms/config.ncl` + `reflection/forms/config.ncl.j2` — typedialog roundtrip for browser-based config editing (`ontoref config-edit`). Form populates fields from existing config via `nickel_path`; Tera template reconstructs full NCL with all contracts on save. - `reflection/nulib/bootstrap.nu` — Nu bootstrapper helper updated: `nats-streams-config` function resolves `NATS_STREAMS_CONFIG` default; env var passed to daemon process via `with-env`. - Daemon `nats.rs`: empty `streams_config` string → `None`, activating `TopologyConfig::load` fallback to `NATS_STREAMS_CONFIG` env var. Projects with a local `nats/streams.json` set `streams_config` explicitly in their config. ### Daemon Fixes - `--config-stdin` now exclusively skips `.ontoref/config.ncl` — project config is never loaded when stdin config is active. Previously both paths could run. - DB connection (`stratum-db`) only established when `db.enabled = true` in config. Previously connected regardless of `enabled` flag. - NATS connection (`platform-nats`) only established when `nats_events.enabled = true`. "Connecting to NATS..." log moved after the enabled check. - `NatsPublisher::connect` signature changed from `config_path: &PathBuf` (re-read file) to `config: Option<&serde_json::Value>` (already-loaded JSON). Eliminates double file read and ensures NATS uses the same config source as the rest of the daemon. - `load_config_overrides` returns `(Option, Option)` — nickel import path and parsed config JSON returned together. `apply_stdin_config` returns `serde_json::Value` directly. ### Self-Description — on+re Update `.ontology/core.ncl` — 1 new Practice node, updated `ontoref-daemon` description and artifact_paths: | Node | Pole | Description | | --- | --- | --- | | `daemon-config-management` | Yang | Install + config form/template roundtrip, CI guard, global NATS topology, config-setup validation | New edges: `daemon-config-management → ontoref-daemon` (DependsOn), `daemon-config-management → adopt-ontoref-tooling` (Complements). `.ontology/state.ncl` — `operational-mode` dimension description updated to reference ADR-004 bootstrap and `NATS_STREAMS_CONFIG` mechanism. `protocol-maturity` blocker updated to reflect install pipeline completion. `.ontology/manifest.ncl` — `tooling` layer paths updated to include `install/` and `nats/`. Previous state: 4 axioms, 2 tensions, 12 practices. Current: 4 axioms, 2 tensions, 13 practices. ### Protocol - ADR-001 accepted: ontoref extracted as a standalone protocol project, independent of stratumiops versioning and release cycle. Consumer projects adopt via `scripts/ontoref` wrapper + `.ontoref/config.ncl`. ([adr-001](adrs/adr-001-protocol-as-standalone-project.ncl)) - ADR-002 accepted: `ontoref-daemon` introduced as optional persistent daemon for NCL export caching (keyed by path+mtime), actor registry (developer/agent/CI), and notification barrier (pre-commit hook, fail-open). Supersedes stratumiops ADR-007. ([adr-002](adrs/adr-002-daemon-for-caching-and-notification-barrier.ncl)) - ADR-003 accepted: Q&A and accumulated operational knowledge persist to `reflection/qa.ncl` — typed NCL, git-versioned, accessible via MCP tools and HTTP endpoints. localStorage eliminated. Q&A entries survive session boundaries and are queryable by any actor. ([adr-003](adrs/adr-003-qa-and-knowledge-persistence-as-ncl.ncl)) ### Crates - `ontoref-ontology`: Rust crate for loading `.ontology/*.ncl` as typed structs (`Core`, `Gate`, `State`). Zero stratumiops dependencies. - `ontoref-reflection`: Rust crate for loading, validating, and executing Reflection modes as NCL DAG contracts. Optional `nats` feature (path dep: `platform-nats`). - `ontoref-daemon`: Rust crate providing HTTP API (axum), DashMap-backed NCL export cache, notify-based file watcher, and actor registry. Optional `db` feature (path dep: `stratum-db`) and `nats` feature (path dep: `platform-nats`). ### Daemon — Q&A NCL Persistence (`crates/ontoref-daemon/src/ui/qa_ncl.rs`) Line-level NCL surgery for `reflection/qa.ncl` — same pattern as `backlog_ncl.rs`. No AST parsing, no nickel-lang-core dependency. - `add_entry` — appends a typed `QaEntry` block before `],` array close; generates sequential `qa-NNN` ids - `update_entry` — in-place field mutation via bidirectional scan (question + answer fields) - `remove_entry` — removes the full block by id using backward scan for `{` and forward scan for `},` HTTP endpoints (all under `#[cfg(feature = "ui")]` except read-only GET): - `GET /qa-json` — export all Q&A entries as JSON (read-only, always enabled) - `POST /qa/add` — append new entry; returns generated id - `POST /qa/delete` — remove entry by id; invalidates NCL cache - `POST /qa/update` — mutate question + answer fields by id; invalidates NCL cache - `GET /actions/run` / `POST /actions/run` — execute a quick action by id; spawns `./ontoref ` Server-side hydration: `qa.html` receives `entries` as Tera context variable, embeds `SERVER_ENTRIES` JSON literal in the page `