ontoref-derive: #[onto_mcp_tool] attribute macro registers MCP tool unit-structs in
the catalog at link time via inventory::submit!; annotated item is emitted unchanged,
ToolBase/AsyncTool impls stay on the struct. All 34 tools migrated from manual wiring
(net +5: ontoref_list_projects, ontoref_search, ontoref_describe,
ontoref_list_ontology_extensions, ontoref_get_ontology_extension).
validate modes (ADR-018): reads level_hierarchy from workflow.ncl and checks every
.ncl mode for level declared, strategy declared, delegate chain coherent, compose
extends valid. mode resolve <id> shows which hierarchy level handles a mode and why.
--self-test generates synthetic fixtures in a temp dir for CI smoke-testing.
validate run-cargo: two-step Cargo.toml resolution — workspace layout first
(crates/<check.crate>/Cargo.toml), single-crate fallback by package name or repo
basename. Lets the same ADR constraint shape apply to workspace and single-crate repos.
ontology/schemas/manifest.ncl: registry_topology_type contract — multi-registry
coordination, push targets, participant scopes, per-namespace capability.
reflection/requirements/base.ncl: oras ≥1.2.0, cosign ≥2.0.0, sops ≥3.9.0, age
≥1.1.0, restic declared as Hard/Soft requirements with version_min, check_cmd, and
install_hint (ADR-017 toolchain surface).
ADR-019: per-file recipient routing for tenant isolation without multi-vault. Schema
additions: sops.recipient_groups + sops.recipient_rules in ontoref-project.ncl.
secrets-bootstrap generates .sops.yaml from project.ncl in declarative mode. Three
new secrets-audit checks: recipient-routing-coherent, recipient-routing-coverage,
no-multi-vault. Adoption templates: single-team/, multi-tenant/, agent-first/.
Integration templates: domain-producer/, mode-producer/, mode-consumer/.
UI: project_picker surfaces registry badge (⟳ participant) and vault badge
(⛁ vault_id · N, green=declarative / amber=legacy) per project card. Expanded panel
adds collapsible Registry section with namespace, endpoint, and push/pull capability.
manage.html gains Runtime Services card — MCP and GraphQL toggleable without restart
via HTMX POST /ui/manage/services/{service}/toggle.
describe.nu: capabilities JSON includes registry_topology and vault_state per project.
sync.nu: drift check extended to detect //! absence on newly registered crates.
qa.ncl: six entries — credential-vault-best-practice (layered data-flow diagram),
credential-vault-templates (paths A/B/C), credential-vault-troubleshooting (15 named
errors), integration-what-and-why (ADR-042 OCI federation), integration-how-to-implement,
integration-troubleshooting.
on+re: core.ncl + manifest.ncl updated to reflect OCI, MCP, and mode-hierarchy nodes.
Deleted stale presentation assets (2026-02 slides + voice notes).
495 lines
23 KiB
Text
495 lines
23 KiB
Text
let content = import "content.ncl" in
|
|
|
|
let repo_kind_type = [|
|
|
'Framework,
|
|
'DevWorkspace,
|
|
'PublishedCrate,
|
|
'Service,
|
|
'Library,
|
|
'AgentResource,
|
|
'Mixed,
|
|
'PersonalOntology,
|
|
|] in
|
|
|
|
let consumer_type = [|
|
|
'Developer,
|
|
'Agent,
|
|
'EndUser,
|
|
'CI,
|
|
'Downstream,
|
|
|] in
|
|
|
|
let artifact_kind_type = [|
|
|
'RustDoc,
|
|
'JsonSchema,
|
|
'ContainerImage,
|
|
'CratePackage,
|
|
'StaticSite,
|
|
'NuPlugin,
|
|
'OntologyExport,
|
|
|] in
|
|
|
|
let audit_level_type = [|
|
|
'Quick,
|
|
'Standard,
|
|
'Strict,
|
|
|] in
|
|
|
|
# ── Operational layers ──────────────────────────────────────────────────────
|
|
# A layer is a named region of the repo with visibility rules per mode.
|
|
# The `committed` flag distinguishes product (true) from process (false).
|
|
|
|
let layer_type = {
|
|
id | String,
|
|
paths | Array String,
|
|
committed | Bool,
|
|
description | String | default = "",
|
|
} in
|
|
|
|
# ── Operational modes ───────────────────────────────────────────────────────
|
|
# A mode is an active perspective the developer/agent switches into.
|
|
# It determines which layers are visible and what audit level applies.
|
|
|
|
let op_mode_type = {
|
|
id | String,
|
|
description | String | default = "",
|
|
visible_layers | Array String,
|
|
audit_level | audit_level_type | default = 'Standard,
|
|
pre_activate | Array String | default = [],
|
|
post_activate | Array String | default = [],
|
|
} in
|
|
|
|
# ── Publication service ─────────────────────────────────────────────────────
|
|
# Where artifacts go and what operations surround the publish action.
|
|
|
|
let auth_method_type = [|
|
|
'SSH,
|
|
'Token,
|
|
'OIDC,
|
|
'None,
|
|
|] in
|
|
|
|
let service_scope_type = [|
|
|
'Public,
|
|
'PrivateNetwork,
|
|
'LocalRegistry,
|
|
'SelfHosted,
|
|
|] in
|
|
|
|
let publication_service_type = {
|
|
id | String,
|
|
artifact | artifact_kind_type,
|
|
scope | service_scope_type,
|
|
registry_url | String | default = "",
|
|
auth_method | auth_method_type | default = 'None,
|
|
pre_publish | Array String | default = [],
|
|
post_publish | Array String | default = [],
|
|
condition | String | default = "",
|
|
trigger | String,
|
|
} in
|
|
|
|
# ── Consumption modes (who consumes, what they need) ────────────────────────
|
|
|
|
let consumption_mode_type = {
|
|
consumer | consumer_type,
|
|
needs | Array artifact_kind_type,
|
|
audit_level | audit_level_type | default = 'Standard,
|
|
description | String | default = "",
|
|
} in
|
|
|
|
# ── Tool requirements ─────────────────────────────────────────────────────
|
|
# Declares what tools the project needs. install-tools.nu and sync audit
|
|
# consume this to verify availability or trigger installation.
|
|
|
|
let install_method_type = [|
|
|
'Builtin,
|
|
'Cargo,
|
|
'Npm,
|
|
'Brew,
|
|
'Pip,
|
|
'Manual,
|
|
|] in
|
|
|
|
let tool_requirement_type = {
|
|
name | String,
|
|
install_method | install_method_type | default = 'Builtin,
|
|
version | String | default = "",
|
|
required | Bool | default = true,
|
|
} in
|
|
|
|
# ── Justfile convention ──────────────────────────────────────────────────
|
|
# Declares expected justfile structure so sync audit can verify completeness.
|
|
|
|
let justfile_system_type = [| 'Import, 'Mod, 'Hybrid, 'Flat, 'None |] in
|
|
|
|
let justfile_convention_type = {
|
|
system | justfile_system_type | default = 'Mod,
|
|
required_modules | Array String | default = ["build", "test", "dev", "ci"],
|
|
required_recipes | Array String | default = ["default", "help"],
|
|
} in
|
|
|
|
# ── Config surface ──────────────────────────────────────────────────────
|
|
# Describes the project's configuration system: where the NCL config lives,
|
|
# how it is structured, and which consumers (Rust structs, Nushell scripts,
|
|
# CI pipelines, external tools) read each section.
|
|
#
|
|
# A field in a section is "unclaimed" only if no consumer declares it —
|
|
# not merely absent from the Rust struct. CI/CD scripts and external tooling
|
|
# are first-class consumers.
|
|
#
|
|
# Mutation uses an override layer: original NCL files are never modified.
|
|
# Changes are written to {section}.overrides.ncl and merged via & at the
|
|
# entry point. Comments, contracts, and formatting in originals are preserved.
|
|
|
|
let config_kind_type = [|
|
|
'NclMerge, # multiple .ncl files merged via & operator
|
|
'TypeDialog, # .typedialog/ structure with form.toml + validators + fragments
|
|
'SingleFile, # single monolithic .ncl file
|
|
|] in
|
|
|
|
let consumer_kind_type = [|
|
|
'RustStruct, # serde::Deserialize struct in a Rust crate
|
|
'NuScript, # Nushell script accessing $config.field paths
|
|
'CiPipeline, # CI pipeline (Woodpecker, GitHub Actions, etc.)
|
|
'External, # external tool or process reading config JSON
|
|
|] in
|
|
|
|
let config_consumer_type = {
|
|
# Identifier for this consumer (e.g. "vapora-backend", "deploy-script").
|
|
id | String,
|
|
kind | consumer_kind_type,
|
|
# Reference path: Rust fully-qualified type or script path.
|
|
# e.g. "vapora_backend::config::ServerConfig" or "scripts/deploy.nu"
|
|
ref | String | default = "",
|
|
# Fields this consumer reads. Empty means the consumer reads all fields,
|
|
# which is treated as claiming all NCL keys for orphan analysis.
|
|
fields | Array String | default = [],
|
|
} in
|
|
|
|
let config_section_type = {
|
|
# Section identifier, must match the top-level NCL key (e.g. "server").
|
|
id | String,
|
|
# Path to the NCL file for this section, relative to config_root.
|
|
file | String,
|
|
# Path to the NCL contract file that types this section. Relative to
|
|
# contracts_path (or project root if contracts_path is empty).
|
|
contract | String | default = "",
|
|
description | String | default = "",
|
|
# Why this section exists and why the current values were chosen.
|
|
# Consumed by the quickref generator to explain decisions, not just values.
|
|
rationale | String | default = "",
|
|
# When false: ontoref will only read, never write, this section.
|
|
mutable | Bool | default = true,
|
|
# All consumers of this section. A NCL field present in no consumer is
|
|
# flagged as unclaimed in the coherence report.
|
|
consumers | Array config_consumer_type | default = [],
|
|
} in
|
|
|
|
let config_surface_type = {
|
|
# Directory containing config NCL files, relative to project root.
|
|
# e.g. "config/", "site/config/", ".typedialog/provisioning/"
|
|
config_root | String,
|
|
# Main NCL file that merges all sections (entry point for nickel export).
|
|
entry_point | String | default = "config.ncl",
|
|
kind | config_kind_type | default = 'NclMerge,
|
|
# Directory containing NCL contract files. Relative to project root.
|
|
# Passed as NICKEL_IMPORT_PATH component when exporting.
|
|
contracts_path | String | default = "",
|
|
# Directory where ontoref writes {section}.overrides.ncl files.
|
|
# Defaults to config_root when empty.
|
|
overrides_dir | String | default = "",
|
|
sections | Array config_section_type | default = [],
|
|
} in
|
|
|
|
# ── Claude baseline ─────────────────────────────────────────────────────
|
|
# Declares expected .claude/ structure per project.
|
|
|
|
let claude_baseline_type = {
|
|
guidelines | Array String | default = ["bash", "nushell"],
|
|
session_hook | Bool | default = true,
|
|
stratum_commands | Bool | default = true,
|
|
} in
|
|
|
|
# ── Capabilities ────────────────────────────────────────────────────────────
|
|
# Declares what the project does, why it was built, how it works, and what
|
|
# artifacts it produces. Answers the "what IS this, why does it exist, how
|
|
# does it work" questions that Practice nodes in core.ncl don't — those are
|
|
# architectural; capabilities are operational and audience-facing.
|
|
|
|
let capability_type = {
|
|
# Unique identifier, e.g. "protocol-spec", "daemon-api".
|
|
id | String,
|
|
name | String,
|
|
# One-line answer to "what does this capability do?" for quick scanning.
|
|
summary | String,
|
|
# The WHY: motivation, problem solved, alternatives consciously rejected.
|
|
rationale | String | default = "",
|
|
# Implementation level: key patterns, entry points, data flows.
|
|
how | String | default = "",
|
|
# Observable artifacts: crate paths, API routes, NCL schemas, CLI commands.
|
|
artifacts | Array String | default = [],
|
|
# ADR IDs that formalize architectural decisions in this capability.
|
|
adrs | Array String | default = [],
|
|
# Ontology node IDs this capability manifests in the DAG.
|
|
nodes | Array String | default = [],
|
|
} in
|
|
|
|
# ── Requirements ─────────────────────────────────────────────────────────────
|
|
# Declares what the project needs to run (production) or develop (development).
|
|
# Covers tools, external services, environment variables, and infrastructure —
|
|
# not just dev tooling. Enables agents and operators to audit readiness.
|
|
|
|
let env_target_type = [|
|
|
'Production, # required only in production deployments
|
|
'Development, # required only during development / CI
|
|
'Both, # required in all environments
|
|
|] in
|
|
|
|
let requirement_kind_type = [|
|
|
'Tool, # executable on PATH (e.g. nushell, nickel, just)
|
|
'Service, # external service (e.g. surrealdb, nats, postgres)
|
|
'EnvVar, # environment variable that must be set
|
|
'Infrastructure, # filesystem layout, network, or platform dependency
|
|
|] in
|
|
|
|
let requirement_type = {
|
|
id | String,
|
|
name | String,
|
|
env | env_target_type | default = 'Both,
|
|
kind | requirement_kind_type,
|
|
# Minimum version or value constraint. Empty means no constraint.
|
|
version | String | default = "",
|
|
required | Bool | default = true,
|
|
# What breaks or degrades if this requirement is absent.
|
|
impact | String | default = "",
|
|
# How to install, set, or provision this requirement.
|
|
provision | String | default = "",
|
|
} in
|
|
|
|
# ── Critical Dependencies ────────────────────────────────────────────────────
|
|
# External dependencies (crates, services, infra) whose contract breakage or
|
|
# disappearance has a documented blast radius. Distinct from requirements:
|
|
# requirements are prerequisites to run; critical_deps are runtime load-bearing
|
|
# dependencies whose failure affects specific capabilities.
|
|
|
|
let critical_dep_type = {
|
|
id | String,
|
|
name | String,
|
|
# Canonical reference: crates.io identifier, GitHub URL, or service name.
|
|
ref | String,
|
|
# Which capabilities or features depend on this dependency.
|
|
used_for | String,
|
|
# What breaks if this dep disappears or breaks its API contract.
|
|
failure_impact | String,
|
|
# Mitigation: feature flags, fallbacks, alternative build targets.
|
|
mitigation | String | default = "",
|
|
} in
|
|
|
|
# ── Registry topology ────────────────────────────────────────────────────────
|
|
# Declares the multi-registry topology for coordination: which registries
|
|
# exist, their roles, and which participant namespaces this project owns.
|
|
# Mirrors capabilities.ncl RegistriesConfig from the provisioning schema so
|
|
# ontoref consumer projects can declare registry intent without a dep on the
|
|
# provisioning crate. Consumed by resolve-registry, describe workspace, and
|
|
# the GraphQL registry_topology resolver.
|
|
|
|
let registry_role_type = [| 'primary, 'build, 'dev, 'mirror |] in
|
|
|
|
let registry_namespaces_type = {
|
|
own | Array String | default = [],
|
|
replicate_to | Array String | default = [],
|
|
mirror_from | String | optional,
|
|
prefixes | Array String | default = [],
|
|
} in
|
|
|
|
let registry_entry_type = {
|
|
id | String,
|
|
endpoint | String,
|
|
role | registry_role_type | default = 'dev,
|
|
tls | Bool | default = true,
|
|
namespaces | registry_namespaces_type | default = {},
|
|
# Credential references — credential_env is intentionally absent (see ADR-017).
|
|
# credential_sops paths are relative to the synced src-vault root, NOT the project
|
|
# root. The src-vault is the OCI artifact restored to ~/.config/ontoref/vaults/<vault_id>/src-vault/
|
|
# and contains encrypted credential files (typically registry/ro.sops.yaml, registry/rw.sops.yaml).
|
|
credential_sops | String | optional, # RO token — for pull/list operations
|
|
credential_sops_rw | String | optional, # RW token — for push operations
|
|
credential_oidc | String | optional, # OIDC audience (future)
|
|
# Explicit dependency declaration for impact analysis (ADR-017 constraint)
|
|
uses_registry | String | optional, # references another RegistryEntry.id
|
|
} in
|
|
|
|
let registries_config_type = {
|
|
registries | Array registry_entry_type | default = [],
|
|
default | String | optional,
|
|
} in
|
|
|
|
# Declared by a project that is a participant in the registry ecosystem:
|
|
# owns domain/mode namespaces and can push artifacts.
|
|
let registry_provides_type = {
|
|
# Identifier used to scope namespaces: domains/<participant>/, modes/<participant>/
|
|
participant | String,
|
|
registries | registries_config_type | default = {},
|
|
} in
|
|
|
|
# ── Domain ontology layer ───────────────────────────────────────────────────
|
|
# A project may have two distinct ontological layers:
|
|
# 1. Self-ontology (.ontology/) — the project describing itself: state, ADRs, practices.
|
|
# Present in any project using the ontoref protocol.
|
|
# 2. Domain ontology — schemas and contracts the project defines for others to consume
|
|
# (domain_provides), or schemas the project imports from an upstream framework
|
|
# (domain_origin). These may be NCL-based or expressed in code (Rust traits, etc.).
|
|
#
|
|
# A project that only has self-ontology omits both fields.
|
|
# A project that is a framework defines domain_provides.
|
|
# A project that is an implementation defines domain_origin.
|
|
# Both fields are optional and independent.
|
|
|
|
let domain_ontology_kind_type = [|
|
|
'Ncl, # domain schemas are NCL contracts (importable via NICKEL_IMPORT_PATH)
|
|
'RustTrait, # domain contracts are Rust traits / type-system boundaries
|
|
'Mixed, # combination of NCL contracts and code-level contracts
|
|
'Implicit, # no formal schema; the domain is implicit in conventions and documentation
|
|
|] in
|
|
|
|
let domain_provides_type = {
|
|
# Canonical identifier for the domain this project defines.
|
|
id | String,
|
|
# Human-readable domain name.
|
|
name | String,
|
|
# Where the domain schemas / contracts live within this project.
|
|
schema_path | String | default = "ontology/schemas/",
|
|
# repo_kind expected for implementation projects consuming this domain.
|
|
impl_repo_kind | String | default = "",
|
|
# How the domain is expressed: NCL, RustTrait, Mixed, or Implicit.
|
|
kind | domain_ontology_kind_type | default = 'Ncl,
|
|
description | String | default = "",
|
|
} in
|
|
|
|
let domain_origin_type = {
|
|
# Identifier matching the upstream framework's domain_provides.id.
|
|
id | String,
|
|
# Human-readable name of the upstream framework / core project.
|
|
name | String,
|
|
# Local filesystem path to the upstream framework project root.
|
|
# Used to resolve NICKEL_IMPORT_PATH entries and CLI navigation.
|
|
path | String | default = "",
|
|
# Which schema stems from the upstream domain are imported/extended.
|
|
# Empty means the project inherits the full domain surface.
|
|
extends | Array String | default = [],
|
|
# If true, this project's self-ontology (.ontology/) IS the domain implementation.
|
|
# If false, the domain schemas are consumed but the self-ontology is independent.
|
|
integrated | Bool | default = true,
|
|
} in
|
|
|
|
# ── Level identity (ADR-018) ────────────────────────────────────────────────
|
|
# Declares where a project sits in the ontoref specialization hierarchy.
|
|
# 'Base = 1 (ontoref itself — generic protocol), 'Domain = 2 (project-type domain,
|
|
# e.g. provisioning), 'Instance = 3 (concrete workspace/infra derived from a domain).
|
|
# Absent at 'Base (base is always Override by definition; no parent exists).
|
|
# Required at 'Domain and 'Instance to enable observable traversal (ore mode resolve).
|
|
|
|
let level_index_type = [| 'Base, 'Domain, 'Instance |] in
|
|
|
|
let level_type = {
|
|
# 'Base=1, 'Domain=2, 'Instance=3 — position in the specialization hierarchy.
|
|
index | level_index_type,
|
|
# Stable identifier for this level (e.g. "ontoref-base", "provisioning-domain").
|
|
name | String,
|
|
# Name of the upstream project this level extends. Absent at 'Base.
|
|
parent | String | optional,
|
|
# Absolute path to the parent project on disk.
|
|
# When set, ore validate modes --check delegate-chain verifies that each Delegate
|
|
# mode exists in {parent_path}/reflection/modes/ — Hard failure if not found there.
|
|
parent_path | String | optional,
|
|
} in
|
|
|
|
# ── Root manifest ───────────────────────────────────────────────────────────
|
|
|
|
let manifest_type = {
|
|
project | String,
|
|
repo_kind | repo_kind_type,
|
|
# Human-readable project description. Consumed by collect-identity in describe.nu.
|
|
description | String | default = "",
|
|
layers | Array layer_type | default = [],
|
|
operational_modes | Array op_mode_type | default = [],
|
|
consumption_modes | Array consumption_mode_type,
|
|
publication_services | Array publication_service_type | default = [],
|
|
tools | Array tool_requirement_type | default = [],
|
|
justfile | justfile_convention_type | default = {},
|
|
claude | claude_baseline_type | default = {},
|
|
default_audit | audit_level_type | default = 'Standard,
|
|
default_mode | String | default = "dev",
|
|
# Node ID this project maps to in the ontology DAG.
|
|
# Used by portfolio tooling to cross-reference publication cards.
|
|
ontology_node | String | default = "",
|
|
# Publishable content assets (logos, diagrams, web pages).
|
|
# Declares source paths and publication targets; consumed by publish modes
|
|
# and sync drift detection to verify assets exist and are deployed correctly.
|
|
content_assets | Array content.ContentAsset | default = [],
|
|
# Reusable NCL templates for mode steps, agent prompts, and publication cards.
|
|
# Each template is a parameterised NCL function at source_path.
|
|
templates | Array content.ContentTemplate | default = [],
|
|
# Configuration surface: where the project's NCL config lives, which
|
|
# consumers read each section, and mutation rules. Optional — projects
|
|
# without a structured config system omit this field.
|
|
config_surface | config_surface_type | optional,
|
|
# What the project does, why it was built, how each capability works,
|
|
# and which artifacts/ADRs/nodes it manifests.
|
|
capabilities | Array capability_type | default = [],
|
|
# Prerequisites for production and/or development: tools, services,
|
|
# env vars, infrastructure. Superset of the legacy `tools` field.
|
|
requirements | Array requirement_type | default = [],
|
|
# External dependencies with documented failure blast radius.
|
|
critical_deps | Array critical_dep_type | default = [],
|
|
# Domain ontology layer — optional, independent of self-ontology (.ontology/).
|
|
# Set when this project IS a domain framework defining schemas for others.
|
|
domain_provides | domain_provides_type | optional,
|
|
# Set when this project IS an implementation extending an upstream domain framework.
|
|
domain_origin | domain_origin_type | optional,
|
|
# Declares this project's participant identity and registry topology.
|
|
# participant scopes artifact namespaces: domains/<participant>/ modes/<participant>/
|
|
registry_provides | registry_provides_type | optional,
|
|
# Level identity in the three-level hierarchy (ADR-018).
|
|
# Required at 'Domain and 'Instance. Absent at 'Base (ontoref itself).
|
|
level | level_type | optional,
|
|
} in
|
|
|
|
{
|
|
RepoKind = repo_kind_type,
|
|
ConsumerType = consumer_type,
|
|
ArtifactKind = artifact_kind_type,
|
|
AuditLevel = audit_level_type,
|
|
AuthMethod = auth_method_type,
|
|
ServiceScope = service_scope_type,
|
|
InstallMethod = install_method_type,
|
|
JustfileSystem = justfile_system_type,
|
|
Layer = layer_type,
|
|
OperationalMode = op_mode_type,
|
|
ConsumptionMode = consumption_mode_type,
|
|
PublicationService = publication_service_type,
|
|
ToolRequirement = tool_requirement_type,
|
|
JustfileConvention = justfile_convention_type,
|
|
ClaudeBaseline = claude_baseline_type,
|
|
ProjectManifest = manifest_type,
|
|
ConfigKind = config_kind_type,
|
|
ConsumerKind = consumer_kind_type,
|
|
ConfigConsumer = config_consumer_type,
|
|
ConfigSection = config_section_type,
|
|
ConfigSurface = config_surface_type,
|
|
EnvTarget = env_target_type,
|
|
RequirementKind = requirement_kind_type,
|
|
Capability = capability_type,
|
|
Requirement = requirement_type,
|
|
CriticalDep = critical_dep_type,
|
|
DomainOntologyKind = domain_ontology_kind_type,
|
|
DomainProvides = domain_provides_type,
|
|
DomainOrigin = domain_origin_type,
|
|
RegistryRole = registry_role_type,
|
|
RegistryNamespaces = registry_namespaces_type,
|
|
RegistryEntry = registry_entry_type,
|
|
RegistriesConfig = registries_config_type,
|
|
RegistryProvides = registry_provides_type,
|
|
LevelIndex = level_index_type,
|
|
Level = level_type,
|
|
}
|