## Mode guards and convergence loops (ADR-011)
- `Guard` and `Converge` types added to `reflection/schema.ncl` and
`reflection/defaults.ncl`. Guards run pre-flight checks (Block/Warn);
converge loops iterate until a condition is met (RetryFailed/RetryAll).
- `sync-ontology.ncl`: 3 guards + converge (zero-drift condition, max 2 iter).
- `coder-workflow.ncl`: guard (coder-dir-exists) + `novelty-check` step.
- Rust types in `ontoref-reflection/src/mode.rs`; executor in `executor.rs`
evaluates guards before steps and convergence loop after.
- `adrs/adr-011-mode-guards-and-convergence.ncl` added.
## Manifest capability completeness
- `.ontology/manifest.ncl`: 3 → 19 declared capabilities covering the full
action surface (daemon API, modes, Task Composer, QA, bookmarks, etc.).
- `sync.nu`: `audit-manifest-coverage` + `sync manifest-check` command.
- `validate-project.ncl`: 6th category `manifest-cov`.
- Pre-commit hook `manifest-coverage` added.
- Migrations `0010-manifest-capability-completeness`,
`0011-manifest-coverage-hooks`.
## Rust doc authoring pattern — canonical `///` convention
- `#[onto_api]`: `description = "..."` optional when `///` doc comment exists
above handler — first line used as fallback. `#[derive(OntologyNode)]` same.
- `ontoref-daemon/src/api.rs`: 42 handlers migrated to `///` doc comments;
`description = "..."` removed from all `#[onto_api]` blocks.
- `sync diff --docs --fail-on-drift`: exits 1 on crate `//!` drift; used by
new `docs-drift` pre-commit hook. `docs-links` hook checks rustdoc broken links.
- `generator.nu`: mdBook `crates/` chapter — per-crate page from `//!` doc,
coverage badge, feature flags, implementing practice nodes.
- `.claude/CLAUDE.md`: `### Documentation Authoring (Rust)` section added.
- Migration `0012-rust-doc-authoring-pattern`.
## OntologyNode derive fixes
- `#[derive(OntologyNode)]`: `name` and `paths` attributes supported; `///`
doc fallback for `description`; `artifact_paths` correctly populated.
- `Core::from_value` calls `merge_contributors()` behind `#[cfg(feature = "derive")]`.
## Bug fixes
- `sync.nu` drift check: exact crate path match (not `str starts-with`);
first-path-only rule; split on `. ` not `.` to avoid `.ontology/` truncation.
- `find-unclaimed-artifacts`: fixed absolute vs relative path comparison.
- Rustdoc broken intra-doc links fixed across all three crates.
- `ci-docs` recipe now sets `RUSTDOCFLAGS` and actually fails on errors.
mode guards/converge, manifest coverage validation, 19 capabilities (ADR-011)
Extend the mode schema with Guard (pre-flight Block/Warn checks) and Converge
(RetryFailed/RetryAll post-execution loops) — protocol pushes back on invalid
state and iterates until convergence. ADR-011 records the decision to extend
modes rather than create a separate action subsystem.
Manifest expanded from 3 to 19 capabilities covering the full action surface
(compose, plans, backlog graduation, notifications, coder pipeline, forms,
templates, drift, quick actions, migrations, config, onboarding). New
audit-manifest-coverage validator + pre-commit hook + SessionStart hook
ensure agents always see complete project self-description.
Bug fix: find-unclaimed-artifacts absolute vs relative path comparison —
19 phantom MISSING items resolved. Health 43% → 100%.
Anti-slop: coder novelty-check step (Jaccard overlap against published+QA)
inserted between triage and publish in coder-workflow.
Justfile restructured into 5 modules (build/test/dev/ci/assets).
Migrations 0010-0011 propagate requirements to consumer projects.
48 KiB
Changelog
All notable changes to ontoref are documented here.
ADRs referenced below live in adrs/ as typed Nickel records.
[Unreleased]
Rust doc authoring pattern — canonical /// convention
#[onto_api] — description now optional
description = "..."parameter is no longer required when a///doc comment exists above the handler. The proc-macro reads the first///line as the fallback description.- Same fallback applied to
#[derive(OntologyNode)]—///first line used whendescriptionattribute is absent. ontoref-daemon/src/api.rs: 42 handlers migrated —description = "..."removed from all#[onto_api]blocks, canonical///first line added above each handler.
sync diff --docs --fail-on-drift
- New
--fail-on-driftflag onsync diff: exits 1 when any crate//!has drifted from its ontology node description. Intended for pre-commit enforcement; without the flag, the command remains non-destructive and returns the table as before.
mdBook crates/ chapter
generator.nu: two helpers added —read-crate-module-doc(parses//!fromlib.rs/main.rs) andcount-pub-coverage(ratio of documented pub items).render-mdbookgeneratesdocs/src/crates/<name>.mdper workspace member://!content, pub item coverage badge, feature flags fromCargo.toml, and which practice nodes list the crate as primaryartifact_paths. Missing//!renders a warning block.SUMMARY.mdgains a# Cratessection with links to all generated pages.
Pre-commit hooks
.pre-commit-config.yaml:docs-linkshook runs rustdoc broken-link check (RUSTDOCFLAGSwith-D rustdoc::broken-intra-doc-links) on.rschanges..pre-commit-config.yaml:docs-drifthook runssync diff --docs --fail-on-drifton.rschanges.
Agent and developer directives
.claude/CLAUDE.md:### Documentation Authoring (Rust)section added — three-layer table, four authoring rules, agent discovery commands (describe workspace,describe features,sync diff --docs), crate registration procedure.
Migration
0012-rust-doc-authoring-pattern: consumer projects receive the### Documentation Authoring (Rust)section for theirCLAUDE.mdand optional pre-commit hooks (docs-links,docs-drift).
Mode guards, convergence loops, and manifest coverage enforcement
Mode schema extension (ADR-011)
- Guard type added to
reflection/schema.ncl: pre-flight executable checks withBlock(abort) orWarn(continue) severity. Guards run before any step — the protocol pushes back on invalid state instead of failing silently mid-execution. - Converge type added to
reflection/schema.ncl: post-execution convergence loop withconditioncommand,max_iterationscap, andRetryFailed/RetryAllstrategy. Modes iterate until a condition is met rather than running once blindly. - Both types exposed in
reflection/defaults.nclasGuardandConverge. - Reference implementation:
sync-ontology.nclgains 3 guards (ontology-exists, nickel-available, manifest-capabilities) and converge (iterate until zero drift, max 2 iterations). coder-workflow.nclgains guard (coder-dir-exists) and newnovelty-checkstep (anti-slop Jaccard overlap detection between pending entries and published+QA).- Nushell executor (
reflection/nulib/modes.nu): guard execution before steps, convergence loop after steps. - Rust types:
Guard,GuardSeverity,Converge,ConvergeStrategyinontoref-reflection/src/mode.rs. - Rust executor: guards evaluated pre-execution (Block returns error, Warn logs), convergence loop post-execution.
- Backward compatible:
guardsdefaults to[],convergeis optional. All 19 existing modes export unchanged.
Manifest capability completeness (19 capabilities)
.ontology/manifest.nclexpanded from 3 to 19 declared capabilities covering the full action surface: protocol spec, daemon API, reflection modes, run/step tracking, Agent Task Composer, backlog graduation, notifications, coder process memory, QA store, form system, template generation, describe query layer, drift detection, quick actions, protocol migration, config surface, search bookmarks, project onboarding, web presence.audit-manifest-coveragefunction inreflection/modules/sync.nu: cross-references Practice nodes, reflection modes, and daemon UI pages against declared capabilities.sync manifest-checkexported command for pre-commit hooks and CI.validate-project.nclgains 6th validation category:manifest-cov.- Pre-commit hook
manifest-coverage: fires on.ontology/,reflection/modes/,reflection/forms/changes. - SessionStart hook (
session-context.sh): shows manifest coverage status at session start. - Agent consumption mode description updated in manifest.
Bug fixes
find-unclaimed-artifactsinsync.nu: fixed absolute vs relative path comparison for modes and forms.path relative-to $rootapplied beforestarts-withcheck. 19 phantom MISSING items resolved.audit-claudesession-hook check: accepts both.claude/hooks/session-context.shand legacy.claude/ontoref-session-start.sh.describe modenow shows guards and converge sections.scan-reflection-mode-dagsJSON output for agents now includes guards, converge, preconditions, postconditions, and step-level cmd/on_error/verify.
Infrastructure
- Justfile restructured:
justfiles/build.just,justfiles/test.just,justfiles/dev.justadded. CI recipes delegated to canonical modules. Manifest justfile convention updated toImportsystem with 5 modules. - Manifest
claudebaseline declared:["rust", "nushell", "nickel"]guidelines, session_hook enabled. .ontology/core.ncl:ci-pipelinesPractice node added.reflection/forms/added toreflection-modesartifact_paths.
Migrations
0010-manifest-capability-completeness: consumer projects must declare ≥3 capabilities.0011-manifest-coverage-hooks: consumer projects must add pre-commit and SessionStart hooks for manifest coverage.
on+re update
| Artifact | Change |
|---|---|
.ontology/manifest.ncl |
3 → 19 capabilities; justfile/claude baselines declared; agent consumption mode updated |
.ontology/core.ncl |
ci-pipelines node; reflection/forms/ in reflection-modes; adr-011 in adr-lifecycle |
.ontology/state.ncl |
protocol-maturity catalyst updated (ADR-011, 19 caps, migrations 0010-0012); self-description-coverage catalyst updated (session 2026-03-30) |
adrs/adr-011-mode-guards-and-convergence.ncl |
New ADR: guards and converge extend mode schema rather than separate action subsystem |
| Health | 43.2% → 100.0% (31 OK / 0 MISSING / 0 STALE) |
Browser-style panel navigation + repo file routing
Graph, search, and api_catalog pages now share a uniform browser-style navigation model: back/forward history stack with cursor-into-array semantics. File artifact paths open in external browser tabs rather than being loaded inline.
crates/ontoref-daemon/templates/pages/graph.html
.artifact-linkclick handler changed from removedopenFile()tosrcOpen().panelNav._replaytype: "file"case changed tosrcOpen(e.id).
crates/ontoref-daemon/templates/pages/search.html
openFileInPanelasync function removed entirely (was loading file content inline via/api/file).srcOpen(path)function added: opens{card_repo}/src/branch/main/{path}for most files; openscard_docsfor.rsfiles when configured.CARD_REPO/CARD_DOCSJS constants injected via Tera (| safefilter required — Tera auto-escapes all{{ }}interpolations regardless of<script>context)..s-file-linkclick delegation updated to callsrcOpen.dpNav._replaytype: "file"case callssrcOpen.
crates/ontoref-daemon/templates/pages/api_catalog.html
ensureFileModalandopenFileremoved.srcOpenadded with same logic as graph and search pages.CARD_REPO/CARD_DOCSconstants injected.#detail-source-btnclick delegation callssrcOpen.
crates/ontoref-daemon/src/ui/handlers.rs
insert_brand_ctxreadscard.repoandcard.docsfrom config NCL and injectscard_repo/card_docsinto the Tera context for all pages.
card.ncl
repo = "https://repo.jesusperez.pro/jesus/ontoref"added.
reflection/migrations/0007-card-repo-field.ncl — new migration
- Check:
card.nclabsent → pass (not applicable); present +repo =found → pass; present withoutrepo =→ pending. - Instructions: add
repoand optionallydocsfields; explains howsrcOpenuses both.
on+re update
| Artifact | Change |
|---|---|
.ontology/core.ncl |
ontoref-daemon description updated — browser-style panel nav, file routing via card.repo/card.docs |
.ontology/state.ncl |
self-description-coverage catalyst updated with session 2026-03-29 |
Protocol Migration System — progressive NCL checks for consumer project upgrades (ADR-010)
Replaces the template-prompt approach with an ordered, idempotent migration system. Applied state
determined by check result alone — no state file. 6 migrations shipped; runtime ships
migrate list/pending/show with interactive group dispatch.
reflection/migrations/ — 6 ordered migrations
0001-ontology-infrastructure—.ontology/manifest.nclandconnections.nclpresent.0002-adr-typed-checks— nocheck_hintin ADR instance files (adr-[0-9][0-9][0-9]-*.ncl); check narrowed fromadrs/broad scan to exclude schema/template infrastructure files.0003-manifest-self-interrogation—capabilities[]andrequirements[]non-empty in manifest.ncl.0004-just-convention— justfile validates against canonical module convention (pending in this repo — documented gap).0005-mode-step-schema— all reflection mode steps declareactor,on_error,depends_on.0006-claude-agent-entrypoint—Agent Entry-Point Protocolsection present in.claude/CLAUDE.md.
All NuCmd checks rewritten from bash to valid Nushell: && removed, $env.VAR replacing $VAR,
no bash-style redirects. Grep checks on ADR files use adr-[0-9][0-9][0-9]-*.ncl glob.
reflection/modules/migrate.nu — new module
migrate list [--fmt] [--actor]— all migrations with applied/pending status; JSON for agents.migrate pending [--fmt] [--actor]— pending only.migrate show <id> [--fmt]— runtime-interpolated instructions; accepts short ids (002→0002).- Applied state:
run-migration-checkdispatches overFileExists | Grep | NuCmd. - No state file — idempotent by construction.
reflection/nulib/interactive.nu + help.nu — migrate group wired
group-command-info—migratecase added (list, pending, show).run-group-command—migratedispatch added.help-group—migratehelp section added; fallback "Available groups" updated.
reflection/bin/ontoref.nu — shims + aliases
main migrate,main migrate list/pending/showadded.- Short aliases:
mg,mg l,mg p.
reflection/schemas/justfile-convention.ncl — export fix
- Removed
ModuleandModuleSystemfrom the exported record (open contract fields with no default value causednickel exportto fail). Both remain asletbindings for internal NCL use.
on+re update
| Artifact | Change |
|---|---|
adrs/adr-010-...ncl |
Created — protocol migration system, progressive NCL checks |
.ontology/core.ncl |
protocol-migration-system node added; adopt-ontoref-tooling artifacts updated; adr-lifecycle updated with ADR-010; 4 new edges |
.ontology/state.ncl |
protocol-maturity catalyst updated (10 consumers, all features complete); blocker narrowed to ontoref.dev not yet published |
Manifest Self-Interrogation Layer — capabilities, requirements, critical deps (ADR-009)
Three new typed arrays in manifest_type answering operational self-knowledge queries distinct from
ontology Practice nodes. describe requirements new subcommand; describe guides extended.
ontology/schemas/manifest.ncl — three new types
capability_type—id,name,summary,rationale,how,artifacts[],adrs[],nodes[].nodes[]cross-references ontology node IDs;adrs[]cross-references ADR IDs.env_target_type—'Production | 'Development | 'Bothclassification axis for requirements.requirement_kind_type—'Tool | 'Service | 'EnvVar | 'Infrastructure.requirement_type—id,name,env,kind,version,required,impact,provision.critical_dep_type—id,name,ref,used_for,failure_impact(required),mitigation.manifest_typegainsdescription | String | default = ""(bug fix —collect-identitywas reading a field that didn't exist),capabilities[],requirements[],critical_deps[](alldefault = []).- New exports:
EnvTarget,RequirementKind,Capability,Requirement,CriticalDep.
ontology/defaults/manifest.ncl — three new builders
make_capability,make_requirement,make_critical_depadded alongside existing builders.- New type re-exports:
EnvTarget,RequirementKind,Capability,Requirement,CriticalDep.
reflection/modules/describe.nu — new subcommand + extended outputs
describe requirements— renders requirements grouped by env (Production / Development / Both) and critical deps table (name, ref, used_for, failure_impact, mitigation).--environmentflag filters.describe capabilitiesextended — loadsmanifest.capabilities?and renders aPROJECT CAPABILITIES (manifest)section with name, summary, artifacts per entry.describe guidesoutput gainscapabilities,requirements,critical_depskeys — agents on cold start viaontoref_guidesMCP tool receive full self-interrogation context without extra tool calls.- Bug fix:
collect-identitywas readingmanifest.kind?(field absent from schema, always returned"") — changed tomanifest.repo_kind?. Same fix formanifest.description?(now exists).
.ontology/manifest.ncl — ontoref self-described
descriptionfield populated.- 3 capabilities:
protocol-spec,daemon-api,reflection-modes— each with rationale, how, artifacts, adrs, nodes cross-references. - 5 requirements:
nushell(both),nickel(both),rust-nightly(dev),surrealdb(prod optional),stratumiops(dev optional) — each with impact and provision. - 3 critical deps:
nickel-lang,inventory,axum— each with failure_impact and mitigation.
on+re update
| Artifact | Change |
|---|---|
adrs/adr-009-...ncl |
Created — manifest self-interrogation layer, three semantic axes |
.ontology/core.ncl |
manifest-self-description node added (29 nodes, 59 edges); adr-lifecycle updated with ADR-009 |
.ontology/state.ncl |
protocol-maturity blocker + self-description-coverage catalyst updated |
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 fornickel export .ontoref/config.ncl | daemon --config-stdin; fields:nickel_import_paths,ui: UiConfig,log: LogConfig,mode_run: ModeRunConfig,nats_events: NatsEventsConfig,actor_init: Vec<ActorInit>,quick_actions: Vec<QuickAction>,daemon: DaemonRuntimeConfig.#[cfg(feature = "db")] db: DbConfig. All#[serde(default)].- Each section struct derives
#[derive(Deserialize, ConfigFields)]+#[config_section(id, ncl_file)]— emitsinventory::submit!(ConfigFieldsEntry{...})at link time. DaemonRuntimeConfig— optional port, timeouts, sweep intervals,notification_ack_required: Vec<String>.
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<DaemonNclConfig>replaces rawOption<serde_json::Value>.stdin_raw: Option<serde_json::Value>retained only for service-modeprojectsextraction. apply_stdin_confignow deserializes JSON toDaemonNclConfigbefore applying CLI overrides;apply_ui_configsignature changed from&serde_json::Valueto&UiConfig.load_config_overridesreturns(Option<String>, Option<DaemonNclConfig>)— 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_dirgated 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_deriveConfigFieldswith helper attributeconfig_section(id, ncl_file). Extracts serde-renamed field names; emitsinventory::submit!(ConfigFieldsEntry{section_id, ncl_file, struct_name, fields}). - Extracted
serde_rename_of(field)helper to fixclippy::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_sectionhelper to reduce nesting depth for_meta_*record merging.
crates/ontoref-daemon/src/api.rs — index_section_fields helper
- Extracted
index_section_fieldsto fixclippy::excessive_nestingat the cross-project field indexing loop. Skips_meta_*and_overrides_metakeys; 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 | traceLogRotation— enum validator:daily | hourly | neverPositiveInt—value > 0 && is_numberPort—value >= 1 && value <= 65535LogConfig— 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 toconfig_surface.logsection:contract = "contracts.ncl → LogConfig"added.- New
daemonsection:contract = "contracts.ncl → DaemonConfig", consumerdaemon-configpointing tocrates/ontoref-daemon/src/config.rs → DaemonRuntimeConfigwith 7 declared fields.
Protocol
- ADR-007 extended:
#[derive(ConfigFields)]is a second application of theinventory::submit!/inventory::collect!linker registration pattern first established by#[onto_api]. Both are now referenced from theconfig-surfacenode. - 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.nclwith_overrides_metaaudit record; original NCL source files are never modified. nickel export validates the merged result before commit; contract violations revert the override file. (adr-008)
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)emitsinventory::submit!(ApiRouteEntry{...})for each handler; auth validated at compile time (none | viewer | admin); param entries parsed asname:type:constraint:descriptionsemicolon-delimitedcrates/ontoref-daemon/src/api_catalog.rs—ApiRouteEntry+ApiParamstructs (&'static strfields for process lifetime);inventory::collect!(ApiRouteEntry);catalog()returns sortedVec<&'static ApiRouteEntry>GET /api/catalog— annotated with#[onto_api]; returns all registered routes as JSON sorted by path+method; no auth requiredGET /projects/{slug}/ontology/versions— per-file reload counters asBTreeMap<filename, u64>; counter bumped on every watcher-triggered NCL cache invalidationdescribe api [--actor] [--tag] [--auth] [--fmt json|text]— queries/api/catalog, groups by first tag, renders auth badges, param detail per route; available asonref daaliasdescribe diff [--file <ncl>] [--fmt json|text]— semantic diff of.ontology/files vs HEAD viagit show HEAD:<rel> | mktemp | nickel export; diffs nodes by id, edges byfrom→to[kind]key; available asonref dfaliasontoref_api_catalogMCP tool — callsapi_catalog::catalog()directly; filters by actor/tag/auth; returns{ routes, total }ontoref_file_versionsMCP tool — readsProjectContext.file_versionsDashMap; returns per-filename counters- Web UI:
/{slug}/apipage — 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_ctxinhandlers.rsupdated: 15 → 28 tools (previously stale for qa, bookmark, action, ontology extensions, validate, impact, guides)HelpToolJSON updated: 8 entries added (validate_adrs, validate, impact, guides, bookmark_list, bookmark_add, api_catalog, file_versions)MCP ServerHandler::get_info()instructions updated to mentionontoref_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 viatest -f || sed), 2 validate steps (nickel export with explicit import paths), 1 aggregate report steptemplates/ontology/manifest.ncl— consumer-project stub; importsontology/defaults/manifest.nclvia import-path-relative resolutiontemplates/ontology/connections.ncl— consumer-project stub; importsconnectionsschema; empty upstream/downstream/peers with format docsreflection/modes/adopt_ontoref.ncl— updated: addscopy_ontology_manifestandcopy_ontology_connectionssteps (parallel,'Continue, idempotent);validate_ontologydepends on both with'Alwaysreflection/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 diffandmain describe apiwrappers inreflection/bin/ontoref.numain d diff,main d api— short aliases withindgroupmain df,main da— toplevel aliases (consistent withd,ad,bklpattern)- QUICK REFERENCE:
describe diff,describe api,run update_ontorefentries added help describedescription updated to includediff, 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) andBookmarkStorecontractsreflection/search_bookmarks.ncl— typed store file; conforms toBookmarkStorecontractcrates/ontoref-daemon/src/ui/search_bookmarks_ncl.rs—add_entry/remove_entryvia line-level NCL surgery; auto-incrementedsb-NNNids; concurrency-safe viaNclWriteLock
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.nuused(identifier: expr)patterns inside$"..."— parsed as command calls by Nu 0.111 parser. Fix: bareidentifier: (expr)for label-value pairs; plain strings (no$) for zero-interpolation prints. Hard constraint: no(label: expr)inside$"..."in any.nufile. Soft constraint: zero-interpolation strings must not use$"...". (adr-006)
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
Nodeschema extended withadrs | Array String | default = [](Nickelontology/schemas/core.ncland inlineCoreConfigtype).- Rust
Nodestruct gainsartifact_paths: Vec<String>andadrs: Vec<String>, both#[serde(default)]— zero migration cost for existing nodes that omit the fields. describe.nubuild-howtopopulatesadrsfrom the node record;render-howto(ANSI),render-howto-md, andhowto-to-md-string(clipboard) all emit a Validated by section whenadrsis non-empty.- New
GET /api/adr/{id}?slug=<slug>endpoint — readsadrs/<stem>.ncl, exports via NCL cache, returns JSON. No auth required (read-only, loopback boundary). - Graph UI (
graph.html):adrsfield passed into Cytoscape node data. Detail panel renders "Validated by" section with clickable◆ <adr-id>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 withglob ($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-splitin.ontology/core.ncl: documents thecore.ncl(what IS) /state.ncl(where we ARE vs want to BE) /gate.ncl(when READY to cross a boundary) separation and the role ofreflection/in answering self-knowledge queries without reading code. assets/presentation/slides.mdspeaker 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 andreflection/self-knowledge layer.
Auth & Session Model (ADR-005)
Unified key-to-session token exchange across all surfaces. All work gated on #[cfg(feature = "ui")].
KeyEntrygainslabel: String(#[serde(default)]) — audit trail for key-based sessions. NCL schemainstall/resources/schemas/ontoref-project.nclupdated accordingly.verify_keys_listreturnsOption<KeyMatch { role, label }>instead ofOption<Role>.SessionEntrygainsid: String— stable public identifier distinct from the bearer token, safe to expose in list responses. Prevents session enumeration by admins.SessionStoregains secondaryid_index: DashMap<id, token>for O(1)revoke_by_id.- New
SessionStoremethods: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<Response>) to satisfyclippy::result_large_err.check_primary_authfast-path: UUID v4 bearer → session lookup (O(1)) before argon2 fallback (~100ms).project_update_keys(PUT /projects/{slug}/keys) now callssessions.revoke_all_for_slugin 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 inps aux) orONTOREF_ADMIN_TOKEN. Sessions use virtual slug"_daemon". manage_login_page/manage_login_submit/manage_logouthandlers for/ui/manage/loginand/ui/manage/logout.AdminGuardredirects to/ui/manage/loginwhendaemon_admin_hashis set.
CLI Bearer Token
bearer-argsexported fromreflection/modules/store.nu: returns["-H" "Authorization: Bearer $token"]whenONTOREF_TOKENis set,[]otherwise.http-get,http-post-json,http-delete(new) instore.nuuse...$auth— Bearer injected transparently, no behavior change whenONTOREF_TOKENis unset.notify-daemon-project-addandnotify-daemon-project-removeinreflection/bin/ontoref.nuusebearer-args.
Project Setup & Onboarding
ontoref setupis now the primary onboarding command (replaces manualcp templates/pattern).--kind <K>flag:Service(default) |Library|DevWorkspace|PublishedCrate|AgentResource|Mixed.--parent <path>flag: generates manifest withimplementationlayer +<slug>-frameworklayer and<slug>-browseop mode for implementation children.- Logo auto-detection:
setupscansassets/for<slug>-logo.svg,<slug>.svg,logo.svg(and.pngvariants); insertsui.logointo generatedconfig.nclwhen found. --gen-keys ["admin:label" "viewer:label"]flag: idempotent bootstrap — skips ifrole =already present inproject.ncl. Hashes viaontoref-daemon.bin --hash-password; prints passwords once to stdout.- All
mkdircalls in setup guarded byif 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) - 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_daemonslug. (adr-005)
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 asontoref-daemon. Users never call.bindirectly. install/ontoref-daemon-boot(renamed fromontoref-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-bootsetsNICKEL_IMPORT_PATH(config dir + platform data dir schemas) andNATS_STREAMS_CONFIG(default~/.config/ontoref/streams.json) before launching the binary.install/install.nu— installs binary, bootstrapper, globalontorefCLI (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 everynickel_path-bearing field inreflection/forms/config.nclhas a matching{{ name }}reference inreflection/forms/config.ncl.j2, and vice versa. Wired intojust ci-lintandjust 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 withdaemon-ontorefandcli-notificationsconsumers 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 vianickel_path; Tera template reconstructs full NCL with all contracts on save.reflection/nulib/bootstrap.nu— Nu bootstrapper helper updated:nats-streams-configfunction resolvesNATS_STREAMS_CONFIGdefault; env var passed to daemon process viawith-env.- Daemon
nats.rs: emptystreams_configstring →None, activatingTopologyConfig::loadfallback toNATS_STREAMS_CONFIGenv var. Projects with a localnats/streams.jsonsetstreams_configexplicitly in their config.
Daemon Fixes
--config-stdinnow 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 whendb.enabled = truein config. Previously connected regardless ofenabledflag. - NATS connection (
platform-nats) only established whennats_events.enabled = true. "Connecting to NATS..." log moved after the enabled check. NatsPublisher::connectsignature changed fromconfig_path: &PathBuf(re-read file) toconfig: 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_overridesreturns(Option<String>, Option<serde_json::Value>)— nickel import path and parsed config JSON returned together.apply_stdin_configreturnsserde_json::Valuedirectly.
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/ontorefwrapper +.ontoref/config.ncl. (adr-001) - ADR-002 accepted:
ontoref-daemonintroduced 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) - 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)
Crates
ontoref-ontology: Rust crate for loading.ontology/*.nclas typed structs (Core,Gate,State). Zero stratumiops dependencies.ontoref-reflection: Rust crate for loading, validating, and executing Reflection modes as NCL DAG contracts. Optionalnatsfeature (path dep:platform-nats).ontoref-daemon: Rust crate providing HTTP API (axum), DashMap-backed NCL export cache, notify-based file watcher, and actor registry. Optionaldbfeature (path dep:stratum-db) andnatsfeature (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 typedQaEntryblock before],array close; generates sequentialqa-NNNidsupdate_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 idPOST /qa/delete— remove entry by id; invalidates NCL cachePOST /qa/update— mutate question + answer fields by id; invalidates NCL cacheGET /actions/run/POST /actions/run— execute a quick action by id; spawns./ontoref <mode>
Server-side hydration: qa.html receives entries as Tera context variable, embeds
SERVER_ENTRIES JSON literal in the page <script> — no fetch round-trip on load.
Daemon — MCP Tools (crates/ontoref-daemon/src/mcp/mod.rs)
Four new MCP tools exposed to AI agents:
| Tool | Description |
|---|---|
ontoref_qa_list |
List Q&A entries with optional filter substring match. Never triggers ontology sync. |
ontoref_qa_add |
Append a new Q&A entry to reflection/qa.ncl; invalidates NCL cache. |
ontoref_action_list |
List all quick actions from .ontoref/config.ncl export. |
ontoref_action_add |
Create a new reflection mode at reflection/modes/<id>.ncl and register it as a quick action. |
Constraint: ontoref_qa_list and ontoref_qa_add never trigger apply steps or modify .ontology/
files (enforced by ADR-003).
Daemon — Passive Drift Observation (crates/ontoref-daemon/src/ui/drift_watcher.rs)
Background observer bridging Yang code artifacts with Yin ontology declarations:
- Watches
crates/,.ontology/,adrs/,reflection/modes/vianotifyfile watcher - 15-second debounce window before triggering scan
- Spawns
./ontoref sync scan && ./ontoref sync diffas read-only subprocesses - Parses stdout for MISSING / STALE / DRIFT / BROKEN markers
- Emits
ontology_driftnotification viapush_customwhen any drift is found - Never applies changes automatically —
applyremains a deliberate human or agent act
Started from main.rs under #[cfg(feature = "ui")]; failure to start is non-fatal (logged as warning).
Tooling
reflection/modules/: 16 Nushell operational modules (adr.nu,backlog.nu,coder.nu,describe.nu,sync.nu, etc.)reflection/modes/: 10 NCL DAG operational modes includingadopt_ontoref,sync-ontology,coder-workflow,create-prreflection/forms/: 7 interactive NCL forms for ADR lifecycle, backlog, and adoptiontemplates/: Consumer-facing adoption templates (ontoref-config.ncl,ontology/,scripts-ontoref)./ontoref: Bash entry point with actor auto-detection, advisory file locking, and Nushell version guard (>= 0.110.0)
Self-Description — on+re Update
.ontology/core.ncl updated with 3 new Practice nodes and 9 new edges:
| Node | Pole | Description |
|---|---|---|
qa-knowledge-store |
Yin | Q&A entries as typed NCL — accumulated knowledge queryable by any actor |
quick-actions |
Yang | Runnable shortcuts over reflection modes; configured in .ontoref/config.ncl |
drift-observation |
Spiral | Passive bridge between Yang code artifacts and Yin ontology declarations |
New edges: qa-knowledge-store → dag-formalized, qa-knowledge-store → coder-process-memory,
ontoref-daemon → qa-knowledge-store, quick-actions → reflection-modes,
quick-actions → ontoref-daemon, describe-query-layer → quick-actions,
drift-observation → ontoref-daemon, drift-observation → ontology-vs-reflection,
drift-observation → reflection-modes.
Previous state: 4 axioms, 2 tensions, 9 practices. Current: 4 axioms, 2 tensions, 12 practices.
reflection/schemas/qa.ncl — QaStore and QaEntry types (id, question, answer, actor, created_at,
tags, related, verified).
reflection/qa.ncl — typed store file, conforms to QaStore contract, Nickel typecheck must pass.
ontoref uses its own ADR system to track decisions. Architectural rationale lives in adrs/, not in this file.