ontoref/.ontology/manifest.ncl
Jesús Pérez 13b03d6edf
Some checks failed
Nickel Type Check / Nickel Type Checking (push) Has been cancelled
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
feat: mode guards, convergence, manifest coverage, doc authoring pattern
## Mode guards and convergence loops (ADR-011)

  - `Guard` and `Converge` types added to `reflection/schema.ncl` and
    `reflection/defaults.ncl`. Guards run pre-flight checks (Block/Warn);
    converge loops iterate until a condition is met (RetryFailed/RetryAll).
  - `sync-ontology.ncl`: 3 guards + converge (zero-drift condition, max 2 iter).
  - `coder-workflow.ncl`: guard (coder-dir-exists) + `novelty-check` step.
  - Rust types in `ontoref-reflection/src/mode.rs`; executor in `executor.rs`
    evaluates guards before steps and convergence loop after.
  - `adrs/adr-011-mode-guards-and-convergence.ncl` added.

  ## Manifest capability completeness

  - `.ontology/manifest.ncl`: 3 → 19 declared capabilities covering the full
    action surface (daemon API, modes, Task Composer, QA, bookmarks, etc.).
  - `sync.nu`: `audit-manifest-coverage` + `sync manifest-check` command.
  - `validate-project.ncl`: 6th category `manifest-cov`.
  - Pre-commit hook `manifest-coverage` added.
  - Migrations `0010-manifest-capability-completeness`,
    `0011-manifest-coverage-hooks`.

  ## Rust doc authoring pattern — canonical `///` convention

  - `#[onto_api]`: `description = "..."` optional when `///` doc comment exists
    above handler — first line used as fallback. `#[derive(OntologyNode)]` same.
  - `ontoref-daemon/src/api.rs`: 42 handlers migrated to `///` doc comments;
    `description = "..."` removed from all `#[onto_api]` blocks.
  - `sync diff --docs --fail-on-drift`: exits 1 on crate `//!` drift; used by
    new `docs-drift` pre-commit hook. `docs-links` hook checks rustdoc broken links.
  - `generator.nu`: mdBook `crates/` chapter — per-crate page from `//!` doc,
    coverage badge, feature flags, implementing practice nodes.
  - `.claude/CLAUDE.md`: `### Documentation Authoring (Rust)` section added.
  - Migration `0012-rust-doc-authoring-pattern`.

  ## OntologyNode derive fixes

  - `#[derive(OntologyNode)]`: `name` and `paths` attributes supported; `///`
    doc fallback for `description`; `artifact_paths` correctly populated.
  - `Core::from_value` calls `merge_contributors()` behind `#[cfg(feature = "derive")]`.

  ## Bug fixes

  - `sync.nu` drift check: exact crate path match (not `str starts-with`);
    first-path-only rule; split on `. ` not `.` to avoid `.ontology/` truncation.
  - `find-unclaimed-artifacts`: fixed absolute vs relative path comparison.
  - Rustdoc broken intra-doc links fixed across all three crates.
  - `ci-docs` recipe now sets `RUSTDOCFLAGS` and actually fails on errors.

  mode guards/converge, manifest coverage validation, 19 capabilities (ADR-011)

  Extend the mode schema with Guard (pre-flight Block/Warn checks) and Converge
  (RetryFailed/RetryAll post-execution loops) — protocol pushes back on invalid
  state and iterates until convergence. ADR-011 records the decision to extend
  modes rather than create a separate action subsystem.

  Manifest expanded from 3 to 19 capabilities covering the full action surface
  (compose, plans, backlog graduation, notifications, coder pipeline, forms,
  templates, drift, quick actions, migrations, config, onboarding). New
  audit-manifest-coverage validator + pre-commit hook + SessionStart hook
  ensure agents always see complete project self-description.

  Bug fix: find-unclaimed-artifacts absolute vs relative path comparison —
  19 phantom MISSING items resolved. Health 43% → 100%.

  Anti-slop: coder novelty-check step (Jaccard overlap against published+QA)
  inserted between triage and publish in coder-workflow.

  Justfile restructured into 5 modules (build/test/dev/ci/assets).
  Migrations 0010-0011 propagate requirements to consumer projects.
2026-03-30 19:08:25 +01:00

553 lines
42 KiB
XML

