Self-Describing Protocol for Evolving Codebases
  • Rust 64.2%
  • HTML 13.3%
  • Nickel 7.7%
  • Nushell 7.3%
  • Shell 3.4%
  • Other 3.9%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
claude-bot 44b1a1233f
Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (push) Has been cancelled
Rust CI / Check + Test + Lint-1 (push) Has been cancelled
feat(substrate): an oplog history can be exported, replayed, and made a declared mode
adr-100 left «versioning the evidence» open and the amended Q&A stated its
conditions. This is the mechanism those conditions describe, built BEFORE the
setting that selects it — an option nobody can take is not an option, and this
project has spent the day retiring surfaces that declared what no path
exercised.

WHAT IT IS. `history.rs` exports an oplog to `<name>.ops`: one operation per
line, `<id> <canonical-hex>`, ordered by OpId. Not the .oplog itself — a redb
file's bytes depend on the writer, the format version and whether a normalising
open has happened, three facts about the FILE and none about the history it
holds, so committing it would mean binary conflicts nobody can resolve.

THE FILE ORDER IS NOT THE APPLY ORDER, and that is load-bearing. Lines are
id-sorted so git has something stable to diff and union-merge; they are applied
in HLC order because append validates that every parent exists and that the
timestamp exceeds every parent's. A union merge produces a correctly-sorted file
whose id order says nothing about causality — sorting on import is what keeps
that safe, and there is a test that reverses every line to prove it.

NO LEDGER. `OpLog::append` is idempotent by OpId, so replaying an export over a
populated log is a no-op for everything already present. «Load it once» needs no
record of what was loaded, and a test asserts the second import applies zero.

An id that does not address its payload is refused rather than appended: storing
the op under the id its payload really has would be silent corruption.

WIRING. `--extract-history-mode local|shared`, defaulting to local. Under
shared the export is replayed BEFORE the delta is computed — after would compare
the graph against an empty log, produce a full re-assert, and mint a second
history for facts already recorded, which is the divergence shared exists to end
— and rewritten after a successful reconciliation, never during a dry run.

The flag exists rather than the binary reading project config so `sync substrate`
stays the one place config is interpreted.

MEASURED END TO END. A replica holding only the export and no oplog replayed 247
ops, asserted ZERO new cells, and landed on the origin's ontology_id AND
state_root. Under local only the second would have matched. As a side effect the
1463-assert failure a fresh clone meets under local does not occur under shared,
because the history arrives with the clone.

config-setup.nu now prints the option, both values with their consequences, and
the default when nothing is declared — shown, never set there, because this is a
property of a repository and not of a machine: two people sharing a repo must
agree, and a machine-level default would let them disagree in silence.

