diff --git a/assets/architecture.svg b/assets/architecture.svg new file mode 100644 index 0000000..7b627e6 --- /dev/null +++ b/assets/architecture.svg @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + CONSUMER PROJECT + ontoref + · .ontoref/config.ncl · ONTOREF_PROJECT_ROOT + + + + exec · ONTOREF_PROJECT_ROOT + + + + TOOLING LAYER + + + + ./ontoref + bash · actor detection + + + + + + + ontoref.nu + Nushell dispatcher + + + + + + + reflection/modules/ · 16 Nushell modules + adr · backlog · coder · describe · sync · store · services · nats · … + subprocess fallback: direct nickel export when daemon unavailable + + + + RUST CRATES + + + + ontoref-ontology + .ontology/*.ncl → typed Rust structs + + + + ontoref-reflection + load + validate + execute NCL DAG modes + + + + ontoref-daemon + NCL cache · file watcher · actor registry · HTTP + optional + + + + HTTP + + + + + + nickel + export + + + + + + + reads + + + + PROTOCOL LAYER + + ontology/schemas/ + core · gate · state · manifest (NCL defaults) + + + + adrs/ + schema · constraints · lifecycle forms + + + + reflection/schemas/ · modes/ · forms/ + 9 schemas · 10 NCL DAG modes · 7 forms + + + + SELF-DESCRIPTION · .ontology/ + + ontoref consuming its own protocol + + + + core.ncl · state.ncl · gate.ncl · manifest.ncl + + + + 4 axioms · 2 tensions · 9 practices · 19 edges + 3 state dimensions: protocol-maturity · self-description · ecosystem + + + + ADR-001: self-describing axiom in practice + + + + active flow + + + reads / executes + + + optional + + + self-description + + ontoref architecture + diff --git a/assets/architecture_0.svg b/assets/architecture_0.svg new file mode 100644 index 0000000..7b627e6 --- /dev/null +++ b/assets/architecture_0.svg @@ -0,0 +1,253 @@ + + + + + + + + + + + + + + + + + + + CONSUMER PROJECT + ontoref + · .ontoref/config.ncl · ONTOREF_PROJECT_ROOT + + + + exec · ONTOREF_PROJECT_ROOT + + + + TOOLING LAYER + + + + ./ontoref + bash · actor detection + + + + + + + ontoref.nu + Nushell dispatcher + + + + + + + reflection/modules/ · 16 Nushell modules + adr · backlog · coder · describe · sync · store · services · nats · … + subprocess fallback: direct nickel export when daemon unavailable + + + + RUST CRATES + + + + ontoref-ontology + .ontology/*.ncl → typed Rust structs + + + + ontoref-reflection + load + validate + execute NCL DAG modes + + + + ontoref-daemon + NCL cache · file watcher · actor registry · HTTP + optional + + + + HTTP + + + + + + nickel + export + + + + + + + reads + + + + PROTOCOL LAYER + + ontology/schemas/ + core · gate · state · manifest (NCL defaults) + + + + adrs/ + schema · constraints · lifecycle forms + + + + reflection/schemas/ · modes/ · forms/ + 9 schemas · 10 NCL DAG modes · 7 forms + + + + SELF-DESCRIPTION · .ontology/ + + ontoref consuming its own protocol + + + + core.ncl · state.ncl · gate.ncl · manifest.ncl + + + + 4 axioms · 2 tensions · 9 practices · 19 edges + 3 state dimensions: protocol-maturity · self-description · ecosystem + + + + ADR-001: self-describing axiom in practice + + + + active flow + + + reads / executes + + + optional + + + self-description + + ontoref architecture + diff --git a/templates/ontology/core.ncl b/templates/ontology/core.ncl new file mode 100644 index 0000000..0e8ba7f --- /dev/null +++ b/templates/ontology/core.ncl @@ -0,0 +1,64 @@ +# .ontology/core.ncl — Project: {{ project_name }} +# Fill in nodes that capture what is invariant and what is in tension. +# +# To use typed construction helpers, add ontology/defaults/ from the ontoref +# checkout and: let d = import "ontology/defaults/core.ncl" in +# +# Fields (node): +# id — unique kebab-case identifier +# name — human-readable label +# pole — 'Yang (active force) | 'Yin (receptive force) | 'Tension +# level — 'Axiom | 'Practice | 'Tension | 'Spiral +# description — what this node means for this project +# invariant — true if this is non-negotiable (requires ADR to change) +# artifact_paths — list of file paths that implement this node (optional) +# +# Fields (edge): +# from, to — node IDs +# kind — 'Implements | 'Resolves | 'Complements | 'Contradicts | +# 'DependsOn | 'ValidatedBy | 'ManifestsIn +# weight — 'High | 'Medium | 'Low +# note — why this edge exists (optional) + +{ + nodes = [ + + # ── Axioms (invariant = true) ───────────────────────────────────────────── + + { + id = "{{ project_name }}-primary-constraint", + name = "Primary Constraint", + pole = 'Yang, + level = 'Axiom, + description = "Replace with the non-negotiable constraint that defines what this project IS.", + invariant = true, + }, + + # ── Tensions ────────────────────────────────────────────────────────────── + + { + id = "{{ project_name }}-first-tension", + name = "First Tension", + pole = 'Tension, + level = 'Tension, + description = "Describe the core structural tension this project must navigate.", + invariant = false, + }, + + # ── Practices — add confirmed patterns and active systems here ──────────── + + ], + + edges = [ + + # Example: + # { + # from = "{{ project_name }}-primary-constraint", + # to = "{{ project_name }}-first-tension", + # kind = 'Resolves, + # weight = 'High, + # note = "Why this edge exists.", + # }, + + ], +} diff --git a/templates/ontology/gate.ncl b/templates/ontology/gate.ncl new file mode 100644 index 0000000..15dd8da --- /dev/null +++ b/templates/ontology/gate.ncl @@ -0,0 +1,44 @@ +# .ontology/gate.ncl — Project: {{ project_name }} +# Membranes are gates that control when a project is ready to cross a boundary. +# Start with active = false. Activate only when the condition is real and enforced. +# +# To use typed construction helpers, add ontology/defaults/ from the ontoref +# checkout and: let d = import "ontology/defaults/gate.ncl" in +# +# Fields (membrane): +# id — unique kebab-case identifier +# name — human-readable label +# description — what this gate protects +# permeability — 'High | 'Medium | 'Low | 'Closed +# accepts — list of signal types: 'EcosystemRelevance | 'Adoption | 'Stability +# protects — list of strings: what this gate guards +# opening_condition — record: { max_tension_dimensions, pending_transitions, core_stable, description } +# closing_condition — string: what causes the gate to close again +# max_duration — 'Weeks | 'Months | 'Years | 'Indefinite +# protocol — 'Observe | 'Absorb | 'Challenge | 'Reject +# active — bool (false = defined but not enforced) + +{ + membranes = [ + + { + id = "{{ project_name }}-readiness-gate", + name = "{{ project_name }} Readiness Gate", + description = "Controls when {{ project_name }} is ready for external use.", + permeability = 'Low, + accepts = ['EcosystemRelevance], + protects = ["Replace with: what this gate protects"], + opening_condition = { + max_tension_dimensions = 2, + pending_transitions = 3, + core_stable = true, + description = "Replace with: measurable condition to open this gate.", + }, + closing_condition = "Replace with: what causes the gate to close again.", + max_duration = 'Indefinite, + protocol = 'Observe, + active = false, + }, + + ], +} diff --git a/templates/ontology/state.ncl b/templates/ontology/state.ncl new file mode 100644 index 0000000..05bad51 --- /dev/null +++ b/templates/ontology/state.ncl @@ -0,0 +1,52 @@ +# .ontology/state.ncl — Project: {{ project_name }} +# State dimensions track WHERE the project IS vs WHERE it WANTS to BE. +# +# To use typed construction helpers, add ontology/defaults/ from the ontoref +# checkout and: let d = import "ontology/defaults/state.ncl" in +# +# Fields (dimension): +# id — unique kebab-case identifier +# name — human-readable label +# description — what this dimension measures +# current_state — string ID of where the project is now +# desired_state — string ID of where it should be +# horizon — 'Weeks | 'Months | 'Years | 'Continuous +# states — [] (or list of named states) +# transitions — list of transition records +# +# Fields (transition): +# from — source state ID +# to — target state ID +# condition — measurable condition for the transition +# catalyst — what would trigger it +# blocker — what currently prevents it +# horizon — 'Weeks | 'Months | 'Years + +{ + dimensions = [ + + { + id = "{{ project_name }}-maturity", + name = "{{ project_name }} Maturity", + description = "Overall maturity of {{ project_name }} — from initial scaffold to stable production use.", + current_state = "bootstrapped", + desired_state = "stable", + horizon = 'Months, + states = [], + transitions = [ + { + from = "bootstrapped", + to = "stable", + condition = "Replace with measurable condition.", + catalyst = "What would trigger this transition?", + blocker = "What is currently blocking it?", + horizon = 'Months, + }, + ], + }, + + # Add more dimensions as the project's state space becomes clearer. + # Useful dimensions: adoption, documentation-coverage, api-stability, test-coverage + + ], +} diff --git a/templates/ontoref-config.ncl b/templates/ontoref-config.ncl new file mode 100644 index 0000000..f87cf50 --- /dev/null +++ b/templates/ontoref-config.ncl @@ -0,0 +1,31 @@ +# .ontoref/config.ncl — ontoref configuration for {{ project_name }} +# Place this file at /.ontoref/config.ncl + +{ + nickel_import_paths = [".", ".ontology", "ontology/schemas", "adrs", "reflection/requirements", "reflection/schemas"], + + log = { + level = "info", + path = ".ontoref/logs", + rotation = "daily", + compress = false, + archive = ".ontoref/logs/archive", + max_files = 7, + }, + + mode_run = { + rules = [ + { when = { mode_id = "validate-ontology" }, allow = true, reason = "validation always allowed" }, + { when = { actor = "agent" }, allow = true, reason = "agent actor always allowed" }, + { when = { actor = "ci" }, allow = true, reason = "ci actor always allowed" }, + ], + }, + + nats_events = { + enabled = false, + url = "nats://localhost:4222", + emit = [], + subscribe = [], + handlers_dir = "reflection/handlers", + }, +} diff --git a/templates/scripts-ontoref b/templates/scripts-ontoref new file mode 100644 index 0000000..ac3633d --- /dev/null +++ b/templates/scripts-ontoref @@ -0,0 +1,45 @@ +#!/bin/bash +# scripts/ontoref — thin wrapper for projects consuming the ontoref protocol +# Set ONTOREF_ROOT to the ontoref checkout, then delegate to its entry point. +# +# Usage: ./scripts/ontoref [args...] +# Alias: Add `alias ontoref="./scripts/ontoref"` to your shell profile. +# +# Required env vars (exported here): +# ONTOREF_ROOT — absolute path to ontoref checkout +# ONTOREF_PROJECT_ROOT — absolute path to THIS project root + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +readonly SCRIPT_DIR +PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +readonly PROJECT_ROOT + +# ── Ontoref root ────────────────────────────────────────────────────────────── +# Point to your ontoref checkout. Can be overridden via env var. + +ONTOREF_ROOT="${ONTOREF_ROOT:-{{ ontoref_dir }}}" +readonly ONTOREF_ROOT + +if [[ ! -f "${ONTOREF_ROOT}/ontoref" ]]; then + echo "ontoref: cannot find ontoref entry point at ${ONTOREF_ROOT}/ontoref" + echo " Set ONTOREF_ROOT to the correct path or update this script." + exit 1 +fi + +# ── Export project context ──────────────────────────────────────────────────── + +export ONTOREF_ROOT +export ONTOREF_PROJECT_ROOT="${PROJECT_ROOT}" + +# Prepend project-specific paths so they take priority over any inherited +# NICKEL_IMPORT_PATH. Existing value is preserved as a fallback at the end. +_project_paths="${PROJECT_ROOT}:${PROJECT_ROOT}/.ontology:${PROJECT_ROOT}/adrs:${ONTOREF_ROOT}/adrs:${ONTOREF_ROOT}/ontology/schemas:${ONTOREF_ROOT}" +export NICKEL_IMPORT_PATH="${_project_paths}${NICKEL_IMPORT_PATH:+:${NICKEL_IMPORT_PATH}}" +unset _project_paths + +# Preserve caller name for dispatcher help output +export ONTOREF_CALLER="${ONTOREF_CALLER:-./scripts/ontoref}" + +exec "${ONTOREF_ROOT}/ontoref" "$@"