let m = import "../ontology/defaults/manifest.ncl" in
m.make_manifest {
project = "ontoref",
repo_kind = 'DevWorkspace,
description = "Protocol specification and tooling layer for structured self-knowledge in software projects. Provides schemas, Nushell automation, and Rust crates so projects can describe what they are, record architectural decisions, track operational state, and execute formalized procedures as typed, queryable artifacts.",
content_assets = [
m.make_asset {
id = "logo-horizontal",
kind = 'Logo,
source_path = "assets/branding/ontoref-h.svg",
variants = ["assets/branding/ontoref-h-static.svg", "assets/branding/ontoref-dark-h.svg", "assets/branding/ontoref-mono-black-h.svg", "assets/branding/ontoref-mono-white-h.svg"],
description = "Primary horizontal logo — animated SVG with static and dark/mono variants.",
},
m.make_asset {
id = "logo-vertical",
kind = 'Logo,
source_path = "assets/branding/ontoref-v.svg",
variants = ["assets/branding/ontoref-v-static.svg", "assets/branding/ontoref-dark-v.svg", "assets/branding/ontoref-mono-black-v.svg", "assets/branding/ontoref-mono-white-v.svg"],
description = "Vertical logo — animated SVG with static and dark/mono variants.",
},
m.make_asset {
id = "logo-icon",
kind = 'Icon,
source_path = "assets/branding/ontoref-icon.svg",
variants = ["assets/branding/ontoref-icon-static.svg"],
description = "Square icon mark — animated and static variants.",
},
m.make_asset {
id = "logo-text",
kind = 'Logo,
source_path = "assets/branding/ontoref-text.svg",
description = "Logotype text-only mark.",
},
m.make_asset {
id = "logo-pakua",
kind = 'Logo,
source_path = "assets/branding/pakua/ontoref_pakua_img.svg",
variants = ["assets/branding/pakua/ontoref-pakua-dark-v.svg"],
description = "Pakua symbol variant of the logo.",
},
m.make_asset {
id = "diagram-architecture",
kind = 'Diagram,
source_path = "assets/architecture.svg",
description = "Current architecture diagram showing the three-layer protocol model.",
},
m.make_asset {
id = "screenshot-graph-dark",
kind = 'Screenshot,
source_path = "assets/ontoref_graph_view-dark.png",
variants = ["assets/ontoref_graph_view-light.png"],
description = "Graph view UI screenshot — dark and light variants.",
},
m.make_asset {
id = "presentation-deck",
kind = 'Document,
source_path = "assets/presentation/slides.md",
description = "Slidev presentation deck for ontoref protocol introduction.",
},
],
templates = [
m.make_template {
id = "project-full-adoption-prompt",
kind = 'AgentPrompt,
source_path = "reflection/templates/project-full-adoption-prompt.md",
description = "Master adoption prompt for new and existing projects: protocol infrastructure, ontology enrichment, config surface (nickel-validated-overrides + ConfigFields derive), API surface (#[onto_api]), and manifest self-interrogation (capabilities/requirements/critical_deps). Orchestrates all other templates.",
},
m.make_template {
id = "update-ontology-prompt",
kind = 'AgentPrompt,
source_path = "reflection/templates/update-ontology-prompt.md",
description = "8-phase ontology enrichment prompt: core.ncl nodes/edges, state.ncl dimension transitions, manifest assets, connections, ADR check_hint migration. Called from Phase 2 of project-full-adoption-prompt.",
},
m.make_template {
id = "manifest-self-interrogation-prompt",
kind = 'AgentPrompt,
source_path = "reflection/templates/manifest-self-interrogation-prompt.md",
description = "Focused prompt for populating capabilities[], requirements[], and critical_deps[] in manifest.ncl. Called from Phase 5 of project-full-adoption-prompt.",
},
m.make_template {
id = "vendor-frontend-assets-prompt",
kind = 'AgentPrompt,
source_path = "reflection/templates/vendor-frontend-assets-prompt.md",
description = "Guide for vendoring frontend JS dependencies locally: directory layout (assets/vendor/), just recipe structure (assets.just with pinned version variables), Tera template integration, CDN asset verification steps, and agent execution checklist. Reusable across any ontoref-protocol project with a static-file-serving daemon.",
},
],
consumption_modes = [
m.make_consumption_mode {
consumer = 'Developer,
needs = ['OntologyExport],
audit_level = 'Standard,
description = "Clones repo, runs ./ontoref, imports Nushell modules. Uses reflection tooling to manage project self-description.",
},
m.make_consumption_mode {
consumer = 'Agent,
needs = ['OntologyExport, 'JsonSchema],
audit_level = 'Quick,
description = "Queries 19 capabilities, 31 ontology nodes, 10 ADRs, and 19 executable modes via describe capabilities (CLI), MCP tools (33), or daemon API. SessionStart hook auto-loads project identity and manifest health. Guards block mode execution on constraint violations.",
},
],
justfile = {
system = 'Import,
required_modules = ["build", "test", "dev", "ci", "assets"],
required_recipes = ["default"],
},
claude = {
guidelines = ["rust", "nushell", "nickel"],
session_hook = true,
stratum_commands = true,
},
config_surface = m.make_config_surface {
config_root = ".ontoref",
entry_point = "config.ncl",
kind = 'SingleFile,
contracts_path = ".ontoref",
sections = [
m.make_config_section {
id = "nickel_import_paths",
file = "config.ncl",
description = "Ordered list of directories added to NICKEL_IMPORT_PATH when invoking nickel.",
rationale = "Ontoref resolves ontology schemas, ADRs, and reflection schemas through this path list. Order matters: earlier entries shadow later ones.",
mutable = true,
consumers = [
m.make_config_consumer {
id = "env",
kind = 'NuScript,
ref = "reflection/modules/env.nu",
fields = ["nickel_import_paths"],
},
m.make_config_consumer {
id = "daemon-main",
kind = 'RustStruct,
ref = "crates/ontoref-daemon/src/main.rs",
fields = ["nickel_import_paths"],
},
],
},
m.make_config_section {
id = "ui",
file = "config.ncl",
description = "Daemon HTTP/UI settings: template directory, static assets, TLS certs, logo override.",
rationale = "Allows dev-mode templates to be served from the source tree instead of the installed path, and TLS to be toggled without recompiling.",
mutable = true,
consumers = [
m.make_config_consumer {
id = "daemon-main",
kind = 'RustStruct,
ref = "crates/ontoref-daemon/src/main.rs",
fields = ["templates_dir", "public_dir", "tls_cert", "tls_key", "logo"],
},
],
},
m.make_config_section {
id = "log",
file = "config.ncl",
contract = "contracts.ncl → LogConfig",
description = "Daemon structured logging: level, rotation policy, archive and retention.",
rationale = "Daily rotation with 7-file retention keeps log footprint bounded; separate archive path allows cold storage without disrupting active logs.",
mutable = true,
consumers = [
m.make_config_consumer {
id = "daemon-main",
kind = 'RustStruct,
ref = "crates/ontoref-daemon/src/main.rs",
fields = ["level", "path", "rotation", "compress", "archive", "max_files"],
},
],
},
m.make_config_section {
id = "mode_run",
file = "config.ncl",
description = "ACL rules for which actors may execute which reflection modes.",
rationale = "Agent and CI actors need unrestricted mode access; human actors are gated per mode to prevent accidental destructive operations.",
mutable = true,
consumers = [
m.make_config_consumer {
id = "daemon-main",
kind = 'RustStruct,
ref = "crates/ontoref-daemon/src/main.rs",
fields = ["rules"],
},
],
},
m.make_config_section {
id = "nats_events",
file = "config.ncl",
description = "NATS event bus integration: enabled flag, server URL, emit/subscribe topic lists, handlers directory.",
rationale = "Disabled by default to keep ontoref zero-dependency for projects without a NATS deployment. Feature-gated in the daemon crate.",
mutable = true,
consumers = [
m.make_config_consumer {
id = "daemon-main",
kind = 'RustStruct,
ref = "crates/ontoref-daemon/src/main.rs",
fields = ["enabled", "url", "emit", "subscribe", "handlers_dir"],
},
],
},
m.make_config_section {
id = "actor_init",
file = "config.ncl",
description = "Per-actor bootstrap: which reflection mode to auto-run on first invocation.",
rationale = "Agents always auto-run 'describe capabilities' so they orient themselves before acting; developers and CI start clean.",
mutable = true,
consumers = [
m.make_config_consumer {
id = "env",
kind = 'NuScript,
ref = "reflection/modules/env.nu",
fields = ["actor", "mode", "auto_run"],
},
],
},
m.make_config_section {
id = "quick_actions",
file = "config.ncl",
description = "Shortcut actions surfaced in the daemon UI dashboard: id, label, icon, category, mode, allowed actors.",
rationale = "Frequently used modes (generate-mdbook, sync-ontology, coder-workflow) promoted to one-click access without navigating the modes list.",
mutable = true,
consumers = [
m.make_config_consumer {
id = "daemon-ui",
kind = 'RustStruct,
ref = "crates/ontoref-daemon/src/ui/handlers.rs",
fields = ["id", "label", "icon", "category", "mode", "actors"],
},
],
},
m.make_config_section {
id = "daemon",
file = "config.ncl",
contract = "contracts.ncl → DaemonConfig",
description = "Runtime overrides for daemon CLI defaults: port, timeouts, sweep intervals, notification limits.",
rationale = "All fields are optional — absent fields use the daemon's built-in CLI defaults. Set only when the defaults need project-specific tuning without rebuilding the binary.",
mutable = true,
consumers = [
m.make_config_consumer {
id = "daemon-config",
kind = 'RustStruct,
ref = "crates/ontoref-daemon/src/config.rs → DaemonRuntimeConfig",
fields = ["port", "idle_timeout", "invalidation_interval", "actor_sweep_interval", "actor_stale_timeout", "max_notifications", "notification_ack_required"],
},
],
},
],
},
capabilities = [
m.make_capability {
id = "protocol-spec",
name = "Protocol Specification",
summary = "Typed NCL schemas for nodes, edges, ADRs, state, gates, and manifests — the contract layer that projects implement to describe themselves.",
rationale = "Projects need a contract layer to describe what they are — not just code comments. NCL provides typed, queryable, git-versionable schemas with contract enforcement at export time. Alternatives (TOML/JSON/YAML) lack contracts; Rust-only structs are not adoption-friendly.",
how = "ontology/schemas/ defines all type contracts (core, manifest, gate, state, content). adrs/adr-schema.ncl defines the ADR lifecycle contract with typed constraints (Cargo/Grep/NuCmd/ApiCall/FileExists checks). ontology/defaults/ exposes builders (make_node, make_edge, make_adr) so consumer projects never write raw NCL records. nickel export validates against declared contracts before any JSON reaches Rust or Nushell.",
artifacts = ["ontology/schemas/", "ontology/defaults/", "adrs/adr-schema.ncl", "adrs/adr-defaults.ncl", "reflection/schemas/"],
nodes = ["dag-formalized", "protocol-not-runtime", "adr-lifecycle", "ontoref-ontology-crate", "ontology-three-file-split", "adr-node-linkage", "personal-ontology-schemas"],
},
m.make_capability {
id = "daemon-api",
name = "Daemon HTTP + MCP Surface",
summary = "HTTP UI (11 pages), 33 MCP tools, annotated API catalog, SSE notifications, per-file versioning, and NCL export cache.",
rationale = "Agents and developers need a queryable interface to ontology state without spawning nickel on every request. The NCL export cache reduces full-sync from ~2m42s to <30s. MCP tools give agents structured access to every capability without screen-scraping the CLI. ADR-002 records the architectural decision to extract the daemon; ADR-007 covers the #[onto_api] catalog pattern; ADR-008 covers the config override layer.",
how = "crates/ontoref-daemon uses axum for HTTP. #[onto_api(...)] proc-macro + inventory::submit! registers every route at link time; GET /api/catalog aggregates via inventory::collect!. NclCache (DashMap<PathBuf, CachedExport>) keyed on path + mtime. File watcher (notify) triggers cache invalidation and drift detection after 15s debounce. MCP over stdio and streamable-HTTP.",
artifacts = [
"crates/ontoref-daemon/",
"GET /api/catalog",
"GET /projects/{slug}/ontology",
"GET /projects/{slug}/config/coherence",
"MCP: ontoref_guides, ontoref_api_catalog, ontoref_validate, ontoref_impact",
],
adrs = ["adr-002", "adr-004", "adr-007", "adr-008"],
nodes = ["ontoref-daemon", "api-catalog-surface", "config-surface", "unified-auth-model"],
},
m.make_capability {
id = "reflection-modes",
name = "Reflection Mode DAG Engine",
summary = "19 executable NCL DAG workflows with typed steps, dependency graphs, 5 error strategies, actor filtering, guards (pre-flight constraint checks that block execution on violations), and convergence loops (re-execute until a condition is met). Modes cover sync, validation, content generation, project scaffolding, ADR lifecycle, and protocol adoption.",
rationale = "Structured procedures expressed as typed DAGs rather than ad-hoc scripts. Every step has a declared dep graph — the executor validates it before running. Agent-safe: modes are NCL contracts, not imperative scripts, so agents can read and reason about them before execution. Guards implement the Active Partner pattern — the protocol pushes back before executing if constraints are violated. Convergence implements the Refinement Loop pattern — modes iterate until a condition is met rather than running once blindly.",
how = "crates/ontoref-reflection loads a mode NCL file, validates the DAG contract (no cycles, declared deps exist), then executes steps via Nushell subprocesses. Each step declares: id, action, cmd, actor, depends_on (Always/OnSuccess/OnFailure), on_error (Stop/Continue/Retry/Fallback/Branch), and verify. Guards run before steps — each has a cmd, reason, and severity (Block/Warn). Converge runs after steps — condition cmd checked, re-executes up to max_iterations using RetryFailed or RetryAll strategy.",
artifacts = ["reflection/modes/", "reflection/modules/", "crates/ontoref-reflection/", "reflection/schema.ncl"],
nodes = ["reflection-modes", "adopt-ontoref-tooling", "ontoref-reflection-crate", "content-modes"],
},
m.make_capability {
id = "run-step-tracking",
name = "Run/Step Execution Tracking",
summary = "Persistent execution tracking for mode runs: start runs, report steps with status/artifacts/warnings, validate dependency satisfaction, verify mode completion. File-based storage under .coder/<actor>/runs/ as JSONL.",
rationale = "Mode execution without tracking is fire-and-forget. Agents and CI need to resume interrupted runs, audit which steps passed or failed, and verify all required steps completed before declaring success. File-based storage keeps tracking git-versionable and debuggable without requiring a database.",
how = "ontoref run start <mode> creates a run directory with run.json metadata and empty steps.jsonl. step report validates the step exists in the mode DAG and that blocking dependencies (OnSuccess) are satisfied before appending. mode complete checks all steps are reported and no Stop-strategy failures block completion. current.json tracks the active run per actor.",
artifacts = ["reflection/modules/run.nu", "reflection/bin/ontoref.nu", ".coder/"],
nodes = ["reflection-modes", "coder-process-memory"],
},
m.make_capability {
id = "agent-task-composer",
name = "Agent Task Composer",
summary = "Form-driven prompt composition UI: select NCL form templates, fill structured fields, preview assembled markdown, send to AI providers, or export as .plan.ncl with execution DAG and lifecycle FSM (Draft/Sent/Accepted/Executed/Archived).",
rationale = "Agents need structured task input, not free-text prompts. Forms enforce required fields and typed options. Plans decouple task definition from execution — a plan can be reviewed before running, and its status tracked across sessions. The compose UI bridges form schemas to AI provider APIs without custom integration per provider.",
how = "reflection/forms/*.ncl define form schemas (elements: section_header/text/select/multiselect/editor/confirm). Daemon UI (/ui/compose) renders forms dynamically, assembles markdown from field values, and offers two actions: (1) send to AI provider via HTTP, (2) save as .plan.md + .plan.ncl. Plan NCL carries template ID, field values, linked backlog items, linked ADRs, and an optional execution DAG referencing modes. Plan status is a 5-state FSM tracked in the NCL file.",
artifacts = ["reflection/forms/", "reflection/schemas/plan.ncl", "reflection/templates/", "crates/ontoref-daemon/templates/pages/compose.html"],
nodes = ["reflection-modes", "ontoref-daemon"],
},
m.make_capability {
id = "backlog-graduation",
name = "Backlog with Typed Graduation Paths",
summary = "Work item tracking (Todo/Wish/Idea/Bug/Debt) with priority, status lifecycle, and typed graduation: items promote to ADRs, reflection modes, state transitions, or PR items via ontoref backlog promote. Notification-based approval workflow for status changes.",
rationale = "Work items are not flat lists — they have destinations. A bug graduates to a fix PR. An idea graduates to an ADR. A wish graduates to a reflection mode. Typed graduation makes the promotion path explicit and machine-readable, enabling agents to propose promotions and humans to approve them via the notification system.",
how = "reflection/backlog.ncl stores items typed by reflection/schemas/backlog.ncl (Item with graduates_to: Adr/Mode/StateTransition/PrItem). CLI commands: backlog add/done/cancel/promote/propose-status/approve. propose-status emits a custom notification (backlog_review) to the daemon; admin approves via notification UI, triggering the status update. roadmap command cross-references items with state.ncl dimensions.",
artifacts = ["reflection/backlog.ncl", "reflection/schemas/backlog.ncl", "reflection/modules/backlog.nu"],
nodes = ["reflection-modes"],
},
m.make_capability {
id = "notification-system",
name = "Notification & Approval Workflows",
summary = "Event broadcast system with SSE streaming, per-actor acknowledgment, custom event emission, and cross-project notifications. Supports approval workflows via custom notification kinds (e.g. backlog_review). Ring buffer storage with configurable retention.",
rationale = "File watchers detect changes but actors need to be notified, not poll. SSE provides real-time push without WebSocket complexity. Per-actor ACK prevents one actor's acknowledgment from hiding notifications from others. Custom events enable approval workflows without a separate messaging system.",
how = "crates/ontoref-daemon/src/notifications.rs implements a per-project ring buffer (DashMap<project, Vec<Notification>>, default 256 entries). File changes emit OntologyChanged/AdrChanged/ReflectionChanged events. User code emits custom events via push_custom(kind, title, payload, source_actor, source_project). SSE broadcast via tokio::broadcast::Sender. Per-token ACK tracking (ack_all/ack_one). Backlog propose-status uses this for approval workflows.",
artifacts = ["crates/ontoref-daemon/src/notifications.rs", "reflection/modules/backlog.nu"],
nodes = ["ontoref-daemon"],
},
m.make_capability {
id = "coder-process-memory",
name = "Coder Process Memory Pipeline",
summary = "Structured knowledge capture across actor sessions: init author workspaces, record JSON entries to queryable JSONL, triage inbox markdown into categories, publish to shared space with attribution, graduate to committed knowledge. 9-step DAG workflow.",
rationale = "Session knowledge evaporates between conversations. The coder pipeline captures insights, decisions, and investigations as structured entries — immediately queryable via coder log, promotable across actor boundaries, and graduable to committed project knowledge. Process memory bridges the gap between ephemeral sessions and persistent project knowledge.",
how = "coder-workflow mode (9 steps): init-author creates .coder/<author>/ with inbox/ and author.ncl. record-json appends structured entries to entries.jsonl. dump-markdown copies raw files to inbox. triage classifies inbox files into categories with companion NCL. query filters entries by tag/kind/domain/author. publish promotes entries to .coder/general/<category>/ with attribution. graduate copies to reflection/knowledge/. validate-ontology-core/state ensure ontology reflects new knowledge.",
artifacts = ["reflection/modes/coder-workflow.ncl", "reflection/modules/coder.nu", "reflection/schemas/coder.ncl", ".coder/"],
nodes = ["coder-process-memory"],
},
m.make_capability {
id = "qa-knowledge-store",
name = "Q&A Knowledge Store",
summary = "Persistent question-answer pairs captured during development sessions, typed by QaEntry schema, with concurrent-safe NCL mutations, tag-based queries, verification status, and cross-references to ontology nodes and ADRs.",
rationale = "Recurring questions deserve persistent answers. Q&A entries bridge session boundaries — knowledge captured in one conversation is available in all future sessions. NCL storage keeps entries git-versionable and queryable without a database. ADR-003 records the decision to persist Q&A as NCL rather than browser storage.",
how = "reflection/qa.ncl stores entries typed by reflection/schemas/qa.ncl (QaEntry: id, question, answer, actor, tags, related, verified). crates/ontoref-daemon/src/ui/qa_ncl.rs performs line-level NCL surgery for add/update/remove with NclWriteLock for concurrency safety. Auto-incrementing IDs (qa-001, qa-002...). Accessible via MCP (ontoref_qa_list/add), HTTP (/qa-json), and CLI.",
artifacts = ["reflection/qa.ncl", "reflection/schemas/qa.ncl", "crates/ontoref-daemon/src/ui/qa_ncl.rs"],
adrs = ["adr-003"],
nodes = ["qa-knowledge-store"],
},
m.make_capability {
id = "form-input-system",
name = "NCL Form Input System",
summary = "Declarative form schemas in NCL with typed elements (text/select/multiselect/editor/confirm/section), dual backend execution (CLI interactive prompts or daemon HTTP), and integration with the compose pipeline and template generation.",
rationale = "Structured input collection avoids free-text ambiguity. Forms declared as NCL schemas are versionable, composable, and renderable by both CLI and web UI without separate implementations. The same form drives interactive terminal prompts and web form submission.",
how = "reflection/forms/*.ncl define form schemas as arrays of typed elements. form list discovers available forms. form run <name> --backend cli|daemon executes the form interactively or via HTTP. Collected field values feed into the compose pipeline (prompt assembly), template rendering (J2), or direct mode execution. Forms for ADR creation, project onboarding, backlog items, and config editing.",
artifacts = ["reflection/forms/", "reflection/modules/form.nu", "crates/ontoref-daemon/templates/pages/compose.html"],
nodes = ["reflection-modes", "ontoref-daemon"],
},
m.make_capability {
id = "template-generation",
name = "Template Generation Pipeline",
summary = "Jinja2 template rendering composing data from ontology nodes, crate metadata, ADRs, and mode definitions to generate NCL files, Nushell scripts, config variants, and adoption artifacts.",
rationale = "Code generation from project knowledge eliminates manual transcription between the ontology and implementation artifacts. Templates bridge the gap between typed NCL declarations and executable scripts or config files.",
how = "reflection/templates/*.j2 are Jinja2 templates processed by generator.nu. Templates extract data from ontology (nodes, edges), crate metadata (Cargo.toml), ADRs (constraints), and modes (steps). Output includes: adr.ncl.j2 (ADR files from form data), adopt_ontoref.nu.j2 (adoption scripts), create_project.nu.j2 (project scaffolding), config-production.ncl.j2 (config variants). describe.nu also supports per-section Tera templates in layouts/.",
artifacts = ["reflection/templates/", "reflection/modules/generator.nu", "reflection/modules/describe.nu"],
nodes = ["adopt-ontoref-tooling"],
},
m.make_capability {
id = "describe-query-layer",
name = "Self-Knowledge Query Layer",
summary = "10 describe subcommands providing multi-level views of project knowledge: project (identity/axioms/tensions/practices), capabilities (modes/commands/flags/backlog), constraints (ADR hard/soft), state (FSM dimensions), tools, features, impact analysis, guides (full agent onboarding context), diff (recent changes), and workspace (multi-project overview).",
rationale = "Projects need queryable self-knowledge at different abstraction levels. A human needs a different view than an agent. describe provides semantic zoom — from one-line project identity to full constraint sets with check commands. This is the primary interface for agents to orient themselves before acting.",
how = "reflection/modules/describe.nu implements 10 subcommands, each collecting data from NCL exports (ontology, ADRs, manifest, backlog, modes) and rendering as text (human) or JSON (agent). Actor filtering applies to API routes, mode visibility, and constraint relevance. describe guides aggregates all subcommands into a single comprehensive output for agent cold-start.",
artifacts = ["reflection/modules/describe.nu", "reflection/bin/ontoref.nu"],
nodes = ["describe-query-layer", "manifest-self-description"],
},
m.make_capability {
id = "drift-observation",
name = "Passive Drift Detection & Sync",
summary = "Background file watcher detecting divergence between .ontology/ declarations and actual project artifacts. 7-step sync mode: scan project structure, diff against ontology, detect doc drift (Jaccard similarity), propose patches, review, apply, verify. Emits ontology_drift notifications when drift is found.",
rationale = "Ontology declarations rot when code evolves without updating .ontology/core.ncl. Passive detection catches drift before it compounds. The sync mode bridges observation to action — detect, propose, and apply in a structured DAG rather than manual file editing.",
how = "crates/ontoref-daemon/src/ui/drift_watcher.rs watches crates/, .ontology/, adrs/, reflection/modes/ for changes. After 15s debounce, runs sync scan + sync diff. If MISSING/STALE/DRIFT/BROKEN items found, emits ontology_drift notification. sync-ontology mode (7 steps) provides the full remediation workflow: scan extracts pub API via cargo doc JSON, diff categorizes divergence, propose generates NCL patches, apply writes changes, verify runs nickel typecheck.",
artifacts = ["reflection/modes/sync-ontology.ncl", "reflection/modules/sync.nu", "crates/ontoref-daemon/src/ui/drift_watcher.rs"],
nodes = ["drift-observation", "reflection-modes"],
},
m.make_capability {
id = "quick-actions",
name = "Quick Actions Catalog",
summary = "Configurable shortcut grid mapping UI buttons to reflection mode execution. Declared in .ontoref/config.ncl with id, label, icon, category, mode reference, and actor ACL. One-click mode execution from the daemon UI without CLI.",
rationale = "Frequently used modes (sync-ontology, generate-mdbook, coder-workflow) need one-click access. The quick actions grid reduces friction between knowing a mode exists and executing it — especially for developers who prefer the UI over CLI.",
how = ".ontoref/config.ncl declares quick_actions array. Daemon UI (/actions) renders a categorized grid of action cards. Click triggers daemon handler run_action_by_id() which spawns tokio::process::Command with ./ontoref run <mode_id>. New actions can be added via MCP (ontoref_action_add) or by editing config.ncl directly.",
artifacts = [".ontoref/config.ncl", "crates/ontoref-daemon/templates/pages/actions.html", "reflection/modes/"],
nodes = ["quick-actions", "ontoref-daemon"],
},
m.make_capability {
id = "protocol-migration",
name = "Protocol Migration System",
summary = "Progressive, idempotent protocol upgrades for consumer projects. Each migration carries a typed check (FileExists/Grep/NuCmd) and human-readable instructions. No state file — the check result IS the applied state. Consumer projects run ontoref migrate pending to discover and apply upgrades.",
rationale = "Protocol changes that only apply to ontoref itself are useless for the ecosystem. The migration system is the propagation mechanism — without it, consumer projects never learn about protocol evolution. ADR-010 records this decision.",
how = "reflection/migrations/NNNN-slug.ncl files define migrations with id, slug, description, check (tag + parameters), and instructions. ontoref migrate list shows all migrations. migrate pending filters to unapplied (check fails). migrate show <id> displays instructions. Checks are idempotent: FileExists tests path existence, Grep tests pattern presence, NuCmd runs a Nushell expression and checks exit code.",
artifacts = ["reflection/migrations/", "reflection/modules/migrate.nu", "reflection/bin/ontoref.nu"],
adrs = ["adr-010"],
nodes = ["protocol-migration-system"],
},
m.make_capability {
id = "config-surface-management",
name = "Config Surface with NCL Validation",
summary = "Structured config system: NCL contracts validate all fields, override-layer mutation preserves original files, zero-maintenance field registry via #[derive(ConfigFields)] + inventory auto-discovers which Rust struct consumes which NCL field, coherence endpoint detects unclaimed fields and consumer fields missing from NCL export.",
rationale = "Config drift between NCL declarations and Rust consumers is invisible until runtime. The config coherence system makes it detectable at build time. Override-layer mutation ensures original NCL files (with comments, contracts, formatting) are never modified — changes are always additive. ADR-008 records this decision.",
how = "crates/ontoref-daemon/src/config.rs defines DaemonRuntimeConfig. #[derive(ConfigFields)] on Rust structs registers consumed fields via inventory::submit!. GET /config/coherence cross-references NCL export keys against registered consumers. .ontoref/contracts.ncl defines LogConfig, DaemonConfig contracts. config show/verify/audit/apply CLI commands for inspection and mutation.",
artifacts = [".ontoref/config.ncl", ".ontoref/contracts.ncl", "crates/ontoref-daemon/src/config.rs", "crates/ontoref-daemon/src/config_coherence.rs", "crates/ontoref-derive/src/lib.rs"],
adrs = ["adr-008"],
nodes = ["config-surface", "ontoref-daemon", "daemon-config-management"],
},
m.make_capability {
id = "project-onboarding",
name = "Project Onboarding",
summary = "CLI and form-driven onboarding for new projects into the ontoref protocol: scaffolds .ontology/, adrs/, reflection/, .ontoref/config.ncl, and registers the project with the daemon. Includes templates for project.ncl and remote-project.ncl.",
rationale = "Adoption friction is the main barrier to protocol spread. Onboarding must be a guided, repeatable process — not a manual checklist. The adopt_ontoref mode and forms reduce the first adoption to answering structured questions.",
how = "reflection/modes/adopt_ontoref.ncl orchestrates the full onboarding DAG. reflection/forms/adopt_ontoref.ncl collects project metadata. reflection/templates/adopt_ontoref.nu.j2 generates the adoption script. templates/ provides starter files for all protocol directories. install/gen-projects.nu handles daemon project registration.",
artifacts = ["reflection/modes/adopt_ontoref.ncl", "reflection/forms/adopt_ontoref.ncl", "templates/", "install/gen-projects.nu", "reflection/bin/ontoref.nu"],
nodes = ["project-onboarding", "adopt-ontoref-tooling", "ci-pipelines"],
},
m.make_capability {
id = "web-presence",
name = "Web Presence",
summary = "Landing page at assets/web/ describing the ontoref protocol to external audiences. Bilingual (EN/ES), covers protocol layers, yin/yang duality, crates, and adoption path.",
rationale = "The protocol needs a public-facing explanation beyond the README. The landing page serves as the first point of contact for potential adopters.",
how = "assets/web/src/index.html is the source. assets/web/index.html is the built output. README.md links to it. assets/architecture.svg provides the visual architecture diagram.",
artifacts = ["assets/web/src/index.html", "assets/web/index.html", "README.md", "assets/architecture.svg"],
nodes = ["web-presence"],
},
m.make_capability {
id = "search-bookmarks",
name = "Search Bookmarks",
summary = "Persistent bookmark store for ontology graph search results. Entries typed as BookmarkEntry with node cross-references, sequential IDs, concurrent-safe NCL mutations via NclWriteLock. Accessible from daemon search UI and MCP.",
rationale = "Graph exploration sessions produce valuable search paths that are lost when the page reloads. Bookmarks persist the trail of ontology exploration across sessions.",
how = "reflection/search_bookmarks.ncl stores entries typed by reflection/schemas/search_bookmarks.ncl. crates/ontoref-daemon/src/ui/search_bookmarks_ncl.rs performs line-level NCL surgery with NclWriteLock. Sequential IDs (sb-001, sb-002...). MCP tool ontoref_bookmark_add for agent access.",
artifacts = ["reflection/search_bookmarks.ncl", "reflection/schemas/search_bookmarks.ncl", "crates/ontoref-daemon/src/ui/search_bookmarks_ncl.rs"],
nodes = ["search-bookmarks"],
},
],
requirements = [
m.make_requirement {
id = "nushell",
name = "Nushell",
env = 'Both,
kind = 'Tool,
version = "0.110.0",
required = true,
impact = "All reflection modes and the ./ontoref dispatcher are Nushell scripts. Without Nu nothing executes — no mode runs, no describe subcommands, no sync.",
provision = "https://www.nushell.sh/ — cargo install nu or OS package manager.",
},
m.make_requirement {
id = "nickel",
name = "Nickel",
env = 'Both,
kind = 'Tool,
version = "",
required = true,
impact = "All schema evaluation, ADR parsing, config export blocked. Daemon NCL cache inoperable. Config surface mutation cannot validate overrides.",
provision = "https://nickel-lang.org/ — cargo install nickel-lang-cli or nix flake.",
},
m.make_requirement {
id = "rust-nightly",
name = "Rust nightly toolchain",
env = 'Development,
kind = 'Tool,
version = "",
required = true,
impact = "cargo +nightly fmt fails — pre-commit hook blocks all commits.",
provision = "rustup toolchain install nightly",
},
m.make_requirement {
id = "surrealdb",
name = "SurrealDB",
env = 'Production,
kind = 'Service,
version = "",
required = false,
impact = "Daemon db feature disabled; ontology not projected into DB. Daemon still works via --no-default-features for local-only use.",
provision = "https://surrealdb.com/ — binary or container. Feature-gated: cargo build -p ontoref-daemon --no-default-features omits it.",
},
m.make_requirement {
id = "stratumiops",
name = "stratumiops repo checkout",
env = 'Development,
kind = 'Infrastructure,
version = "",
required = false,
impact = "ontoref-daemon (db/nats features) and ontoref-reflection (nats feature) cannot build. Build with --no-default-features to work without it.",
provision = "git clone at ../../../stratumiops relative to this repo root.",
},
],
critical_deps = [
m.make_critical_dep {
id = "nickel-lang",
name = "nickel-lang",
ref = "crates.io: nickel-lang-core / nickel-lang-cli",
used_for = "Schema evaluation, contract enforcement, config export, ADR parsing. Every nickel export call in the daemon cache and in Nushell modules.",
failure_impact = "Total loss of typed schema layer. All NCL export operations fail. Daemon cache inoperable. Config override mutation cannot validate before committing. describe guides and ontoref_guides MCP tool return empty data.",
mitigation = "Pin to a specific Nickel release in PATH. Nickel is a subprocess dep (never linked into Rust binary) — breakage manifests at runtime as nickel export exit code != 0, which all callers handle gracefully (daemon-export-safe returns null, callers use | default []).",
},
m.make_critical_dep {
id = "inventory",
name = "inventory",
ref = "crates.io: inventory 0.3",
used_for = "#[onto_api] HTTP catalog registration and #[derive(ConfigFields)] config coherence registry. Both use inventory::submit! at link time; GET /api/catalog and GET /config/coherence use inventory::iter! at runtime.",
failure_impact = "GET /api/catalog returns empty. Config coherence endpoint loses Rust struct field data. ontoref_api_catalog MCP tool blind. API version change would require updating both onto_api and ConfigFields derive macros simultaneously.",
mitigation = "inventory uses linker sections (zero runtime overhead). Version is pinned in Cargo.toml. ontoref-derive and ontoref-ontology both declare it — version must stay in sync.",
},
m.make_critical_dep {
id = "axum",
name = "axum",
ref = "crates.io: axum",
used_for = "All 11 UI pages and REST API endpoints in ontoref-daemon. Router, handlers, extractors, middleware.",
failure_impact = "Daemon does not compile. Full HTTP surface down: UI, REST API, MCP over HTTP, session management, config surface endpoints.",
mitigation = "ontoref-ontology and the ./ontoref CLI are axum-free. Reflection modes, ADR tooling, and describe subcommands continue working without the daemon.",
},
],
layers = [
m.make_layer {
id = "protocol",
paths = ["ontology/", "adrs/", "reflection/schemas/"],
committed = true,
description = "Protocol specification: Nickel schemas, ADR tooling, and reflection schemas. The contract layer that projects implement.",
},
m.make_layer {
id = "tooling",
paths = ["reflection/", "install/", "nats/", "templates/", "ontoref"],
committed = true,
description = "Operational tooling: Nushell modules, modes, forms, dispatcher, bash entry point, install scripts, default config resources, and NATS stream topology.",
},
m.make_layer {
id = "crates",
paths = ["crates/", "Cargo.toml"],
committed = true,
description = "Rust implementation: ontoref-ontology (load/query .ontology/ as typed structs) and ontoref-reflection (execute reflection modes against project state).",
},
m.make_layer {
id = "self-description",
paths = [".ontology/"],
committed = true,
description = "Ontoref consuming ontoref: the project's own ontology, state, gate, and manifest.",
},
m.make_layer {
id = "process",
paths = [".coder/"],
committed = false,
description = "Session artifacts: plans, investigations, summaries. Process memory for actors.",
},
],
}