ontoref-code/README.md
2026-07-10 01:44:59 +01:00

456 lines
30 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<p align="center">
<img src="assets/ontoref-logo.svg" alt="ontoref" width="320" />
</p>
<br>
**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
```text
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/ Outward-facing surface as a four-element framework (ADR-035, ADR-043) — three orthogonal axes (QUÉ: Differentiator/Competitor · PARA QUIÉN: Audience · CÓMO: DifusionMechanism/Campaign) bound by a Proof seam (VALIDACIÓN). Queryable NCL with `evidence_adrs` anchoring claims to ADRs; `ore positioning audit` self-applies five coherence rules (opt-in, tier-orthogonal)
.coder/interactions.jsonl Interaction trace (ADR-037) — parse-first session records as JSONL; filter, don't prose-mine (opt-in, tier-orthogonal; optional witness binding)
.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, opt-in) — human-signed SOWs, witness.pub, signed Work-Order receipts. The governed-delivery mode's executor enforces the gates: 'Block guards abort, verify-declared steps derive status from the check's exit code, typed postchecks gate `mode complete` (exit 1 when incomplete); done requires two out-of-band human signatures
```
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>`, both `serde(default)`). 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, SurrealDB, NCL export cache, per-file ontology versioning, annotated API catalog, Agent Task Composer. Substrate features (`db`, `nats`) are 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.
**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](adrs/adr-008-ncl-first-config-validation-and-override-layer.ncl))
**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](adrs/adr-034-catalog-extensibility-beyond-rust.ncl), [ADR-030](adrs/adr-030-catalog-discovery-cross-project.ncl))
**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](adrs/adr-010-protocol-migration-system.ncl))
**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](adrs/adr-009-manifest-self-interrogation-layer-three-semantic-axes.ncl))
**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](adrs/adr-012-domain-extension-system.ncl))
**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](adrs/adr-018-level-hierarchy-mode-resolution-strategy.ncl))
**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](adrs/adr-045-recursive-level-chains-and-domain-cotenancy.ncl))
**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
```sh
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)
Two paths share one build, both from the OCI registry. The daemon is an **optional
accelerator** (ADR-029) the `curl|sh` path installs a CLI + data layer that work without it.
```sh
# 1. curl | sh — install the CLI + data layer on a Linux host (amd64/arm64)
curl -fsSL https://get.librecloud.online/ontoref/install.sh | sh
curl -fsSL https://get.librecloud.online/ontoref/install.sh | sh -s -- --prefix ~/.local --version 0.1.5
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.5
```
`install.sh` detects OS/arch, pulls the per-platform bundle from the anonymous-pull
`ontoref/dist` namespace via `oras` (curl fallback to the OCI Distribution API), verifies
the `.sha256` sidecar, and lays out binaries + data + wrappers exactly as `install.nu` does.
`nickel` is bundled; `nushell` is the only external runtime dependency (detected, with install
guidance if absent). macOS has no published build `install.sh` prints source-build/container
guidance.
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:
```sh
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
```sh
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`):
```sh
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.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](adrs/adr-019-per-file-recipient-routing-tenant-isolation.ncl)).
**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**:
```sh
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](adrs/adr-017-registry-credential-vault-model.ncl)
(vault model) and [019](adrs/adr-019-per-file-recipient-routing-tenant-isolation.ncl)
(per-file recipient routing).
## Prerequisites
- [Nushell](https://www.nushell.sh/) >= 0.110.0
- [Nickel](https://nickel-lang.org/) (for schema evaluation)
- Rust toolchain (for building crates)
- [Just](https://just.systems/) (for CI recipes)
- [age](https://github.com/FiloSottile/age) + [sops](https://github.com/getsops/sops) (credential vault, ADR-017/019)
- [oras](https://oras.land/) + [cosign](https://github.com/sigstore/cosign) ≥ 2 (OCI artifact federation)
- [restic](https://restic.net/) or [kopia](https://kopia.io/) (vault snapshots)
To build `ontoref-daemon` and `ontoref-reflection` with NATS/SurrealDB support, the
stratumiops repo must be checked out at `../../../../stratumiops/code` (constellation layout — sibling project, `code/` sub-repo). Without it, build without
default features:
```sh
cargo build -p ontoref-daemon --no-default-features
cargo build -p ontoref-ontology # always standalone
```
## Development
```sh
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
MIT OR Apache-2.0