let d = import "../ontology/defaults/core.ncl" in

{
  nodes = [

    # ── Axioms (invariant = true) ─────────────────────────────────────────────

    d.make_node {
      id          = "protocol-not-runtime",
      name        = "Protocol, Not Runtime",
      pole        = 'Yang,
      level       = 'Axiom,
      description = "Onref is a protocol specification and tooling layer. It is never a runtime dependency. Projects implement the protocol; onref provides the schemas and modules to do so.",
      invariant   = true,
    },

    d.make_node {
      id          = "self-describing",
      name        = "Self-Describing",
      pole        = 'Yang,
      level       = 'Axiom,
      description = "Onref describes itself using its own protocol. The .ontology/, adrs/, and reflection/ directories in this repository are onref consuming ontoref.",
      invariant   = true,
      artifact_paths = [".ontology/core.ncl", ".ontology/state.ncl", "adrs/"],
    },

    d.make_node {
      id          = "no-enforcement",
      name        = "No Enforcement",
      pole        = 'Yang,
      level       = 'Axiom,
      description = "Onref defines contracts and patterns. There is no enforcement mechanism. Coherence is voluntary and emerges from justified adoption.",
      invariant   = true,
    },

    d.make_node {
      id          = "dag-formalized",
      name        = "DAG-Formalized Knowledge",
      pole        = 'Yin,
      level       = 'Axiom,
      description = "All project knowledge — concepts, tensions, decisions, state — is formalized as directed acyclic graphs. This enables transversal queries, impact analysis, and ecosystem-level visibility.",
      invariant   = true,
      artifact_paths = ["ontology/schemas/", "crates/ontoref-ontology/"],
    },

    # ── Tensions ──────────────────────────────────────────────────────────────

    d.make_node {
      id          = "formalization-vs-adoption",
      name        = "Formalization vs Adoption Friction",
      pole        = 'Spiral,
      level       = 'Tension,
      description = "Richer formalization produces better ecosystem visibility but increases the cost of adoption. The balance: schemas are optional layers, not mandatory gates.",
    },

    d.make_node {
      id          = "ontology-vs-reflection",
      name        = "Ontology vs Reflection",
      pole        = 'Spiral,
      level       = 'Tension,
      description = "Ontology captures what IS (invariants, structure, being). Reflection captures what BECOMES (operations, drift, memory). Both must coexist without one dominating. This tension is onref's core identity.",
    },

    # ── Practices ─────────────────────────────────────────────────────────────

    d.make_node {
      id          = "adr-lifecycle",
      name        = "ADR Lifecycle",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Architectural decisions follow: Proposed → Accepted → Superseded. Superseded ADRs retain constraints for historical reconstruction. Active Hard constraints drive the constraint set. Nodes declare which ADRs validate them via the adrs field — surfaced by describe and the daemon graph UI.",
      artifact_paths = [
        "adrs/schema.ncl",
        "adrs/reflection.ncl",
        "adrs/_template.ncl",
        "adrs/adr-001-protocol-as-standalone-project.ncl",
        "adrs/adr-002-daemon-for-caching-and-notification-barrier.ncl",
        "adrs/adr-003-qa-and-knowledge-persistence-as-ncl.ncl",
        "adrs/adr-004-ncl-pipe-bootstrap-pattern.ncl",
        "adrs/adr-005-unified-auth-session-model.ncl",
        "adrs/adr-006-nushell-0111-string-interpolation-compat.ncl",
        "adrs/adr-007-api-surface-discoverability-onto-api-proc-macro.ncl",
        "adrs/adr-008-ncl-first-config-validation-and-override-layer.ncl",
        "adrs/adr-009-manifest-self-interrogation-layer-three-semantic-axes.ncl",
        "adrs/adr-010-protocol-migration-system.ncl",
        "adrs/adr-011-mode-guards-and-convergence.ncl",
        "adrs/adr-012-domain-extension-system.ncl",
        "CHANGELOG.md",
      ],
      adrs = ["adr-001", "adr-002", "adr-003", "adr-004", "adr-005", "adr-006", "adr-007", "adr-008", "adr-009", "adr-010", "adr-011", "adr-012"],
    },

    d.make_node {
      id          = "reflection-modes",
      name        = "Reflection Modes",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Operational procedures are first-class artifacts encoded as NCL DAG contracts. Modes declare actors, steps, dependencies, and error strategies — not prose. Forms (reflection/forms/) provide structured input schemas that feed into modes and the compose pipeline.",
      artifact_paths = ["reflection/modes/", "reflection/schemas/", "crates/ontoref-reflection/", "reflection/forms/"],
    },

    d.make_node {
      id          = "coder-process-memory",
      name        = "Coder Process Memory",
      pole        = 'Yin,
      level       = 'Practice,
      description = "Session knowledge is captured as structured JSONL via coder record. Queryable, exportable, and promotable to reflection/knowledge/. The memory layer between sessions.",
      artifact_paths = ["reflection/modules/coder.nu", "reflection/schemas/coder.ncl"],
    },

    d.make_node {
      id          = "describe-query-layer",
      name        = "Describe Query Layer",
      pole        = 'Yang,
      level       = 'Practice,
      description = "describe.nu aggregates all project sources and answers self-knowledge queries: what IS this, what can I DO, what can I NOT do, what tools exist, what is the impact of changing X. Renders Validated by section when a node declares adrs. describe diff computes a semantic diff of .ontology/ files vs HEAD — nodes/edges added/removed/changed without text diffing. describe api queries GET /api/catalog and renders the annotated HTTP surface grouped by tag, filterable by actor/auth.",
      artifact_paths = ["reflection/modules/describe.nu"],
    },

    d.make_node {
      id          = "ontoref-ontology-crate",
      name        = "Ontoref Ontology Crate",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Rust implementation for loading and querying .ontology/ NCL files as typed structs. Provides Core, Gate, and State types for ecosystem-level introspection. Node carries artifact_paths (Vec<String>) and adrs (Vec<String>) — both serde(default) for zero-migration backward compatibility.",
      artifact_paths = ["crates/ontoref-ontology/"],
      adrs = ["adr-001"],
    },

    d.make_node {
      id          = "ontoref-reflection-crate",
      name        = "Ontoref Reflection Crate",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Rust implementation for loading, validating, and executing Reflection modes as NCL DAG contracts against project state.",
      artifact_paths = ["crates/ontoref-reflection/"],
    },

    d.make_node {
      id          = "adopt-ontoref-tooling",
      name        = "Adopt Ontoref Tooling",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Migration system for onboarding existing projects into the ontoref protocol. adopt_ontoref mode installs .ontoref/, .ontology/ stubs (core, state, gate, manifest, connections), config.ncl template, and scripts/ontoref wrapper — all idempotent. update_ontoref mode brings already-adopted projects to the current protocol version: adds manifest.ncl (content assets) and connections.ncl (cross-project federation) if missing, scans ADR migration status, validates both files, and prints a protocol update report. The 8-phase update-ontology-prompt.md guides an agent through full ontology enrichment on any project.",
      artifact_paths = [
        "ontoref",
        "justfile",
        "justfiles/ci.just",
        "templates/ontology/",
        "templates/ontoref-config.ncl",
        "templates/scripts-ontoref",
        "reflection/modes/adopt_ontoref.ncl",
        "reflection/modes/update_ontoref.ncl",
        "reflection/forms/adopt_ontoref.ncl",
        "reflection/templates/adopt_ontoref.nu.j2",
        "reflection/templates/update-ontology-prompt.md",
        "reflection/migrations/",
      ],
    },

    d.make_node {
      id          = "protocol-migration-system",
      name        = "Protocol Migration System",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Progressive, ordered protocol migrations for consumer projects. Each migration is an NCL file in reflection/migrations/NNN-slug.ncl declaring id, slug, description, a typed check (FileExists | Grep | NuCmd), and instructions interpolated at runtime with project_root and project_name. Applied state is determined solely by whether the check passes — no state file, fully idempotent. NuCmd checks must be valid Nushell (no bash &&, $env.VAR not $VAR). Accessible via `ontoref migrate list/pending/show` and the interactive group dispatch. Narrows ADR instance checks to `adr-[0-9][0-9][0-9]-*.ncl` to exclude schema/template infrastructure files from pattern matching.",
      invariant   = false,
      artifact_paths = [
        "reflection/migrations/",
        "reflection/modules/migrate.nu",
        "reflection/nulib/interactive.nu",
        "reflection/nulib/help.nu",
        "reflection/bin/ontoref.nu",
      ],
      adrs = ["adr-010"],
    },

    d.make_node {
      id          = "ontology-three-file-split",
      name        = "Ontology Three-File Split",
      pole        = 'Yang,
      level       = 'Practice,
      description = "The .ontology/ directory separates three orthogonal concerns into three files. core.ncl captures what the project IS — invariant axioms and structural tensions; touching invariant=true nodes requires a new ADR. state.ncl captures where it IS vs where it wants to BE — current and desired state per dimension. gate.ncl defines when it is READY to cross a boundary — active membranes protecting key conditions. reflection/ reads all three and answers self-knowledge queries. This separation lets an agent understand a project without reading code — only by consulting the declarative graph.",
      invariant   = false,
      artifact_paths = [".ontology/core.ncl", ".ontology/state.ncl", ".ontology/gate.ncl"],
    },

    d.make_node {
      id          = "adr-node-linkage",
      name        = "ADR–Node Declared Linkage",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Nodes declare which ADRs validate them via the adrs field (Array String). This makes the ADR→Node relationship explicit in the graph rather than implicit in prose. describe surfaces a Validated by section per node. The daemon graph UI renders each ADR as a clickable link opening the full ADR via GET /api/adr/{id}. Field is serde(default) and Nickel default=[] — zero migration cost for existing nodes.",
      artifact_paths = [
        "ontology/schemas/core.ncl",
        "crates/ontoref-ontology/src/types.rs",
        "reflection/modules/describe.nu",
        "crates/ontoref-daemon/templates/pages/graph.html",
        "crates/ontoref-daemon/src/api.rs",
      ],
    },

    d.make_node {
      id          = "web-presence",
      name        = "Web Presence",
      pole        = 'Yang,
      level       = 'Practice,
      description = "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. Self-description artifact.",
      artifact_paths = ["assets/web/src/index.html", "assets/web/index.html", "README.md", "assets/architecture.svg"],
    },

    d.make_node {
      id          = "ontoref-daemon",
      name        = "Ontoref Daemon",
      pole        = 'Yang,
      level       = 'Practice,
      description = "HTTP daemon for NCL export caching, file watching, actor registry, and MCP surface. Provides notification barrier, HTTP API (11 pages), MCP server (29 tools, stdio + streamable-HTTP), Q&A NCL persistence, quick-actions catalog, passive drift observation, unified auth/session management, per-file ontology version counters (GET /projects/{slug}/ontology/versions), and annotated API catalog (GET /api/catalog). API catalog populated at link time via #[onto_api] proc-macro + inventory — zero runtime overhead. Launched via ADR-004 NCL pipe bootstrap: nickel export config.ncl | ontoref-daemon.bin --config-stdin. Graph, search, and api_catalog UI pages carry browser-style panel navigation (back/forward history stack). File artifact paths open in external tabs: card.repo (Gitea source URL) for most files, card.docs (cargo docs) for .rs files — no inline file loading. card_repo/card_docs injected into Tera context from insert_brand_ctx; | safe filter required for URL values inside <script> blocks.",
      invariant   = false,
      artifact_paths = [
        "crates/ontoref-daemon/",
        "crates/ontoref-daemon/src/api_catalog.rs",
        "crates/ontoref-daemon/templates/pages/api_catalog.html",
        "crates/ontoref-derive/",
        "install/ontoref-daemon-boot",
        "install/install.nu",
        "nats/streams.json",
        "reflection/modules/services.nu",
        "crates/ontoref-daemon/src/ui/qa_ncl.rs",
        "crates/ontoref-daemon/src/ui/drift_watcher.rs",
        "crates/ontoref-daemon/src/mcp/mod.rs",
        "crates/ontoref-daemon/src/session.rs",
        "crates/ontoref-daemon/src/ui/auth.rs",
        "crates/ontoref-daemon/src/ui/login.rs",
        "crates/ontoref-daemon/src/ui/search_bookmarks_ncl.rs",
        "justfiles/ci.just",
      ],
    },

    d.make_node {
      id          = "api-catalog-surface",
      name        = "API Catalog Surface",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Every HTTP handler is annotated with #[onto_api(method, path, description, auth, actors, params, tags)] — a proc-macro attribute that emits an inventory::submit!(ApiRouteEntry{...}) at link time. inventory::collect!(ApiRouteEntry) aggregates all entries into a zero-cost static catalog. GET /api/catalog serves the full annotated surface as JSON, sorted by path+method. describe api queries the catalog and renders it grouped by tag, filterable by actor/auth in the CLI. ApiCatalogTool exposes the catalog to MCP agents. The /ui/{slug}/api web page renders it with client-side filtering and a parameter detail panel.",
      invariant   = false,
      artifact_paths = [
        "crates/ontoref-daemon/src/api_catalog.rs",
        "crates/ontoref-derive/src/lib.rs",
        "crates/ontoref-daemon/src/api.rs",
        "crates/ontoref-daemon/templates/pages/api_catalog.html",
        "reflection/modules/describe.nu",
        "crates/ontoref-daemon/src/mcp/mod.rs",
      ],
    },

    d.make_node {
      id          = "unified-auth-model",
      name        = "Unified Auth Model",
      pole        = 'Yang,
      level       = 'Practice,
      description = "All surfaces (CLI, UI, MCP) exchange a raw key for a UUID v4 session token via POST /sessions (30-day lifetime, O(1) lookup vs O(~100ms) argon2 per request). Project keys carry role (admin|viewer) and label for audit trail. Daemon admin sessions use virtual slug '_daemon'. ONTOREF_TOKEN injected as Bearer by CLI automatically. Sessions have a stable public id (distinct from bearer token) for safe list/revoke operations. Key rotation revokes all sessions for the rotated project.",
      invariant   = false,
      artifact_paths = [
        "crates/ontoref-daemon/src/session.rs",
        "crates/ontoref-daemon/src/api.rs",
        "crates/ontoref-daemon/src/registry.rs",
        "crates/ontoref-daemon/src/ui/login.rs",
        "crates/ontoref-daemon/src/ui/auth.rs",
        "reflection/modules/store.nu",
        "install/resources/schemas/ontoref-project.ncl",
      ],
    },

    d.make_node {
      id          = "project-onboarding",
      name        = "Project Onboarding",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Idempotent onboarding via `ontoref setup`. Creates .ontoref/project.ncl, .ontoref/config.ncl (with logo auto-detection in assets/), .ontology/ scaffold, adrs/, reflection/modes/, backlog.ncl, qa.ncl, git hooks, and registers in projects.ncl. Supports --kind (repo_kind) and --parent (framework layers + browse modes for implementation children). Bootstrap key generation via --gen-keys ['admin:label' 'viewer:label']: idempotent (no-op if keys exist), hashes via daemon binary, prints passwords once.",
      invariant   = false,
      artifact_paths = [
        "reflection/bin/ontoref.nu",
        "templates/project.ncl",
        "templates/ontoref-config.ncl",
        "templates/ontology/",
        "install/gen-projects.nu",
        "install/resources/schemas/ontoref-project.ncl",
      ],
    },

    d.make_node {
      id          = "daemon-config-management",
      name        = "Daemon Config Management",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Install and configuration infrastructure for ontoref-daemon. Global config at ~/.config/ontoref/config.ncl (Nickel, type-checked). Browser-based editing via typedialog roundtrip: form (config.ncl) → browser → Tera template (config.ncl.j2) → updated config.ncl. CI guard (check-config-sync.nu) enforces form/template parity on every commit. Global NATS topology at ~/.config/ontoref/streams.json; project-local override via nats/streams.json and NATS_STREAMS_CONFIG env var. Config validation + liveness probes via config-setup.nu.",
      invariant   = false,
      artifact_paths = [
        "install/resources/config.ncl",
        "install/resources/streams.json",
        "install/config-setup.nu",
        "install/check-config-sync.nu",
        "reflection/forms/config.ncl",
        "reflection/forms/config.ncl.j2",
        "reflection/nulib/bootstrap.nu",
      ],
    },

    d.make_node {
      id          = "qa-knowledge-store",
      name        = "Q&A Knowledge Store",
      pole        = 'Yin,
      level       = 'Practice,
      description = "Accumulated Q&A entries persisted as NCL — questions and answers captured during development sessions, AI interactions, and architectural reviews. Git-versioned, typed by QaEntry schema, queryable via MCP (ontoref_qa_list/add) and HTTP (/qa-json). Bridges session boundaries: knowledge is never lost between actor sessions.",
      artifact_paths = [
        "reflection/qa.ncl",
        "reflection/schemas/qa.ncl",
        "crates/ontoref-daemon/src/ui/qa_ncl.rs",
      ],
    },

    d.make_node {
      id          = "quick-actions",
      name        = "Quick Actions Catalog",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Runnable shortcuts over existing reflection modes. Configured as quick_actions in .ontoref/config.ncl (id, label, icon, category, mode, actors). Accessible from UI (/actions), CLI (./ontoref), and MCP (ontoref_action_list/add). New modes created via ontoref_action_add are immediately available as actions. Reduces friction between knowing a mode exists and executing it.",
      artifact_paths = [
        ".ontoref/config.ncl",
        "crates/ontoref-daemon/templates/pages/actions.html",
        "reflection/modes/",
      ],
    },

    d.make_node {
      id          = "personal-ontology-schemas",
      name        = "Personal Ontology Schemas",
      pole        = 'Yin,
      level       = 'Practice,
      description = "Typed NCL schema layer for personal and career artifacts: career.ncl (Skills, WorkExperience, Talks, Positioning, CompanyTargets, PublicationCards), personal.ncl (Content and Opportunity lifecycle — BlogPost to CV to Application, Job to Conference to Grant), project-card.ncl (canonical display metadata for portfolio and cv_repo publication), links.ncl (typed Link record with LinkKind enum — replaces raw urls/docs/emails/slides_url/video_url/repository string arrays across all personal+career+core schemas). All types carry linked_nodes referencing .ontology/core.ncl node IDs — bridging career artifacts into the DAG.",
      invariant   = false,
      artifact_paths = [
        "ontology/schemas/links.ncl",
        "ontology/schemas/career.ncl",
        "ontology/schemas/personal.ncl",
        "ontology/schemas/project-card.ncl",
        "ontology/defaults/career.ncl",
        "ontology/defaults/personal.ncl",
        "ontology/defaults/project-card.ncl",
      ],
    },

    d.make_node {
      id          = "content-modes",
      name        = "Content & Career Reflection Modes",
      pole        = 'Yang,
      level       = 'Practice,
      description = "NCL DAG modes for personal content and career operations: draft-application (job/grant/collaboration application anchored in personal ontology — gate alignment check, node selection, career trajectory render), draft-email, generate-article, update-cv, write-cfp. Each mode queries personal.ncl and core.ncl nodes to ground output in declared project artifacts rather than free-form prose.",
      invariant   = false,
      artifact_paths = [
        "reflection/modes/draft-application.ncl",
        "reflection/modes/draft-email.ncl",
        "reflection/modes/generate-article.ncl",
        "reflection/modes/update-cv.ncl",
        "reflection/modes/write-cfp.ncl",
      ],
    },

    d.make_node {
      id          = "search-bookmarks",
      name        = "Search Bookmarks",
      pole        = 'Yin,
      level       = 'Practice,
      description = "Persistent bookmark store for search results over the ontology graph. Entries typed as BookmarkEntry (id, node_id, kind, title, level, term, actor, created_at, tags) and persisted to reflection/search_bookmarks.ncl via line-level NCL surgery — same atomic-write pattern as qa_ncl.rs. IDs are sequential sb-NNN, zero-padded. Concurrency-safe via NclWriteLock. Supports add and remove; accessible from the daemon search UI.",
      invariant   = false,
      artifact_paths = [
        "reflection/search_bookmarks.ncl",
        "reflection/schemas/search_bookmarks.ncl",
        "crates/ontoref-daemon/src/ui/search_bookmarks_ncl.rs",
      ],
    },

    d.make_node {
      id          = "drift-observation",
      name        = "Passive Drift Observation",
      pole        = 'Spiral,
      level       = 'Practice,
      description = "Background observer that bridges Yang code artifacts with Yin ontology declarations. Watches crates/, .ontology/, adrs/, reflection/modes/ for changes; after a debounce window runs sync scan + sync diff; if MISSING/STALE/DRIFT/BROKEN items are found emits an ontology_drift notification. Never applies changes automatically — apply remains a deliberate human or agent act.",
      artifact_paths = [
        "crates/ontoref-daemon/src/ui/drift_watcher.rs",
        "reflection/modes/sync-ontology.ncl",
      ],
    },

    d.make_node {
      id          = "manifest-self-description",
      name        = "Manifest Self-Interrogation Layer",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Three typed arrays added to manifest_type: capabilities[] (what the project does, why, how — with explicit ontology node and ADR cross-references), requirements[] (prerequisites classified by env_target_type: Production/Development/Both and requirement_kind_type: Tool/Service/EnvVar/Infrastructure), and critical_deps[] (external dependencies with documented blast radius distinct from startup prerequisites). describe requirements new subcommand surfaces these. describe guides gains capabilities/requirements/critical_deps keys — agents on cold start receive full self-interrogation context without extra tool calls. Also fixes the collect-identity bug where manifest.kind? was read (field did not exist) instead of manifest.repo_kind?, and adds description | String | default = '' to manifest_type.",
      invariant   = false,
      artifact_paths = [
        "ontology/schemas/manifest.ncl",
        "ontology/defaults/manifest.ncl",
        ".ontology/manifest.ncl",
        "reflection/modules/describe.nu",
      ],
      adrs = ["adr-009"],
    },

    d.make_node {
      id          = "config-surface",
      name        = "Config Surface",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Per-project config introspection, coherence verification, and documented mutation. Rust structs annotated with #[derive(ConfigFields)] + #[config_section(id, ncl_file)] emit inventory::submit!(ConfigFieldsEntry{...}) at link time — the same inventory pattern as API catalog. 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 compares this registry against the NCL export, Nu script accessors, and CI pipeline fields declared in manifest.ncl's config_surface — any NCL field claimed by no consumer is flagged unclaimed. API endpoints: GET /projects/{slug}/config (full export), /config/{section} (single section), /config/schema (sections with contracts and consumers), /config/coherence (multi-consumer diff), /config/quickref (generated documentation with rationales, override history, coherence status). PUT /projects/{slug}/config/{section} mutates via an override layer: writes {section}.overrides.ncl with audit metadata (actor, reason, timestamp, previous value), appends a single import to the entry point (idempotent), validates with nickel export, reverts on contract violation. NCL contracts (std.contract.from_validator) enforce field constraints (enums, positive numbers, port ranges) before any Rust struct is populated — Nickel is the single validation layer. Ontoref describes its own config via .ontoref/contracts.ncl applying LogConfig and DaemonConfig contracts.",
      invariant   = false,
      artifact_paths = [
        "crates/ontoref-daemon/src/config.rs",
        "crates/ontoref-daemon/src/config_coherence.rs",
        "crates/ontoref-daemon/src/api.rs",
        "crates/ontoref-derive/src/lib.rs",
        "crates/ontoref-ontology/src/lib.rs",
        "ontology/schemas/manifest.ncl",
        ".ontoref/contracts.ncl",
        ".ontoref/config.ncl",
      ],
      adrs = ["adr-007", "adr-008"],
    },

    d.make_node {
      id          = "domain-extension-system",
      name        = "Domain Extension System",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Bash-layer dispatch for repo_kind-conditional CLI domains. Consumer projects with specific repo_kinds get project-type-aware CLI commands via ore <domain-id> <command>. Each domain ships three files under $ONTOREF_ROOT/domains/{id}/: domain.ncl (NCL contract: commands, pages, repo_kinds, short_alias), commands.nu (Nu script with def main entry point), repo_kinds.txt (grep-readable list of matching repo_kind values). install.nu copies all domains/ to $data_dir and generates aliases.txt + standalone bin wrappers from short_alias. help.nu and describe.nu read domain.ncl at runtime for dynamic help and capabilities output. repo_kind extracted from project manifest via grep (not nickel export) to avoid import-path failures. Session 2026-04-05: personal domain (PersonalOntology — state, next, validate, audit, career, cfp, opportunities, content) and provisioning domain (DevWorkspace/Mixed — state, next, connections, gates, card, capabilities, backlog) implemented. Session 2026-04-06: framework domain (Library/Service/Tool — state, next, connections, gates, capabilities, validate) added to cover Library and Service projects (librosys, DD7pasos, rustelo, website-impl) that have connections.ncl and gate.ncl but no workspace-specific commands.",
      invariant   = false,
      artifact_paths = [
        "domains/",
        "domains/schema.ncl",
        "domains/personal/domain.ncl",
        "domains/personal/commands.nu",
        "domains/personal/repo_kinds.txt",
        "domains/provisioning/domain.ncl",
        "domains/provisioning/commands.nu",
        "domains/provisioning/repo_kinds.txt",
        "domains/framework/domain.ncl",
        "domains/framework/commands.nu",
        "domains/framework/repo_kinds.txt",
        "install/ontoref-global",
        "install/install.nu",
        "reflection/nulib/help.nu",
        "reflection/modules/describe.nu",
      ],
      adrs = ["adr-012"],
    },

    d.make_node {
      id          = "vcs-abstraction",
      name        = "VCS Abstraction Layer",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Uniform VCS API over jj and git. Filesystem-based detection (.jj/ vs .git/) — no config, no env var. Exposes show-committed, restore-file, remote-url, current-branch, uncommitted-files, and commit-count with identical semantics regardless of VCS backend. All ontoref modules consume vcs.nu instead of hardcoding git commands.",
      artifact_paths = [
        "reflection/modules/vcs.nu",
      ],
      adrs = ["adr-013"],
    },

    d.make_node {
      id          = "agent-workspace-orchestration",
      name        = "Agent Workspace Orchestration",
      pole        = 'Yang,
      level       = 'Practice,
      description = "jj + ontoref + Radicle lifecycle wrapper for agent workspaces. jjw agent create spawns a jj workspace and starts an ontoref run; jjw agent step reports progress; jjw agent publish validates, pushes, and opens a Radicle patch (or git push fallback); jjw agent merge commits and cleans the workspace. NCL conflict resolution via jjw-ncl-merge.nu registered as a jj merge tool — enables automated .ontology/ conflict resolution during workspace merge.",
      artifact_paths = [
        "reflection/bin/jjw.nu",
        "reflection/bin/jjw-ncl-merge.nu",
      ],
    },

    d.make_node {
      id          = "ci-pipelines",
      name        = "CI/CD Pipelines",
      pole        = 'Yang,
      level       = 'Practice,
      description = "Continuous integration pipelines: GitHub Actions (Nickel typecheck, Rust CI) and Woodpecker (standard + advanced CI). Pre-commit hooks enforce formatting, linting, testing, dependency auditing, docs-links, docs-drift, and manifest coverage before code reaches CI.",
      artifact_paths = [
        ".github/workflows/",
        ".woodpecker/",
        ".pre-commit-config.yaml",
        ".claude/hooks/",
      ],
    },

  ],

  edges = [

    { from = "self-describing",    to = "dag-formalized",          kind = 'ManifestsIn,  weight = 'High   },
    { from = "self-describing",    to = "adr-lifecycle",           kind = 'ManifestsIn,  weight = 'High   },
    { from = "self-describing",    to = "reflection-modes",        kind = 'ManifestsIn,  weight = 'High   },
    { from = "ontology-vs-reflection", to = "dag-formalized",      kind = 'Resolves,     weight = 'High   },
    { from = "ontology-vs-reflection", to = "coder-process-memory", kind = 'Resolves,   weight = 'Medium },
    { from = "dag-formalized",     to = "ontoref-ontology-crate",  kind = 'ManifestsIn,  weight = 'High   },
    { from = "reflection-modes",   to = "ontoref-reflection-crate", kind = 'ManifestsIn, weight = 'High   },
    { from = "no-enforcement",     to = "formalization-vs-adoption", kind = 'Resolves,   weight = 'Medium },
    { from = "protocol-not-runtime", to = "no-enforcement",        kind = 'Implies,      weight = 'High   },
    { from = "adr-lifecycle",      to = "reflection-modes",        kind = 'Complements,  weight = 'Medium },
    { from = "adr-node-linkage",   to = "adr-lifecycle",           kind = 'ManifestsIn,  weight = 'High   },
    { from = "adr-node-linkage",   to = "describe-query-layer",    kind = 'Complements,  weight = 'High   },
    { from = "describe-query-layer", to = "dag-formalized",        kind = 'DependsOn,    weight = 'High   },
    { from = "coder-process-memory", to = "describe-query-layer",  kind = 'Complements,  weight = 'Medium },
    { from = "ontoref-daemon",        to = "ontoref-ontology-crate",  kind = 'Complements,  weight = 'High   },
    { from = "ontoref-daemon",        to = "reflection-modes",        kind = 'Complements,  weight = 'Medium },
    { from = "protocol-not-runtime",  to = "ontoref-daemon",          kind = 'Contradicts,  weight = 'Low,
      note = "Daemon is optional runtime support, not a protocol requirement. Protocol functions without it." },
    { from = "no-enforcement",        to = "adopt-ontoref-tooling",   kind = 'ManifestsIn,  weight = 'High,
      note = "Adoption is voluntary — the tooling makes it easy but never mandatory." },
    { from = "adopt-ontoref-tooling", to = "reflection-modes",        kind = 'DependsOn,    weight = 'High   },
    { from = "self-describing",       to = "web-presence",            kind = 'ManifestsIn,  weight = 'Medium },
    { from = "web-presence",          to = "adopt-ontoref-tooling",   kind = 'Complements,  weight = 'Medium },

    # Q&A Knowledge Store edges
    { from = "qa-knowledge-store",    to = "dag-formalized",          kind = 'ManifestsIn,  weight = 'High,
      note = "Q&A entries are typed NCL records, git-versioned — knowledge as DAG." },
    { from = "qa-knowledge-store",    to = "coder-process-memory",    kind = 'Complements,  weight = 'High,
      note = "Q&A is the persistent layer; coder.nu is the session capture layer. Together they form the full memory stack." },
    { from = "ontoref-daemon",        to = "qa-knowledge-store",      kind = 'Contains,     weight = 'High   },
    { from = "daemon-config-management", to = "ontoref-daemon",       kind = 'DependsOn,    weight = 'High   },
    { from = "daemon-config-management", to = "adopt-ontoref-tooling", kind = 'Complements, weight = 'Medium,
      note = "Config management is part of the adoption surface — new projects get config.ncl and streams.json during install." },

    # Quick Actions edges
    { from = "quick-actions",         to = "reflection-modes",        kind = 'DependsOn,    weight = 'High,
      note = "Each quick action invokes a reflection mode by id." },
    { from = "quick-actions",         to = "ontoref-daemon",          kind = 'ManifestsIn,  weight = 'Medium },
    { from = "describe-query-layer",  to = "quick-actions",           kind = 'Complements,  weight = 'Medium,
      note = "describe capabilities lists available modes; quick-actions makes them executable." },

    # Drift Observation edges
    { from = "drift-observation",     to = "ontoref-daemon",          kind = 'ManifestsIn,  weight = 'High   },
    { from = "drift-observation",     to = "ontology-vs-reflection",  kind = 'Resolves,     weight = 'Medium,
      note = "Drift observer continuously monitors the gap between Yin (ontology) and Yang (code). Passive resolution — it signals drift without forcing resolution." },
    { from = "drift-observation",     to = "reflection-modes",        kind = 'DependsOn,    weight = 'High,
      note = "Invokes sync-ontology mode steps (scan, diff) as read-only sub-processes." },

    # Personal Ontology Schemas edges
    { from = "personal-ontology-schemas", to = "dag-formalized",      kind = 'ManifestsIn,  weight = 'High,
      note = "Career and personal artifacts are typed NCL records with linked_nodes — DAG connections into the core ontology." },
    { from = "personal-ontology-schemas", to = "self-describing",     kind = 'Complements,  weight = 'Medium,
      note = "Personal/career schemas let projects describe not just what they ARE but who built them and for what trajectory." },
    { from = "content-modes",           to = "reflection-modes",      kind = 'ManifestsIn,  weight = 'High   },
    { from = "content-modes",           to = "personal-ontology-schemas", kind = 'DependsOn, weight = 'High,
      note = "Content and career modes query personal.ncl and core.ncl to ground output in declared artifacts." },
    { from = "search-bookmarks",        to = "qa-knowledge-store",    kind = 'Complements,  weight = 'High,
      note = "Both are NCL persistence layers using the same atomic-write surgery pattern. Q&A is for accumulated knowledge; bookmarks are for search navigation state." },
    { from = "search-bookmarks",        to = "ontoref-daemon",        kind = 'ManifestsIn,  weight = 'High   },
    { from = "ontoref-daemon",          to = "search-bookmarks",      kind = 'Contains,     weight = 'High   },

    # API Catalog Surface edges
    { from = "api-catalog-surface",   to = "ontoref-daemon",          kind = 'ManifestsIn,  weight = 'High   },
    { from = "api-catalog-surface",   to = "describe-query-layer",    kind = 'Complements,  weight = 'High,
      note = "describe api queries GET /api/catalog and renders the annotated surface in the CLI." },
    { from = "api-catalog-surface",   to = "protocol-not-runtime",    kind = 'Complements,  weight = 'Medium,
      note = "Catalog is compiled into the binary via inventory — no runtime doc system, no external dependency." },

    # Unified Auth Model edges
    { from = "unified-auth-model",    to = "ontoref-daemon",          kind = 'ManifestsIn,  weight = 'High   },
    { from = "unified-auth-model",    to = "no-enforcement",          kind = 'Contradicts,  weight = 'Low,
      note = "Auth is opt-in per project (no keys = open deployment). When keys are configured enforcement is real, but the protocol itself never mandates it." },
    { from = "ontoref-daemon",        to = "unified-auth-model",      kind = 'Contains,     weight = 'High   },

    # Project Onboarding edges
    { from = "project-onboarding",    to = "adopt-ontoref-tooling",   kind = 'Complements,  weight = 'High,
      note = "adopt-ontoref-tooling is the migration surface for existing projects; project-onboarding is the first-class setup for new projects." },
    { from = "project-onboarding",    to = "unified-auth-model",      kind = 'DependsOn,    weight = 'Medium,
      note = "--gen-keys bootstraps the first keys into project.ncl during setup." },
    { from = "project-onboarding",    to = "daemon-config-management", kind = 'DependsOn,   weight = 'Medium },

    # Manifest Self-Interrogation Layer edges
    { from = "manifest-self-description", to = "self-describing",       kind = 'Complements,  weight = 'High,
      note = "capabilities/requirements/critical_deps in the manifest are the typed operational answer to 'what IS this project' — complementing the architectural answer in core.ncl Practice nodes." },
    { from = "manifest-self-description", to = "adopt-ontoref-tooling", kind = 'Complements,  weight = 'High,
      note = "Consumer projects declare their own capabilities, requirements, and critical deps — the self-interrogation layer is part of the adoption surface." },
    { from = "manifest-self-description", to = "describe-query-layer",  kind = 'ManifestsIn,  weight = 'High,
      note = "describe capabilities renders manifest_capabilities; describe requirements surfaces requirements + critical_deps; describe guides extends its output with all three arrays." },
    { from = "manifest-self-description", to = "dag-formalized",        kind = 'Complements,  weight = 'Medium,
      note = "capabilities.nodes[] cross-references ontology node IDs; capabilities.adrs[] cross-references ADR IDs — bridging the manifest into the queryable DAG." },
    { from = "manifest-self-description", to = "adr-lifecycle",         kind = 'Complements,  weight = 'Medium,
      note = "capabilities.adrs[] creates explicit typed links from capabilities to the ADRs that formalize them — the ADR→Node linkage pattern extended to the manifest layer." },

    # Protocol Migration System edges
    { from = "protocol-migration-system", to = "adopt-ontoref-tooling",  kind = 'ManifestsIn,  weight = 'High,
      note = "Migration system is the versioned upgrade surface for adopt-ontoref-tooling — new protocol features arrive as numbered migrations, not template rewrites." },
    { from = "protocol-migration-system", to = "adr-lifecycle",          kind = 'Complements,  weight = 'High,
      note = "Each migration check can verify ADR-level constraints are met in consumer repos — migrations and ADRs are complementary protocol enforcement layers." },
    { from = "protocol-migration-system", to = "no-enforcement",         kind = 'Complements,  weight = 'Medium,
      note = "Migrations are advisory: `migrate pending` reports state, never applies automatically. The actor decides when to apply." },
    { from = "self-describing",           to = "protocol-migration-system", kind = 'ManifestsIn, weight = 'Medium,
      note = "Ontoref runs its own migration checks against itself — the migration system is self-applied." },

    # Domain Extension System edges
    { from = "domain-extension-system", to = "formalization-vs-adoption",    kind = 'Resolves,     weight = 'High,
      note = "Domain commands remove the adoption friction of project-type-specific CLI — PersonalOntology and DevWorkspace get discoverable commands without local scripts." },
    { from = "domain-extension-system", to = "personal-ontology-schemas",    kind = 'DependsOn,    weight = 'High,
      note = "The personal domain reads career.ncl, personal.ncl, and backlog.ncl — it is the CLI surface for the personal ontology schema layer." },
    { from = "domain-extension-system", to = "describe-query-layer",         kind = 'Complements,  weight = 'High,
      note = "describe capabilities runs resolve-domain-extension and renders DOMAIN EXTENSION section; ore help <domain-id> reads domain.ncl commands[] dynamically." },
    { from = "domain-extension-system", to = "adopt-ontoref-tooling",        kind = 'Complements,  weight = 'High,
      note = "Domain extensions are part of the adoption surface — new repo_kinds get project-type-aware CLI by shipping a domain directory." },
    { from = "domain-extension-system", to = "protocol-not-runtime",         kind = 'Complements,  weight = 'Medium,
      note = "Domain dispatch is bash+grep — no runtime dependency on nickel for the dispatch path itself. commands.nu is an isolated Nu process." },

    # VCS Abstraction edges
    { from = "vcs-abstraction",              to = "reflection-modes",          kind = 'DependsOn,    weight = 'Medium,
      note = "opmode.nu and git-event.nu consume vcs.nu — mode execution is VCS-aware." },
    { from = "vcs-abstraction",              to = "project-onboarding",        kind = 'DependsOn,    weight = 'Medium,
      note = "init-repo.nu uses vcs detection to choose jj colocated vs git init during onboarding." },

    # Agent Workspace Orchestration edges
    { from = "agent-workspace-orchestration", to = "vcs-abstraction",          kind = 'DependsOn,    weight = 'High,
      note = "jjw delegates VCS detection and operations to vcs.nu." },
    { from = "agent-workspace-orchestration", to = "reflection-modes",         kind = 'DependsOn,    weight = 'High,
      note = "jjw agent create starts an ontoref run; jjw agent step reports steps; jjw agent merge completes the run." },
    { from = "agent-workspace-orchestration", to = "no-enforcement",           kind = 'Complements,  weight = 'Medium,
      note = "Radicle publish is optional — jjw degrades to git push if no rad remote is configured." },

    # Config Surface edges
    { from = "config-surface",        to = "ontoref-daemon",          kind = 'ManifestsIn,  weight = 'High   },
    { from = "config-surface",        to = "ontoref-ontology-crate",  kind = 'DependsOn,    weight = 'High,
      note = "ConfigFieldsEntry struct and inventory::collect!(ConfigFieldsEntry) live in ontoref-ontology — the zero-dep adoption surface." },
    { from = "config-surface",        to = "api-catalog-surface",     kind = 'Complements,  weight = 'High,
      note = "#[derive(ConfigFields)] extends the same inventory::submit! pattern as #[onto_api]. Both emit link-time registration entries collected by the daemon at startup." },
    { from = "config-surface",        to = "dag-formalized",          kind = 'ManifestsIn,  weight = 'High,
      note = "Config sections, consumers, and coherence reports are typed NCL/Rust records — the config tree is a queryable subgraph." },
    { from = "config-surface",        to = "self-describing",         kind = 'Complements,  weight = 'High,
      note = "Ontoref applies its own LogConfig and DaemonConfig contracts in .ontoref/contracts.ncl — the config surface is self-demonstrated, not just specified." },
    { from = "config-surface",        to = "adopt-ontoref-tooling",   kind = 'Complements,  weight = 'Medium,
      note = "Consumer projects adopting ontoref can annotate their config structs with #[derive(ConfigFields)] to participate in the coherence registry." },

  ],
}
