# Architecture

Protocol layers, runtime components, data flows, persistence tiers, and active constraints — v0.1.0

Protocol Layers
Declarative
Layer
Nickel
.ontology/core.ncl .ontology/state.ncl adrs/adr-NNN.ncl reflection/schemas/ reflection/modes/ reflection/forms/ reflection/qa.ncl .ontoref/config.ncl
Strong types, contracts, enums. Fails at definition time. No runtime evaluation — nickel export produces JSON consumed by all layers above.
Knowledge
Graph
.ontology/
4 axioms 2 tensions 12 practices nodes + edges invariants gates dimensions
The project knows what it knows. Actor-agnostic. Machine-queryable. ontoref uses its own protocol — the .ontology/ here describes ontoref itself.
Operational
Layer
Nushell
adr.nu backlog.nu coder.nu describe.nu sync.nu config.nu register.nu forms.nu +8 more
Typed Nushell pipelines over structured data — no text streams. 16 modules, each responsible for one operational domain. DAG modes validated before execution.
Entry
Point
Bash → Nu
./ontoref actor detection advisory locking NICKEL_IMPORT_PATH ./ontoref -V
Single entry point per project. Detects actor (developer / agent / CI) from flag, env var, or TTY. Acquires mkdir-based POSIX advisory lock per resource. Dispatches to Nu.
Runtime
Layer
Rust + axum
ontoref-daemon ontoref-ontology ontoref-reflection axum HTTP API Tera templates MCP server DashMap cache notify watcher drift observer search engine notification store actor registry session store SurrealDB (optional)
Optional persistent daemon. Caches nickel export results (path+mtime keyed). Serves HTTP UI (10 pages) + MCP server (19 tools). Actor registry with DashMap sessions. Notification barrier (pre_commit, drift, ontology_drift). Full-text search engine across nodes/ADRs/modes. Never a protocol requirement.
Adoption
Layer
Per-project
templates/ontology/ templates/ontoref-config.ncl templates/scripts-ontoref adopt_ontoref mode ONTOREF_PROJECT_ROOT
Each project maintains its own .ontology/ data. One ontoref checkout serves multiple projects via ONTOREF_PROJECT_ROOT. Zero lock-in — files are plain NCL.
Request Flows
CLI path — developer or agent via shell
Actor
developer · agent · CI
→
./ontoref
bash wrapper
→
ontoref.nu
Nu dispatcher
→
daemon
cache / notify
→
nickel export
.ontology/ · adrs/
→
reflection/
qa.ncl · backlog.ncl
MCP / AI agent path — Claude Code or any MCP client
AI Agent
Claude · any MCP client
→
MCP server
stdio · HTTP /mcp
→
19 tools
read · write · query
→
NCL files
git-versioned
Pre-commit barrier — notification-gated commit path
git commit
pre-commit hook fires
→
GET /notifications
/pending?token=X&project=Y
→
pending?
pre_commit · drift · ontology_drift
→
block
until acked in UI / POST /notifications/ack
→
pass
fail-open if daemon unreachable
Daemon Components

### HTTP API · /ui/{slug}

- GET/ui/{slug}/Dashboard — overview, actors, cache stats
- GET/ui/{slug}/graphD3 ontology graph (nodes by pole, edges)
- GET/ui/{slug}/searchSearch across nodes/ADRs/modes
- GET/ui/{slug}/sessionsLive actor registry
- GET/ui/{slug}/notificationsNotification feed + ack UI
- GET/ui/{slug}/backlogBacklog with priority/status
- GET/ui/{slug}/qaQ&A knowledge store
- GET/ui/{slug}/actionsQuick actions catalog
- GET/ui/{slug}/modesReflection modes browser
- GET/ui/{slug}/composeAgent task composer (live sharing)
- GET/actorsActor sessions list
- GET/search?q=&project=Search JSON endpoint
- GET/notifications/pendingPre-commit hook polling
- POST/notifications/ackAck one or all notifications
- POST/{slug}/notifications/emitEmit custom notification
- POST/{slug}/notifications/{id}/actionTrigger notification action
- POST/compose/sendDispatch mode to ./ontoref server-side
- POST/actions/runExecute quick action by id
- POST/qa/addAppend Q&A entry to NCL
- POST/qa/deleteRemove entry by id
- POST/qa/updateMutate question + answer
- GET/qa-jsonExport all Q&A entries
- POST/backlog/addAdd backlog item
- POST/backlog/statusUpdate backlog item status
- GET/backlog-jsonExport backlog as JSON
- GET/healthCache stats + uptime + SurrealDB status

### MCP Server · 19 tools