Claude-Session: https://claude.ai/code/session_01WJUC2PvDfmScdCQGGyhvYn
2026-08-20 23:39:42 +01:00
.cargo chore: clean up for constellation migration 2026-07-10 01:44:59 +01:00
.config feat: workflow layer model — NCL-first CI/build/distribution generator 2026-04-08 14:20:38 +01:00
.github/workflows chore: add ci and dev settings 2026-03-13 00:15:49 +00:00
.governance chore: clean up for constellation migration 2026-07-10 01:44:59 +01:00
.vale chore: add ci and dev settings 2026-03-13 00:15:49 +00:00
.woodpecker feat(substrate): the extraction records the address that reproduces, not only the one that identifies a copy 2026-08-20 23:01:52 +01:00
assets chore: add assets for daemon and svgs 2026-07-18 00:58:53 +01:00
crates feat(substrate): an oplog history can be exported, replayed, and made a declared mode 2026-08-20 23:39:42 +01:00
domains feat(domains): a domain page declares where its template resolves from, and ontoref stops carrying a foreign one 2026-08-20 10:52:12 +01:00
examples refactor(positioning): difusión becomes dissemination where the loader and the catalog read it 2026-08-18 17:46:23 +01:00
install feat(substrate): an oplog history can be exported, replayed, and made a declared mode 2026-08-20 23:39:42 +01:00
justfiles feat(substrate): the extraction records the address that reproduces, not only the one that identifies a copy 2026-08-20 23:01:52 +01:00
lian-build chore: clean up for constellation migration 2026-07-10 01:44:59 +01:00
nats feat: unified auth model, project onboarding, install pipeline, config management 2026-03-13 20:56:31 +00:00
ontology fix(carriers): three files stop asserting what they never governed 2026-08-18 17:47:47 +01:00
provisioning chore: clean up for constellation migration 2026-07-10 01:44:59 +01:00
scripts fix(oplog): record a path a clone can follow, and keep redb where the gate holds 2026-07-30 03:41:27 +01:00
templates chore: clean up for constellation migration 2026-07-10 01:44:59 +01:00
.clippy.toml chore: add ci and dev settings 2026-03-13 00:15:49 +00:00
.devconfig.ncl feat(workspace): peer paths a clone can reach, and a map that says where from 2026-07-30 03:43:03 +01:00
.gitignore chore: no target paths 2026-08-20 10:05:28 +01:00
.markdownlint-cli2.jsonc fix(lint): exclude target-local from markdownlint 2026-07-30 00:51:03 +01:00
.ontoref-backup-pre-0023.tgz chore: clean up for constellation migration 2026-07-10 01:44:59 +01:00
.pre-commit-config.yaml fix(hooks): docs-drift invokes the CLI; two hooks that could never fire here are removed 2026-08-11 23:38:46 +01:00
.rustfmt.toml chore: add ci and dev settings 2026-03-13 00:15:49 +00:00
.shellcheckrc chore: add ci and dev settings 2026-03-13 00:15:49 +00:00
.taplo.toml fix(ci): the TOML formatter stops being a gate that is red by construction 2026-08-20 21:55:10 +01:00
.vale.ini chore: add ci and dev settings 2026-03-13 00:15:49 +00:00
.yamllint-ci.yml chore: add ci and dev settings 2026-03-13 00:15:49 +00:00
Cargo.lock refactor(daemon): the external store leaves and redb 4 becomes the only substrate 2026-08-20 21:54:44 +01:00
Cargo.toml refactor(daemon): the external store leaves and redb 4 becomes the only substrate 2026-08-20 21:54:44 +01:00
CHANGELOG.md docs(changelog): the routed-operation envelope and the delegation contract 2026-08-14 23:38:30 +01:00
CODE_OF_CONDUCT.md chore: add ci and dev settings 2026-03-13 00:15:49 +00:00
CONTRIBUTING.md chore: add ci and dev settings 2026-03-13 00:15:49 +00:00
Cross.toml fix(distribution): make the release path executable end to end 2026-07-29 00:02:39 +01:00
deny.toml refactor(daemon): the external store leaves and redb 4 becomes the only substrate 2026-08-20 21:54:44 +01:00
diagram.md chore: clean up for constellation migration 2026-07-10 01:44:59 +01:00
Dockerfile chore: clean up for constellation migration 2026-07-10 01:44:59 +01:00
justfile fix(just): anchor on source_directory() so the member composes from the root 2026-08-06 04:04:25 +01:00
LICENSE-APACHE docs(license): add LICENSE-MIT and LICENSE-APACHE, amend the README section 2026-07-30 11:19:11 +01:00
LICENSE-MIT docs(license): add LICENSE-MIT and LICENSE-APACHE, amend the README section 2026-07-30 11:19:11 +01:00
ontoref chore: update crates for view and cli 2026-07-18 00:57:58 +01:00
README.md refactor(daemon): the external store leaves and redb 4 becomes the only substrate 2026-08-20 21:54:44 +01:00
SECURITY.md chore: add ci and dev settings 2026-03-13 00:15:49 +00:00

ontoref


ontoref is a protocol specification and tooling layer for structured self-knowledge in software projects. It provides schemas, Nushell automation, and Rust crates so that projects can describe what they are, record architectural decisions, track operational state, and execute formalized procedures — all as typed, queryable artifacts.


Axioms

Axiom Meaning
Protocol, Not Runtime Never a runtime dependency. Projects adopt the protocol; ontoref provides the schemas and modules to do so.
Self-Describing Consumes its own protocol: .ontoref/{ontology,adrs,reflection}/ in this repo ARE ontoref running against itself (consolidated per ADR-032).
No Enforcement ontoref defines contracts. There is no enforcement mechanism. Coherence is voluntary and emerges from justified adoption.
DAG-Formalized Knowledge Concepts, tensions, decisions, state — encoded as DAGs. Enables transversal queries and impact analysis.

Tiers — coexisting permanently (ADR-029)

Adoption is voluntary, additive, and offline-first. A project picks the lowest tier that delivers the value it needs and climbs only when concrete pressure justifies the cost. Tier choice is per-project, indefinite, and recorded as a deliberate act (ops.tier in .ontoref/config.ncl) — no code path ever migrates a project's tier silently.

