- Rust 64.2%
- HTML 13.3%
- Nickel 7.7%
- Nushell 7.3%
- Shell 3.4%
- Other 3.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
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 |
||
| .cargo | ||
| .config | ||
| .github/workflows | ||
| .governance | ||
| .vale | ||
| .woodpecker | ||
| assets | ||
| crates | ||
| domains | ||
| examples | ||
| install | ||
| justfiles | ||
| lian-build | ||
| nats | ||
| ontology | ||
| provisioning | ||
| scripts | ||
| templates | ||
| .clippy.toml | ||
| .devconfig.ncl | ||
| .gitignore | ||
| .markdownlint-cli2.jsonc | ||
| .ontoref-backup-pre-0023.tgz | ||
| .pre-commit-config.yaml | ||
| .rustfmt.toml | ||
| .shellcheckrc | ||
| .taplo.toml | ||
| .vale.ini | ||
| .yamllint-ci.yml | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CHANGELOG.md | ||
| CODE_OF_CONDUCT.md | ||
| CONTRIBUTING.md | ||
| Cross.toml | ||
| deny.toml | ||
| diagram.md | ||
| Dockerfile | ||
| justfile | ||
| LICENSE-APACHE | ||
| LICENSE-MIT | ||
| ontoref | ||
| README.md | ||
| SECURITY.md | ||
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 Schemas — ontology/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 Diff — describe 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.
ADR–Node 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 today —
declare 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
(0001–0029); 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-Interrogation — manifest_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 Validation — validate 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 Layer — reflection/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 1 —
access.sops.yamlper project, multi-recipient encrypted; carrieszot_username,zot_password,vault_key,cosign_password - Layer 2 — operation credentials (RO/RW per registry entry) under
src-vault/registry/, referenced bymanifest.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
- MIT license (LICENSE-MIT or https://spdx.org/licenses/MIT.html)
- Apache License, Version 2.0 (LICENSE-APACHE or https://www.apache.org/licenses/LICENSE-2.0)
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.