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).
245 lines
12 KiB
Text
245 lines
12 KiB
Text
let s = import "./schema.ncl" in
|
|
|
|
# Tool and dependency requirements for the ontoref ecosystem.
|
|
# Query (agent or newcomer):
|
|
# nickel export reflection/requirements/base.ncl | get tools | select id binary version_min install_hint
|
|
#
|
|
# Query by context:
|
|
# nickel export reflection/requirements/base.ncl | get tools | where (contexts | any { |c| $c == "local_dev" })
|
|
#
|
|
# Validate environment:
|
|
# nu reflection/bin/check-prereqs.nu --context local_dev
|
|
|
|
{
|
|
tools = [
|
|
|
|
# ── Core (required in every context) ─────────────────────────────────────
|
|
|
|
({
|
|
id = "nickel",
|
|
binary = "nickel",
|
|
description = "Type-safe configuration language. Primary config source of truth (ADR-001).",
|
|
version_min = "1.9.0",
|
|
check_cmd = "nickel --version",
|
|
version_extract = "nickel (\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "cargo install nickel-lang-cli # or: brew install nickel-lang",
|
|
docs_url = "https://nickel-lang.org",
|
|
severity = 'Hard,
|
|
contexts = ["local_dev", "ci", "agent", "benchmark"],
|
|
used_by_forms = ["new_adr", "query_constraints", "new_project", "supersede_adr"],
|
|
used_by_modes = ["new_adr", "read_as_agent", "validate_decision", "supersede_adr"],
|
|
} | s.Tool),
|
|
|
|
({
|
|
id = "nushell",
|
|
binary = "nu",
|
|
description = "Structured shell and scripting language. Used for check_hints, scripts, and mode execution.",
|
|
version_min = "0.110.0",
|
|
check_cmd = "nu --version",
|
|
version_extract = "(\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "cargo install nu # or: brew install nushell",
|
|
docs_url = "https://nushell.sh",
|
|
severity = 'Hard,
|
|
contexts = ["local_dev", "ci", "agent", "benchmark"],
|
|
used_by_forms = ["new_project", "supersede_adr"],
|
|
used_by_modes = ["validate_decision", "new_project", "supersede_adr", "query_constraints"],
|
|
config_check = "nu -c 'version | get version'",
|
|
config_hint = "Minimum 0.110.0 required for pipeline let binding and `| complete` patterns.",
|
|
} | s.Tool),
|
|
|
|
({
|
|
id = "git",
|
|
binary = "git",
|
|
description = "Version control. Required for ADR commit workflow and project initialization.",
|
|
version_min = "2.40.0",
|
|
check_cmd = "git --version",
|
|
version_extract = "git version (\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "brew install git # or: system package manager",
|
|
severity = 'Hard,
|
|
contexts = ["local_dev", "ci"],
|
|
used_by_forms = ["new_adr", "supersede_adr", "new_project"],
|
|
used_by_modes = ["new_adr", "supersede_adr", "new_project"],
|
|
} | s.Tool),
|
|
|
|
# ── Interactive / form layer ──────────────────────────────────────────────
|
|
|
|
({
|
|
id = "typedialog",
|
|
binary = "typedialog",
|
|
description = "Multibackend form runner. Required for interactive ADR authoring and project initialization. Forms are NCL records (not TOML). Uses nickel-roundtrip for editing existing files.",
|
|
version_min = "0.1.0",
|
|
check_cmd = "typedialog --version",
|
|
version_extract = "typedialog (\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "cargo install typedialog",
|
|
docs_url = "https://repo.jesusperez.pro/jesus/typedialog",
|
|
severity = 'Soft,
|
|
contexts = ["local_dev"],
|
|
used_by_forms = ["new_adr", "new_project", "supersede_adr", "query_constraints"],
|
|
used_by_modes = ["new_adr", "new_project", "supersede_adr"],
|
|
config_check = "do { ^typedialog --version } | complete | get stdout | str contains '0.'",
|
|
config_hint = "Forms use NCL format (not TOML). Command: typedialog nickel-roundtrip --input <file.ncl> --form <form.ncl> --output <out.ncl>",
|
|
} | s.Tool),
|
|
|
|
# ── NATS ─────────────────────────────────────────────────────────────────
|
|
|
|
({
|
|
id = "nats-cli",
|
|
binary = "nats",
|
|
description = "NATS CLI for stream creation and message publishing. Required for ecosystem event publishing and NATS stream setup.",
|
|
version_min = "0.1.0",
|
|
check_cmd = "nats --version",
|
|
version_extract = "(\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "brew install nats-io/nats-tools/nats # or: go install github.com/nats-io/natscli/nats@latest",
|
|
severity = 'Soft,
|
|
contexts = ["local_dev"],
|
|
used_by_forms = ["new_project"],
|
|
used_by_modes = ["new_project"],
|
|
config_check = "do { ^nats server check --server nats://localhost:4222 } | complete | get stdout | str contains 'OK'",
|
|
config_hint = "NATS server must be running at nats://localhost:4222 for ecosystem event publishing. Start: nats-server -js",
|
|
} | s.Tool),
|
|
|
|
# ── Nu plugins ───────────────────────────────────────────────────────────
|
|
# Checked via `plugin list`, not `which`. plugin_name drives the check path.
|
|
|
|
({
|
|
id = "nu-plugin-nickel",
|
|
binary = "nu_plugin_nickel",
|
|
plugin_name = "nickel",
|
|
description = "Nushell plugin for Nickel. Provides nickel-export (no from json), nickel-eval (cached), nickel-validate, nickel-format.",
|
|
version_min = "0.110.0",
|
|
check_cmd = "plugin list | where name == 'nickel' | first | get version",
|
|
install_hint = "plugin add ~/.local/bin/nu_plugin_nickel # then restart nu",
|
|
severity = 'Soft,
|
|
contexts = ["local_dev", "agent"],
|
|
used_by_forms = ["new_adr", "new_project", "supersede_adr"],
|
|
used_by_modes = ["new_adr", "new_project"],
|
|
} | s.Tool),
|
|
|
|
({
|
|
id = "nu-plugin-tera",
|
|
binary = "nu_plugin_tera",
|
|
plugin_name = "tera",
|
|
description = "Nushell plugin for Tera (Jinja2-compatible) template rendering. Used by agent render path: nickel-export | tera-render template.ncl.j2.",
|
|
version_min = "0.110.0",
|
|
check_cmd = "plugin list | where name == 'tera' | first | get version",
|
|
install_hint = "plugin add ~/.local/bin/nu_plugin_tera # then restart nu",
|
|
severity = 'Soft,
|
|
contexts = ["local_dev", "agent"],
|
|
used_by_forms = ["new_adr", "new_project", "supersede_adr"],
|
|
used_by_modes = ["new_adr", "new_project"],
|
|
} | s.Tool),
|
|
|
|
({
|
|
id = "nu-plugin-nats",
|
|
binary = "nu_plugin_nats",
|
|
plugin_name = "nats",
|
|
description = "Nushell plugin for NATS JetStream. Provides nats pub, nats stream setup, nats status, nats notify.",
|
|
version_min = "0.110.0",
|
|
check_cmd = "plugin list | where name == 'nats' | first | get version",
|
|
install_hint = "plugin add /path/to/nu_plugin_nats # then restart nu",
|
|
severity = 'Soft,
|
|
contexts = ["local_dev"],
|
|
used_by_forms = ["new_project"],
|
|
used_by_modes = ["new_project"],
|
|
config_check = "plugin list | where name == 'nats' | is-not-empty | into string",
|
|
config_hint = "nats plugin must be registered: plugin add /path/to/nu_plugin_nats",
|
|
} | s.Tool),
|
|
|
|
# ── Optional ecosystem tooling ────────────────────────────────────────────
|
|
|
|
({
|
|
id = "kogral",
|
|
binary = "kogral",
|
|
description = "Graph database CLI. Optional — new_project continues without it.",
|
|
version_min = "0.1.0",
|
|
check_cmd = "kogral --version",
|
|
version_extract = "(\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "cargo install kogral # see: https://repo.jesusperez.pro/jesus/kogral",
|
|
severity = 'Soft,
|
|
contexts = ["local_dev"],
|
|
used_by_forms = ["new_project"],
|
|
used_by_modes = ["new_project"],
|
|
} | s.Tool),
|
|
|
|
({
|
|
id = "syntaxis",
|
|
binary = "syntaxis",
|
|
description = "Project registry CLI. Optional — new_project continues without it.",
|
|
version_min = "0.1.0",
|
|
check_cmd = "syntaxis --version",
|
|
version_extract = "(\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "cargo install syntaxis # see: https://repo.jesusperez.pro/jesus/syntaxis",
|
|
severity = 'Soft,
|
|
contexts = ["local_dev"],
|
|
used_by_forms = ["new_project"],
|
|
used_by_modes = ["new_project"],
|
|
} | s.Tool),
|
|
|
|
# ── OCI credential and artifact layer (ADR-017) ───────────────────────────
|
|
|
|
({
|
|
id = "oras",
|
|
binary = "oras",
|
|
description = "OCI Registry As Storage client. Required to push/pull domain artifacts, mode artifacts, and src-vault OCI artifacts. Primary mechanism for ontoref OCI discovery.",
|
|
version_min = "1.2.0",
|
|
check_cmd = "oras version",
|
|
version_extract = "Version:\\s+(\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "brew install oras # or: https://oras.land/docs/installation",
|
|
docs_url = "https://oras.land",
|
|
severity = 'Hard,
|
|
contexts = ["local_dev", "ci", "agent"],
|
|
used_by_forms = [],
|
|
used_by_modes = ["new_project"],
|
|
config_hint = "All oras calls use an isolated DOCKER_CONFIG tmpdir (ADR-017) — never ambient ~/.docker/config.json.",
|
|
} | s.Tool),
|
|
|
|
({
|
|
id = "cosign",
|
|
binary = "cosign",
|
|
description = "Artifact signing and verification. Required to sign src-vault OCI artifacts on push and verify on pull. Prevents artifact substitution attacks on credential distribution.",
|
|
version_min = "2.0.0",
|
|
check_cmd = "cosign version",
|
|
version_extract = "GitVersion:\\s+(\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "brew install cosign # or: https://docs.sigstore.dev/cosign/system_config/installation/",
|
|
docs_url = "https://docs.sigstore.dev/cosign",
|
|
severity = 'Hard,
|
|
contexts = ["local_dev", "ci"],
|
|
used_by_forms = [],
|
|
used_by_modes = [],
|
|
config_hint = "COSIGN_KEY_PATH env var or --cosign-key flag selects the signing key. Unsigned src-vault artifacts are rejected by ore secrets pull.",
|
|
} | s.Tool),
|
|
|
|
({
|
|
id = "sops",
|
|
binary = "sops",
|
|
description = "Secrets OPerationS — multi-recipient encrypted file editor. Encrypts/decrypts access.sops.yaml containing registry credentials and vault_key.",
|
|
version_min = "3.8.0",
|
|
check_cmd = "sops --version",
|
|
version_extract = "sops (\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "brew install sops # or: https://github.com/getsops/sops/releases",
|
|
docs_url = "https://getsops.io",
|
|
severity = 'Hard,
|
|
contexts = ["local_dev", "ci"],
|
|
used_by_forms = [],
|
|
used_by_modes = [],
|
|
config_hint = "SOPS_AGE_KEY_FILE must point to the .kage master key (declared in project.ncl sops.master_key_path). Never inside vault dir.",
|
|
} | s.Tool),
|
|
|
|
({
|
|
id = "age",
|
|
binary = "age-keygen",
|
|
description = "age encryption key generator. Required to provision new actor keypairs for multi-recipient sops vaults.",
|
|
version_min = "1.1.0",
|
|
check_cmd = "age-keygen --version",
|
|
version_extract = "v(\\d+\\.\\d+\\.\\d+)",
|
|
install_hint = "brew install age # or: https://github.com/FiloSottile/age/releases",
|
|
docs_url = "https://age-encryption.org",
|
|
severity = 'Soft,
|
|
contexts = ["local_dev"],
|
|
used_by_forms = [],
|
|
used_by_modes = [],
|
|
config_hint = "Only needed when generating new keypairs (just secrets-gen-key). Decryption uses sops which bundles its own age support.",
|
|
} | s.Tool),
|
|
|
|
],
|
|
}
|