Tier Adopts Authoritative state Mutation path Cryptography
tier-0 Minimal NCL files edit anywhere none
tier-1 Verifiable substrate NCL + commit layer edit + reconcile blake3 state_root
tier-2 Operations layer Rust dispatch_op only blake3 + Ed25519 witnesses

Each tier includes the one below plus its delta; no tier removes a lower tier's capabilities. No tier requires network or external services — the default commitment, sync, and blob backends are all in-memory/filesystem; P2P transports (Iroh / Hypercore / Radicle / NATS) and remote backends (S3 / OCI) are trigger-based. The same ontoref-daemon binary serves every tier; build features (db, nats, ui, mcp, graphql) are orthogonal to tier.

Layers

ontology/                 Protocol specification — Nickel schemas/defaults for nodes, edges, ADRs, state, gates, positioning
crates/                   Rust implementation — typed struct loaders, ops, validators, daemon
.ontoref/ontology/        Self-description — ontoref's own ontology, state, gate, manifest
.ontoref/adrs/            Architecture Decision Records — typed NCL with constraints and ondaod evaluations
.ontoref/reflection/      Operational tooling — Nushell modules, DAG modes, forms, schemas, migrations
.ontoref/catalog/         Operations + validators (tier-2) — typed NCL declarations
.ontoref/positioning/     Four-element framework (ADR-035/043) — three orthogonal axes bound by a Proof seam (opt-in, tier-orthogonal)
.coder/interactions.jsonl Interaction trace (ADR-037) — parse-first session records as JSONL (opt-in, tier-orthogonal)
.ontoref/artifacts/       Generated artefacts (api-catalog, etc.)
.ontoref/card.ncl         Project beacon — typed self-definition (optional `primary_value_prop_id`)
.governance/              Governed delivery (ADR-063/066, migration 0041) — human-signed SOWs, witness.pub, signed receipts (opt-in)

Per ADR-032 the consumer-facing surface is consolidated under a single hidden root .ontoref/. Layout is config-driven (LayoutConfig); the defaults shown above may be overridden via .ontoref/config.ncl[layout].

Crates

The workspace is 14 crates on a strict dependency hierarchy, organized by tier. All share a single version ([workspace.package].version).

Tier-0 — adoption surface