- ontoref_help — list all tools and usage
- ontoref_list_projects — enumerate loaded projects
- ontoref_set_project — set session default project
- ontoref_project_status — full project dashboard
- ontoref_describe — architecture overview
- ontoref_search — free-text across nodes/ADRs/modes
- ontoref_get — fetch node by id
- ontoref_get_node — full ontology node with edges
- ontoref_list_adrs — list ADRs by status filter
- ontoref_get_adr — full ADR with constraints
- ontoref_list_modes — list reflection modes
- ontoref_get_mode — mode DAG contract
- ontoref_get_backlog — backlog filtered by status
- ontoref_backlog — add / update_status
- ontoref_constraints — all architectural constraints
- ontoref_qa_list — list Q&A with optional filter
- ontoref_qa_add — append to reflection/qa.ncl
- ontoref_action_list — quick actions from config.ncl
- ontoref_action_add — create mode + register action

### Sessions & Actor Registry

- ActorRegistrybacked by DashMap<String, ActorSession>
- tokenrandom string, unique per session
- actor_typedeveloper · agent · CI
- registered_atISO timestamp, set on registration
- last_seenupdated on each API call
- current_modelast active reflection mode
- serializablesnapshot for disk persistence
- pre-commit CIregisters as ci actor on hook fire

### Compose / Live Sharing

- /ui/{slug}/composerenders mode form schemas as interactive HTML
- POST /compose/senddispatches ./ontoref {mode} {params} on server
- shared contextmultiple actors see same composed task live
- /ui/{slug}/manageproject registry CRUD (multi-project mode)

### Notification Store & Search

- NotificationStorein-memory queue per (project, token)
- pre_commitblocks git commits until acked by actor
- driftschema drift between codebase and ontology
- ontology_driftfrom passive observer — missing/stale/drift/broken counts
- fail-openif daemon unreachable, pre-commit hook passes
- ack workflowPOST /notifications/ack (one or all); action buttons in UI

### Search Engine

- indexesontology nodes (id, name, description)
- indexesADRs (title, context, decision)
- indexesreflection modes (name, description, steps)
- SearchResultkind · id · title · snippet · score
- used byUI search page + MCP ontoref_search tool

### NCL Files — Mutations

- reflection/qa.nclQaStore — typed entries, git-versioned; written only via crates/ontoref-daemon/src/ui/qa_ncl.rs (ADR-003 hard constraint)
- reflection/backlog.nclBacklogStore — items with status (Open/InProgress/Done/Cancelled) and priority (Critical/High/Medium/Low)
- .ontoref/config.nclquick_actions catalog, log level, NATS toggle
- reflection/modes/*.nclnew mode files created by ontoref_action_add

### Drift Observer

- watchescrates/ · .ontology/ · adrs/ · reflection/modes/
- debounce15 seconds after last filesystem event
- runssync scan → sync diff (read-only, never applies changes)
- emitsontology_drift { missing, stale, drift, broken } to NotificationStore

### SurrealDB (optional --db feature)

- connectionWebSocket to --db-url ws://...; 5s timeout at startup; fail-open
- seedsontology tables from local NCL files on startup and on file changes (via notify watcher)
- persistsactor sessions, seeded ontology tables, search index, notification history — survives daemon restarts
- without --dbDashMap-backed in-memory cache only; process-lifetime; actor sessions and search index are ephemeral

Persistence Tiers

### In-Memory — Always Active

DashMap-backed, process-lifetime — no flags required

- DashMap cache — NCL export results, path+mtime keyed
- NotificationStore — per (project, token) notification queue
- ActorRegistry — live session DashMap
- SessionStore — token → ActorSession map
- Search index — in-process full-text over loaded NCL data
- All state is lost on daemon restart
- Serializable snapshots can be written to disk as JSON/NCL

### SurrealDB — Optional `--db` Flag

WebSocket connection, fail-open — survives daemon restarts

- Actor sessions — token, type, registered_at, last_seen, mode
- Seeded ontology tables — nodes, ADRs, modes from NCL files
- Search index — persisted search index for nodes/ADRs/modes
- Notification history — acked and dismissed notifications
- Enabled with `--db-url ws://...` + `--db-namespace`
- If SurrealDB is unreachable at startup, daemon still starts using in-memory tier

Active Constraints (ADR-003 · ADR-002 · ADR-001)
qa-write-via-mutation-module
All mutations to reflection/qa.ncl must go through `crates/ontoref-daemon/src/ui/qa_ncl.rs` — no direct file writes from other call sites.
qa-schema-typed
`reflection/qa.ncl` must conform to the QaStore contract from `reflection/schemas/qa.ncl` — nickel typecheck must pass.
mcp-qa-tools-no-apply-drift
MCP tools `ontoref_qa_list` and `ontoref_qa_add` must never trigger sync apply steps or modify `.ontology/` files.
protocol-not-runtime (axiom)
ontoref-daemon is optional runtime support — not a protocol requirement. The protocol functions without it. Every module falls back to direct subprocess.
notification-barrier-fail-open
The pre-commit hook must not block git commits when the daemon is unreachable. If `GET /notifications/pending` fails (connection error, timeout), the hook must pass immediately.
ontology-crate-zero-stratumiops-deps (ADR-001)
`ontoref-ontology` must never depend on `stratum-graph`, `stratum-state`, or `stratum-orchestrator`. The ontology crate is the protocol's minimal adoption surface and must build standalone.