Crate Purpose
ontoref-ontology .ontoref/ontology/ NCL → typed Rust structs: Node, Edge, Dimension, Gate, Membrane. Node carries artifact_paths and adrs (Vec<String>, serde(default)); Edge carries kind (EdgeType, nine reconciled kinds) and symbolic Weight ('High/'Medium/'Low), single-source with the schema enum + ontology/defaults/edge-inverses.ncl (ADR-069). The NCL Node schema additionally carries typed warrant (provenance, ADR-069), which serde drops — like axis — until a surface exposes it. Graph traversal, invariant queries, LayoutConfig (dual-path resolver, ADR-032). Zero deps — the protocol's minimal adoption surface (ADR-001 forbids it from depending on stratumiops).
ontoref-reflection NCL DAG contract executor with guards (pre-flight Block/Warn checks) and convergence loops (RetryFailed/RetryAll). ADR lifecycle, step dep resolution, config seal. stratum-graph + stratum-state required.
ontoref-derive Proc-macro crate. #[onto_api(...)] annotates HTTP handlers — description is optional when a /// doc comment exists (first line used as fallback). #[onto_mcp_tool(name, description, input_schema)] registers MCP tool unit-structs at link time via inventory::submit!(McpToolEntry{...}); the annotated item is emitted unchanged and ToolBase/AsyncTool impls remain on the struct. #[derive(OntologyNode)] + #[onto(id, name, paths, description, adrs)] auto-registers nodes via inventory::submit!, merged into Core by merge_contributors(). #[derive(ConfigFields)] + #[config_section(id, ncl_file)] registers config struct fields. All four aggregate via inventory::collect!.

Tier-1 / tier-2 — verifiable substrate (per ADR-023/024/025/026/027)

Crate Purpose
ontoref-types Shared substrate primitives: content hashes, ids, canonical serialization.
ontoref-blobs Content-addressed blob store; default LocalFilesystemBlobs, S3/OCI trigger-based.
ontoref-triples Triple store for the content-addressed ontology representation.
ontoref-commit Commit layer + state_root (blake3 Merkle); the tier-1 boundary.
ontoref-oplog Append-only operation-log DAG; the witnessed history of mutations.
ontoref-query Query surface over the substrate (cells, witnesses, history).
ontoref-sync Pluggable sync (CRDT per domain, ADR-027); default FilesystemSync, P2P trigger-based.
ontoref-ops Tier-2 operations dispatch — dispatch_op, three validation planes (ADR-026), Ed25519 witness emission (ADR-024).
ontoref-core Substrate composition root tying the layers together.
ontoref-ontology-content Content-addressed ontology bridge between ontoref-ontology and the substrate.

Daemon

Crate Purpose
ontoref-daemon HTTP UI (11 pages), actor registry, notification barrier, MCP (34 tools), search engine, search bookmarks, NCL export cache, per-file ontology versioning, annotated API catalog, Agent Task Composer. Storage is the embedded redb substrate — no external database (ADR-099). nats is feature-gated; builds standalone with --no-default-features.

ontoref-daemon caches nickel export results (keyed by path + mtime), reducing full sync scans from ~2m42s to <30s. The daemon is always optional — every module falls back to direct subprocess when unavailable.

Daemon Capabilities

Unified Auth Model — all surfaces (CLI, UI, MCP) exchange a key for a UUID v4 session token via POST /sessions. Token lifetime: 30 days, O(1) lookup. Project keys carry role (admin|viewer) and label for audit trail. Daemon-level admin via ONTOREF_ADMIN_TOKEN_FILE. GET /sessions and DELETE /sessions/{id} for session visibility and revocation. Key rotation invalidates all sessions for the rotated project. CLI injects ONTOREF_TOKEN as Bearer automatically.

Q&A Knowledge Store — accumulated Q&A entries persist to reflection/qa.ncl (typed NCL, git-versioned). Not localStorage. Any actor — developer, agent, CI — reads the same store.

MCP Server — 34 tools over stdio and streamable-HTTP, all registered at link time via #[onto_mcp_tool] (no manual catalog wiring). Categories: discovery, retrieval, project state, ontology, backlog, validation, Q&A, bookmarks, API surface. Representative subset:

Tool What it does
ontoref_guides Full project context on cold start: axioms, practices, gate, actor policy
ontoref_api_catalog Annotated HTTP surface — all routes with auth, actors, params, tags
ontoref_file_versions Per-file reload counters — detect which ontology files changed
ontoref_validate_adrs Run typed ADR constraint checks; returns pass/fail per constraint
ontoref_validate Full project validation: ADRs, content assets, connections, gate consistency, manifest coverage
ontoref_impact BFS impact graph from a node, optionally across project connections
ontoref_qa_list List Q&A entries with optional filter
ontoref_qa_add Append a new Q&A entry to reflection/qa.ncl
ontoref_action_list List quick actions from .ontoref/config.ncl
ontoref_action_add Create a reflection mode + register as a quick action

Search Bookmarks — search results persist to reflection/search_bookmarks.ncl (typed NCL, BookmarkEntry schema). Same atomic-write pattern as Q&A. IDs are sequential sb-NNN. Concurrency-safe via NclWriteLock. Add and remove from the daemon search UI.

Personal Ontology Schemasontology/schemas/career.ncl, personal.ncl, project-card.ncl provide typed contract layers for career and content artifacts (Skills, WorkExperience, Talks, Content lifecycle, Opportunities, PublicationCards). All types carry linked_nodes referencing core ontology node IDs — bridging career artifacts into the DAG. Five content/career reflection modes (draft-application, draft-email, generate-article, update-cv, write-cfp) query these schemas to ground output in declared project artifacts rather than free-form prose.

API Catalog — every HTTP handler carries #[onto_api(method, path, auth, actors, params, tags)]. description is sourced from the first /// doc line above the handler — no duplication with doc comments. At link time inventory::submit! registers each route. GET /api/catalog returns the full annotated surface as JSON. The /ui/{slug}/api page renders it with client-side filtering (method, auth, path). describe api [--actor] [--tag] [--fmt] renders the catalog in the CLI. ontoref_api_catalog exposes it to MCP agents.

Semantic Diffdescribe diff [--file <ncl>] [--fmt json|text] computes a node- and edge-level diff of .ontoref/ontology/ files against the last git commit. Reports added/removed/changed nodes by id and edges by from→to[kind] key — not a text diff.

Per-File Versioning — each ontology file tracked in ProjectContext.file_versions: DashMap<PathBuf, u64>. Counter increments on every watcher-triggered reload. GET /projects/{slug}/ontology/versions and ontoref_file_versions MCP tool expose the map. Dashboard surfaces the counters.

ADRNode Linkage — nodes declare which ADRs validate them via adrs: Array String. describe surfaces a Validated by section per node (CLI and --fmt md). The graph UI renders each ADR as a clickable link that opens the full ADR content via GET /api/adr/{id}.

Browser-Style Panel Navigation — graph, search, and api_catalog UI pages carry a back/forward history stack (cursor-into-array model). Clicking nodes, ADRs, or search results pushes to history; clicking artifacts opens the source file in the configured repository or docs. card.repo in card.ncl resolves to {repo}/src/branch/main/{path} (Gitea format). For .rs files, card.docs redirects to the cargo docs URL instead. insert_brand_ctx injects both as card_repo/card_docs into every Tera template.

Passive Drift Observation — background file watcher that detects divergence between Yang code artifacts and Yin ontology. Watches crates/, .ontoref/ontology/, adrs/, reflection/modes/. After a 15s debounce runs sync scan + sync diff; emits an ontology_drift notification when MISSING/STALE/DRIFT/BROKEN items are found. Never applies changes — apply is always deliberate.

Quick Actions — runnable shortcuts over reflection modes, configured as quick_actions in .ontoref/config.ncl. Accessible from HTTP (/actions), CLI (ontoref), and MCP (ontoref_action_list/add).

Config Surface — per-project config introspection, coherence verification, and documented mutation. Rust structs annotated with #[derive(ConfigFields)] + #[config_section(id, ncl_file)] register their field names at link time via inventory::submit!(ConfigFieldsEntry{...}). The daemon queries inventory::iter::<ConfigFieldsEntry>() at startup to build a zero-maintenance registry of which Rust fields each struct reads from each NCL section. Multi-consumer coherence (GET /projects/{slug}/config/coherence) compares the inventory registry against NCL export keys, Nu script accessor patterns, and CI fields declared in manifest.ncl — any NCL field claimed by no consumer is flagged unclaimed. GET /projects/{slug}/config/quickref generates living documentation (rationales, override history, coherence status) on demand.

Config mutation never modifies source NCL files. PUT /projects/{slug}/config/{section} writes a {section}.overrides.ncl file with only the changed fields plus a _overrides_meta audit record (actor, reason, timestamp, previous value), then appends a single idempotent import line to the entry-point NCL using the & merge operator. nickel export validates the merged result against the section's declared contract before committing; contract violations revert the override file and return the nickel error verbatim. NCL contracts (std.contract.from_validator) are the single validation gate — Rust structs are contract-trusted readers with #[serde(default)].

Ontoref demonstrates the pattern on itself: .ontoref/contracts.ncl applies LogConfig and DaemonConfig contracts to .ontoref/config.ncl. (ADR-008)

Operations & Catalog Extensibility (tier-2) — tier-2 mutations route exclusively through dispatch_op: typed preconditions, three validation planes (ADR-026), an Ed25519 witness per act, oplog DAG append. Operations and validators are declared as typed NCL in .ontoref/catalog/ and the catalog is discoverable across projects (ADR-030) via ADR-028 content-addressing. The OperationDecl / ValidatorDecl contracts carry a kind discriminator admitting 'Rust (default, executable today via #[onto_operation] + inventory), 'NclTransform, 'Wasm, and 'Sidecar (ADR-034, migration 0025). The schema admits all four todaydeclare before execute: a non-Rust kind is declarable but unexecutable until its executive backend lands (Sidecar is Phase A, near-term; Wasm / NclTransform are trigger-deferred per ADR-030), and the daemon returns a structured 501 rather than a silent 404. Two Hard guarantees keep the design honest: wasmtime-not-in-default-daemon-build (adding the 'Wasm kind never pulls a WASM runtime into the default build — protocol-not-runtime stays intact) and non-rust-kinds-require-ondaod-pre (non-Rust ops can't run ondaod inline, so they MUST declare evaluate_ondaod in constraints.pre — discipline becomes structural). Four worked examples that typecheck today live in examples/catalog-extension/ (rust · sidecar · ncl-transform · wasm); ore q catalog extension is the FAQ. (ADR-034, ADR-030)

Protocol Migration System — protocol upgrades for consumer projects expressed as ordered NCL files in reflection/migrations/NNN-slug.ncl. Each migration declares a typed check (FileExists | Grep | NuCmd) whose result IS the applied state — no state file, fully idempotent. migrate list shows all migrations with applied/pending status; migrate pending lists only what is missing; migrate show <id> renders runtime-interpolated instructions (project_root and project_name auto-detected). NuCmd checks are valid Nushell (no bash &&, $env.VAR not $VAR). Grep checks targeting ADR files scope to adr-[0-9][0-9][0-9]-*.ncl to exclude schema/template infrastructure files. 29 migrations shipped (00010029); 0012-rust-doc-authoring-pattern adds the /// → //! → node description three-layer doc convention; 0025-catalog-kind-field ships the catalog kind discriminator; 0027/0028/0029 ship the positioning layer, interaction trace, and OCI distribution. (ADR-010)

Manifest Self-Interrogationmanifest_type gains three typed arrays that answer self-knowledge queries agents and operators need on cold start: capabilities[] (what the project does, why it was built, how it works — with explicit nodes[] and adrs[] cross-references into the DAG), requirements[] (prerequisites classified by environment: 'Production | 'Development | 'Both and kind: 'Tool | 'Service | 'EnvVar | 'Infrastructure), critical_deps[] (external dependencies with required failure_impact and optional mitigation). describe requirements surfaces these; describe guides and ontoref_guides include all three arrays in their output. (ADR-009)

Domain Extension System — CLI commands conditional on repo_kind. The ontoref bash wrapper resolves the first argument against $ONTOREF_ROOT/domains/{id}/repo_kinds.txt before delegating to the Nu dispatcher; if the project's repo_kind matches, the domain's commands.nu is dispatched directly. Each domain ships domain.ncl (typed contract: commands, pages, short_alias, repo_kinds), commands.nu (Nu entry point), and repo_kinds.txt (grep-readable, sub-1ms dispatch). Two domains shipped: personal (PersonalOntology — cfp, career, content, opportunities) and provisioning (DevWorkspace/Mixed — state, connections, gates, card, backlog). Short aliases (personal, prov) work as both ore prov <cmd> and standalone prov <cmd>. ore help and describe capabilities surface the active domain automatically. New domains require only three files — no changes to the Nu dispatcher. (ADR-012)

Mode Hierarchy Validationvalidate modes [--check] reads reflection/defaults/workflow.ncl::level_hierarchy and checks every .ncl mode file for: level declared, strategy declared, delegate chain coherent, compose extends references valid. mode resolve <id> prints which hierarchy level handles the given mode and why — and (ADR-045) the full traversal path plus the chain scope, not a single hop. validate modes --self-test generates synthetic fixtures in a temp dir for fast CI smoke-testing of the validator itself. (ADR-018)

Domain Co-Tenancy Validation (ADR-045) — validate hosts [--check] validates recursive level chains and cross-project hosting declared in manifest.ncl::hosts. Five checks: chain-ref (hosted chain resolvable by local catalog domain or digest pin — witness, not clone), mutation-sovereignty (no local op may render_paths into a hosted mount — the host must not mutate hosted authoritative state), chain-root (the level.parent walk terminates at a 'Base; a cycle is a Hard failure) — all Hard; layer3-tag and derived-index — Soft. Levels are relative: depth is derived by walking level.parent and is uncapped. validate hosts --self-test exercises every check on synthetic fixtures. (ADR-045)

Project Picker — vault and registry badges — each project card surfaces OCI state inline: registry participant badge (⟳ <participant>) when registry_provides is declared; vault badge (⛁ <vault_id> · N) coloured green (declarative) or amber (legacy) when sops.enabled is true. Expanded project panel shows a collapsible Registry section with namespace, endpoint, and push/pull capability. The manage page adds Runtime Services toggles — MCP and GraphQL can be switched without a daemon restart via HTMX POST /ui/manage/services/{service}/toggle.

VCS Abstraction Layerreflection/modules/vcs.nu exposes a uniform API over jj and git: detect, show-committed, restore-file, remote-url, current-branch, uncommitted-files, commit-count. All ontoref modules consume vcs.nu — never hardcoded ^git. Detection is filesystem-based (.jj/ vs .git/), no config required. jj is opt-in: all operations degrade to git when .jj/ is absent. reflection/bin/jjw.nu wraps jj workspaces, ontoref runs, and optional Radicle patch submission into a single jjw agent create|step|publish|merge|discard lifecycle for agent-driven development. jjw-ncl-merge.nu is a jj merge tool for .ontoref/ontology/ NCL conflicts, registered manually in ~/.config/jj/config.toml. jj and Radicle are not protocol requirements — consumer projects use plain git without any configuration change.

Install

just install-daemon        # build + install binary, bootstrapper, CLI, UI assets, config skeleton
ontoref config-edit        # browser form → ~/.config/ontoref/config.ncl
ontoref-daemon-boot        # NCL pipe bootstrap: nickel export config.ncl | daemon --config-stdin
ontoref-daemon-boot --dry-run   # preview composed JSON without starting

Installed layout (~/.local/bin/):

Binary Role
ontoref Global CLI dispatcher — all reflection modes, ADR lifecycle, daemon control
ontoref-daemon Bootstrapper (public entrypoint) — validates config via Nickel, pipes JSON to binary
ontoref-daemon.bin Compiled Rust binary — never called directly

Global config at ~/.config/ontoref/config.ncl (type-checked Nickel). Global NATS stream topology at ~/.config/ontoref/streams.json. Project-local topology override via nats/streams.json + nats_events.streams_config in .ontoref/config.ncl.

Install without a source checkout (OCI distribution, ADR-038)

Paths share one build. The daemon is an optional accelerator (ADR-029) — the curl|sh path installs a CLI + data layer that work without it.

# 1. curl | sh — install the CLI + data layer (linux and macOS, amd64/arm64)
curl -fsSL https://ontoref.dev/public/install.sh | sh
curl -fsSL https://ontoref.dev/public/install.sh | sh -s -- --prefix ~/.local
sh install.sh --uninstall            # remove binaries; --purge also removes data + config

# 2. Container — run the daemon as a service (multi-arch, cosign-signed)
docker run --rm -p 7891:7891 reg.librecloud.online/ontoref/ontoref-daemon:0.1.8

Access and verification are different routes, on purpose. install.sh detects OS/arch and first fetches the per-platform bundle as a plain file from https://ontoref.dev/public/dist/ — no account, no token, no oras. The registry namespace ontoref/dist is not anonymous-pull (GET /v2/ontoref/dist/tags/list answers UNAUTHORIZED), so it is the route for whoever wants the signed and attested artifact, not the route for merely installing. The installer falls back to it via oras, then to the OCI Distribution API by hand.

The static mirror carries one release, the current one. Asking for any other --version leaves the static branch and takes the registry, out loud — it does not silently hand you the current bundle under another name.

Either way the .sha256 sidecar is verified before anything is laid out, and the layout of binaries + data + wrappers is exactly what install.nu produces. nickel is bundled; nushell is the only external runtime dependency (detected, with install guidance if absent). Published platforms: linux/{amd64,arm64} and darwin/{amd64,arm64}.

Distribution is modeled in the workflow layer, not hand-maintained: the release layer in .ontoref/ontology/workflow.ncl drives the build-once pipeline (cross compiles each arch once; both the bundle and the buildah-assembled image consume that same binary). Regenerate the artifacts — never edit them by hand:

ore workflow list                         # the release layer is visible
ore workflow generate --layer release     # → .woodpecker/release.yml, install/install.sh, justfiles/release.just
ore q oci distribution                    # FAQ: both paths, build-once, forbidden patterns

Onboarding a project

cd /path/to/my-project
ontoref setup                          # idempotent; kind: Service by default
ontoref setup --kind Library           # Library | Service | DevWorkspace | PublishedCrate | AgentResource | Mixed | PersonalOntology
ontoref setup --parent /path/to/fw     # implementation child: adds framework layer + browse mode
ontoref setup --gen-keys ["admin:dev" "viewer:ci"]   # bootstrap auth keys (no-op if keys already exist)

ontoref setup creates .ontoref/project.ncl, .ontoref/config.ncl (with logo auto-detection), .ontoref/ontology/ scaffold, adrs/, reflection/modes/, backlog.ncl, qa.ncl, git hooks, and registers the project in ~/.config/ontoref/projects.ncl.

For existing projects that predate setup, or to bring an already-adopted project up to the current protocol version (adds manifest.ncl and connections.ncl):

ontoref --actor developer adopt_ontoref    # first-time adoption
ontoref run update_ontoref                 # bring existing project to protocol v2

The update_ontoref mode detects missing v2 files, adds them idempotently, validates both with nickel export, scans ADRs for deprecated check_hint fields, and prints a protocol update report. The reusable reflection/templates/update-ontology-prompt.md guides an agent through full ontology enrichment in 8 phases.

ONTOREF_PROJECT_ROOT is set by the consumer wrapper — one ontoref checkout serves multiple projects.

Credential vault and registry federation

ontoref ships a credential model for projects publishing or consuming OCI artifacts (domain contracts and integration modes) on a self-hosted registry like ZOT. The model is layered, declarative, and avoids ambient docker config:

  • Layer 0 — master age private key (.kage) per actor, declared in ~/.config/ontoref/config.ncl::vault.master_key_path (override per-project in <project>/.ontoref/project.ncl::sops.master_key_path)
  • Layer 1access.sops.yaml per project, multi-recipient encrypted; carries zot_username, zot_password, vault_key, cosign_password
  • Layer 2 — operation credentials (RO/RW per registry entry) under src-vault/registry/, referenced by manifest.ncl::registry_provides[].credential_sops*

Tenant isolation within a single vault uses sops creation_rules driven by sops.recipient_groups + sops.recipient_rules in project.ncl — different clients/agents get disjoint recipient sets per file, all in one vault. Multi-vault is explicitly out of scope (ADR-019).

Adoption — copy a template from install/resources/templates/sops/:

Template When to use
single-team/ One team, no tenant separation
multi-tenant/ Multiple clients with isolated credentials
agent-first/ AI agents (MCP) read a single read-only credential

For integration artifacts (publishing domain contracts or consuming someone's mode), templates in install/resources/templates/integration/: domain-producer/, mode-producer/, mode-consumer/.

Day-to-day:

ore secrets bootstrap         # create vault for a new project (admin only)
ore secrets sync              # pull latest src-vault from ZOT
ore secrets open              # acquire OCI lock + edit access.sops.yaml
ore secrets close             # impact report → push → release lock
ore secrets describe          # full inventory: groups, rules, scopes, ops
ore secrets audit             # 6 ADR-017 + ADR-019 constraint checks

See FAQ entries in reflection/qa.ncl for diagrams, troubleshooting, and the 15 named errors. ADRs: 017 (vault model) and 019 (per-file recipient routing).

Prerequisites

  • Nushell >= 0.110.0
  • Nickel (for schema evaluation)
  • Rust toolchain (for building crates)
  • Just (for CI recipes)
  • age + sops (credential vault, ADR-017/019)
  • oras + cosign ≥ 2 (OCI artifact federation)
  • restic or kopia (vault snapshots)

To build ontoref-daemon with NATS support, the stratumiops repo must be checked out at ../../../../stratumiops/code (constellation layout — sibling project, code/ sub-repo). Without it, build without default features:

cargo build -p ontoref-daemon --no-default-features
cargo build -p ontoref-ontology   # always standalone

Development

cargo check-all                              # check all targets + features
cargo test-all                               # run full test suite
just ci-lint                                 # clippy + TOML + Nickel + Markdown
just ci-docs                                 # rustdoc broken intra-doc link check
just ci-full                                 # all CI checks
nu --ide-check 50 reflection/modules/<file>.nu  # validate a Nushell module
./ontoref --actor developer <mode>           # run a reflection mode
./ontoref sync diff --docs                   # crate //! drift against ontology nodes
./ontoref describe workspace                 # per-crate doc coverage + drift status

Doc authoring convention

Three canonical layers — no duplication across them:

Layer Where Read by
/// first line handlers, structs, types #[onto_api], #[derive(OntologyNode)], MCP
//! first sentence lib.rs describe features, mdBook crates chapter, drift check
node description .ontoref/ontology/core.ncl UI graph, describe project, CLI

sync diff --docs --fail-on-drift (used by pre-commit docs-drift hook) enforces that //! first sentence stays aligned with the practice node description (Jaccard ≥ 0.20 threshold).

License

Licensed under either of

at your option. This matches the license field of the workspace manifest (MIT OR Apache-2.0).

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Trade marks

The names "ontoref", "on+re" and "onre", and the brand identity under assets/ (logotypes, wordmarks, palette — synchronised from the constellation root by onre sync assets) are not covered by the licences above. They are expressly reserved; no trade-mark rights are granted. Unaltered nominative and editorial reference is permitted.