feat: domain extension system, VCS abstraction, personal/provisioning domains, web subpages
Domain extension system (ADR-012): bash-layer dispatch activates repo_kind-conditional CLI
domains. install.nu copies domains/ tree; short_alias wrappers generated (personal, prov).
ore help and describe capabilities domain-aware.
personal domain (PersonalOntology): career skills/talks/publications/positioning, CFP
pipeline (Watching→Delivered), opportunities lifecycle, content pipeline, Sessionize
integration. Daemon pages: /career, /personal.
provisioning domain (DevWorkspace/Mixed): FSM state, next transitions, connections graph,
gates, workspace card, capabilities, backlog. Daemon page: /provisioning.
VCS abstraction layer (ADR-013): reflection/modules/vcs.nu — uniform jj/git API via
filesystem detection (.jj/ vs .git/). opmode.nu and git-event.nu migrated off ^git.
reflection/bin/jjw.nu — jj + ontoref + Radicle agent workspace lifecycle. jjw-ncl-merge.nu
registered as jj merge tool for .ontology/ NCL conflicts. init-repo.nu for new_project mode.
jj/rad not in ontoref requirements — belong in orchestration project manifests.
'Framework RepoKind: ontology/schemas/manifest.ncl gains 'Framework variant; ontoref
self-identifies as framework — no domain activates for the protocol itself.
Web presence: personal.html and provisioning.html domain subpages. index.html gains
"Project Types — Domain Extensions" section with type cards and subpage links. Nav
compacted (Arch/Prov labels, solid backdrop-filter background).
on+re: vcs-abstraction (adrs: adr-013) and agent-workspace-orchestration Practice nodes;
21 manifest capabilities; state.ncl catalysts updated.
2026-04-07 23:08:29 +01:00
|
|
|
|
#!/usr/bin/env nu
|
|
|
|
|
|
# domains/provisioning/commands.nu — Provisioning domain CLI for ontoref.
|
|
|
|
|
|
# Dispatched by the ontoref bash wrapper when repo_kind in {DevWorkspace, Mixed}:
|
|
|
|
|
|
# ore provisioning <command> [args]
|
|
|
|
|
|
#
|
|
|
|
|
|
# Works for both DevWorkspace (workspace-level) and Mixed (platform-level) projects.
|
|
|
|
|
|
# Commands that require project-specific files (card.ncl, reflection/backlog.ncl)
|
|
|
|
|
|
# degrade gracefully when those files are absent.
|
|
|
|
|
|
|
|
|
|
|
|
def project-root [] {
|
|
|
|
|
|
$env.ONTOREF_PROJECT_ROOT? | default (pwd | path expand)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── Loaders ──────────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
def load-state [] { ^nickel export $"(project-root)/.ontology/state.ncl" | from json }
|
|
|
|
|
|
def load-core [] { ^nickel export $"(project-root)/.ontology/core.ncl" | from json }
|
|
|
|
|
|
def load-gate [] { ^nickel export $"(project-root)/.ontology/gate.ncl" | from json }
|
|
|
|
|
|
def load-connections [] { ^nickel export $"(project-root)/.ontology/connections.ncl" | from json }
|
|
|
|
|
|
def load-manifest [] { ^nickel export $"(project-root)/.ontology/manifest.ncl" | from json }
|
|
|
|
|
|
|
|
|
|
|
|
def load-card [] {
|
|
|
|
|
|
let path = $"(project-root)/card.ncl"
|
|
|
|
|
|
if ($path | path exists) { ^nickel export $path | from json } else { null }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def load-backlog [] {
|
|
|
|
|
|
let path = $"(project-root)/reflection/backlog.ncl"
|
|
|
|
|
|
if ($path | path exists) { ^nickel export $path | from json } else { { items: [] } }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── state / next / validate ──────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
export def "state" [] {
|
|
|
|
|
|
load-state | get dimensions | each { |dim|
|
|
|
|
|
|
{ dimension: $dim.id, current: $dim.current_state, desired: $dim.desired_state, horizon: $dim.horizon }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "next" [] {
|
|
|
|
|
|
load-state | get dimensions | each { |dim|
|
|
|
|
|
|
let active = $dim.transitions | where from == $dim.current_state
|
|
|
|
|
|
if ($active | is-empty) {
|
|
|
|
|
|
{ dimension: $dim.id, from: $dim.current_state, to: "–", condition: "no active transition", blocker: "–", catalyst: "–" }
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let tr = $active | first
|
|
|
|
|
|
{ dimension: $dim.id, from: $tr.from, to: $tr.to, condition: $tr.condition, blocker: $tr.blocker, catalyst: $tr.catalyst }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "validate" [decision: string] {
|
|
|
|
|
|
let core = load-core
|
|
|
|
|
|
let words = ($decision | str downcase | split row " " | where { |w| ($w | str length) > 3 })
|
|
|
|
|
|
let affected = ($core.nodes | each { |n|
|
|
|
|
|
|
let text = $"($n.id) ($n.name) ($n.description)" | str downcase
|
|
|
|
|
|
if ($words | any { |w| $text =~ $w }) { $n } else { null }
|
|
|
|
|
|
} | compact)
|
|
|
|
|
|
{
|
|
|
|
|
|
decision: $decision,
|
|
|
|
|
|
invariants_at_risk: ($affected | where invariant == true | select id level name),
|
|
|
|
|
|
tensions_touched: ($affected | where level == "Tension" | select id name),
|
|
|
|
|
|
practices_touched: ($affected | where level == "Practice" | select id name),
|
|
|
|
|
|
verdict: "manual review required — if any invariant is contradicted, justification is required",
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── connections / gates ──────────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
export def "connections" [] {
|
|
|
|
|
|
let c = load-connections
|
|
|
|
|
|
if ($c.upstream? | default [] | is-not-empty) {
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "UPSTREAM"
|
|
|
|
|
|
$c.upstream | each { |u|
|
|
|
|
|
|
print $" ($u.project) kind=($u.kind) via=($u.via)"
|
|
|
|
|
|
if ($u.node? | default "" | is-not-empty) { print $" node: ($u.node)" }
|
|
|
|
|
|
print $" ($u.note)"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($c.downstream? | default [] | is-not-empty) {
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "DOWNSTREAM"
|
|
|
|
|
|
$c.downstream | each { |d|
|
|
|
|
|
|
print $" ($d.project) kind=($d.kind) via=($d.via)"
|
|
|
|
|
|
if ($d.node? | default "" | is-not-empty) { print $" node: ($d.node)" }
|
|
|
|
|
|
print $" ($d.note)"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($c.peers? | default [] | is-not-empty) {
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "PEERS"
|
|
|
|
|
|
$c.peers | each { |p| print $" ($p.project) kind=($p.kind) via=($p.via)" }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "gates" [] {
|
|
|
|
|
|
load-gate | get membranes | each { |m|
|
|
|
|
|
|
{
|
|
|
|
|
|
membrane: $m.id,
|
|
|
|
|
|
name: $m.name,
|
|
|
|
|
|
active: $m.active,
|
|
|
|
|
|
permeability: $m.permeability,
|
|
|
|
|
|
condition: ($m.opening_condition.description? | default ""),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── card (DevWorkspace only) ─────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
export def "card" [] {
|
|
|
|
|
|
let c = load-card
|
|
|
|
|
|
if ($c | is-empty) {
|
|
|
|
|
|
print "No card.ncl found — this command is only available for DevWorkspace projects."
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
print $"id: ($c.id)"
|
|
|
|
|
|
print $"name: ($c.name)"
|
|
|
|
|
|
print $"tagline: ($c.tagline)"
|
|
|
|
|
|
print $"status: ($c.status)"
|
|
|
|
|
|
print $"version: ($c.version)"
|
|
|
|
|
|
print $"started: ($c.started_at)"
|
|
|
|
|
|
if ($c.tags? | default [] | is-not-empty) { print $"tags: ($c.tags | str join ', ')" }
|
|
|
|
|
|
if ($c.tools? | default [] | is-not-empty) { print $"tools: ($c.tools | str join ', ')" }
|
|
|
|
|
|
if ($c.features? | default [] | is-not-empty) {
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "features:"
|
|
|
|
|
|
$c.features | each { |f| print $" - ($f)" }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── capabilities (manifest.capabilities) ────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
export def "capabilities" [] {
|
|
|
|
|
|
let caps = load-manifest | get capabilities? | default []
|
|
|
|
|
|
if ($caps | is-empty) { print "No capabilities declared in manifest."; return }
|
|
|
|
|
|
$caps | select id name summary
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── backlog (platform only) ──────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
export def "backlog" [--priority: string = ""] {
|
|
|
|
|
|
let items = load-backlog | get items
|
|
|
|
|
|
if ($items | is-empty) {
|
|
|
|
|
|
print "No backlog.ncl found — this command is only available for platform projects."
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let filtered = if ($priority | is-empty) { $items } else { $items | where priority == $priority }
|
|
|
|
|
|
$filtered | each { |i|
|
|
|
|
|
|
{
|
|
|
|
|
|
id: $i.id,
|
|
|
|
|
|
priority: $i.priority,
|
|
|
|
|
|
blocked_by: ($i.blocked_by | str join ", "),
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "backlog show" [id: string] {
|
|
|
|
|
|
let items = load-backlog | get items
|
|
|
|
|
|
if ($items | is-empty) { error make { msg: "No backlog.ncl found for this project." } }
|
|
|
|
|
|
let item = $items | where id == $id
|
|
|
|
|
|
if ($item | is-empty) { error make { msg: $"Backlog item not found: ($id)" } }
|
|
|
|
|
|
let r = $item | first
|
|
|
|
|
|
print $"id: ($r.id)"
|
|
|
|
|
|
print $"priority: ($r.priority)"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "description:"
|
|
|
|
|
|
print $" ($r.description)"
|
|
|
|
|
|
if ($r.blocked_by? | default [] | is-not-empty) {
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print $"blocked_by: ($r.blocked_by | str join ', ')"
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($r.related_nodes? | default [] | is-not-empty) {
|
|
|
|
|
|
print $"nodes: ($r.related_nodes | str join ', ')"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat: #[onto_mcp_tool] catalog, OCI credential vault layer, validate ADR-018 mode hierarchy
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).
2026-05-12 04:46:15 +01:00
|
|
|
|
# ─── install (Mixed/platform only) ───────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
def detect-platform []: nothing -> string {
|
|
|
|
|
|
if (do { ^which docker } | complete | get exit_code) == 0 { "docker" }
|
|
|
|
|
|
else if (do { ^which podman } | complete | get exit_code) == 0 { "podman" }
|
|
|
|
|
|
else if (do { ^which kubectl } | complete | get exit_code) == 0 { "kubernetes" }
|
|
|
|
|
|
else { "" }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "install" [
|
|
|
|
|
|
--mode: string = "solo" # Deployment mode: solo|multi-user|cicd|enterprise
|
|
|
|
|
|
--platform: string = "" # Container platform: docker|podman|kubernetes (auto-detected)
|
|
|
|
|
|
--dry-run # Print what would be run without executing
|
|
|
|
|
|
]: nothing -> nothing {
|
|
|
|
|
|
let root = (project-root)
|
|
|
|
|
|
|
|
|
|
|
|
let installer_bin = [$root, "platform", "target", "release", "provisioning-installer"] | path join
|
|
|
|
|
|
let installer_src = [$root, "platform", "installer"] | path join
|
|
|
|
|
|
let just_available = (do { ^which just } | complete | get exit_code) == 0
|
|
|
|
|
|
|
|
|
|
|
|
let resolved_platform = if ($platform | is-not-empty) { $platform } else { detect-platform }
|
|
|
|
|
|
|
|
|
|
|
|
print $"Platform install mode=($mode) platform=(if ($resolved_platform | is-empty) { '?' } else { $resolved_platform })"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
|
|
|
|
|
|
if ($resolved_platform | is-empty) {
|
|
|
|
|
|
print "No supported container platform found (docker, podman, kubectl)."
|
|
|
|
|
|
print "Install one and retry."
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($installer_bin | path exists) {
|
|
|
|
|
|
print $"installer binary: ($installer_bin)"
|
|
|
|
|
|
if $dry_run {
|
|
|
|
|
|
print $"[dry-run] would run: ($installer_bin) --headless --mode ($mode) --platform ($resolved_platform) --yes"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
do { ^$installer_bin --headless --mode $mode --platform $resolved_platform --yes } | complete | ignore
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if ($installer_src | path exists) {
|
|
|
|
|
|
print "installer binary not built — building from source..."
|
|
|
|
|
|
if $dry_run {
|
|
|
|
|
|
print $"[dry-run] would run: cargo build --release --manifest-path ($installer_src)/Cargo.toml"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let r = do { ^cargo build --release --manifest-path $"($installer_src)/Cargo.toml" } | complete
|
|
|
|
|
|
if $r.exit_code != 0 {
|
|
|
|
|
|
error make { msg: $"installer build failed:\n($r.stderr)" }
|
|
|
|
|
|
}
|
|
|
|
|
|
do { ^$installer_bin --headless --mode $mode --platform $resolved_platform --yes } | complete | ignore
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if $just_available {
|
|
|
|
|
|
print "No installer binary or source found — delegating to: just install"
|
|
|
|
|
|
if $dry_run {
|
|
|
|
|
|
print $"[dry-run] would run: just install mode=($mode)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let r = do { ^just install $"mode=($mode)" } | complete
|
|
|
|
|
|
if $r.exit_code != 0 {
|
|
|
|
|
|
error make { msg: $"just install failed:\n($r.stderr)" }
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
print "installer not found and 'just' is not available."
|
|
|
|
|
|
print $"Build the installer first: cargo build --release --manifest-path ($installer_src)/Cargo.toml"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── ops (ADR-037: NATS ops contract) ────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
def workspace-id []: nothing -> string {
|
|
|
|
|
|
let card = load-card
|
|
|
|
|
|
if ($card | is-empty) { "unknown" } else { $card.id }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def nats-available []: nothing -> bool {
|
|
|
|
|
|
(do { ^which nats } | complete | get exit_code) == 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def keeper-cli-available []: nothing -> bool {
|
|
|
|
|
|
(do { ^which keeper-cli } | complete | get exit_code) == 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def rad-available []: nothing -> bool {
|
|
|
|
|
|
(do { ^which rad } | complete | get exit_code) == 0
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "ops list" []: nothing -> nothing {
|
|
|
|
|
|
let ws = workspace-id
|
|
|
|
|
|
if not (nats-available) {
|
|
|
|
|
|
print "nats CLI not found — install nats-io/natscli"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let stream = $"OPS_PENDING_(($ws | str upcase))"
|
|
|
|
|
|
let r = do { ^nats stream info $stream --json } | complete
|
|
|
|
|
|
if $r.exit_code != 0 {
|
|
|
|
|
|
print $"Stream ($stream) not found or NATS unreachable: ($r.stderr | str trim)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let info = $r.stdout | from json
|
|
|
|
|
|
print $"stream: ($stream)"
|
|
|
|
|
|
print $"messages: ($info.state.messages)"
|
|
|
|
|
|
print $"first_seq: ($info.state.first_seq)"
|
|
|
|
|
|
print $"last_seq: ($info.state.last_seq)"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "ops describe" [id: string]: nothing -> nothing {
|
|
|
|
|
|
let ws = workspace-id
|
|
|
|
|
|
if not (nats-available) { print "nats CLI not found"; return }
|
|
|
|
|
|
let subject = $"ops.pending.($ws).>"
|
|
|
|
|
|
let r = do { ^nats req $subject "" --count 50 --json } | complete
|
|
|
|
|
|
if $r.exit_code != 0 { print $"NATS request failed: ($r.stderr | str trim)"; return }
|
|
|
|
|
|
let msgs = $r.stdout | lines | each { |l| $l | from json | get data? | default {} }
|
|
|
|
|
|
let found = $msgs | where { |m| ($m.jti? | default "") == $id }
|
|
|
|
|
|
if ($found | is-empty) { print $"Op not found: ($id)"; return }
|
|
|
|
|
|
let op = $found | first
|
|
|
|
|
|
print $"jti: ($op.jti)"
|
|
|
|
|
|
print $"op_type: ($op.op_type? | default 'unknown')"
|
|
|
|
|
|
print $"target: ($op.target? | default 'unknown')"
|
|
|
|
|
|
print $"expected_version: ($op.expected_state_version? | default 'none')"
|
|
|
|
|
|
print $"scopes: ($op.scopes? | default [] | str join ', ')"
|
|
|
|
|
|
print $"issued_at: ($op.iat? | default 'unknown')"
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "ops sign" [id: string]: nothing -> nothing {
|
|
|
|
|
|
if not (keeper-cli-available) { print "keeper-cli not found — build from platform/crates/ops-keeper"; return }
|
|
|
|
|
|
let ws = workspace-id
|
|
|
|
|
|
let r = do { ^keeper-cli --workspace $ws sign $id } | complete
|
|
|
|
|
|
if $r.exit_code != 0 {
|
|
|
|
|
|
error make { msg: $"keeper-cli sign failed: ($r.stderr | str trim)" }
|
|
|
|
|
|
}
|
|
|
|
|
|
print $r.stdout
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "ops history" [--workspace: string = ""]: nothing -> nothing {
|
|
|
|
|
|
let ws = if ($workspace | is-empty) { workspace-id } else { $workspace }
|
|
|
|
|
|
let repo_path = $env.HOME | path join ".local/share/radicle/repos" $"state-($ws)"
|
|
|
|
|
|
if not ($repo_path | path exists) {
|
|
|
|
|
|
print $"Radicle state repo not found at ($repo_path)"
|
|
|
|
|
|
print "Run: rad clone rad:<rid> state-($ws)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let r = do { ^git -C $repo_path log --oneline --no-decorate -20 } | complete
|
|
|
|
|
|
if $r.exit_code != 0 { print $"git log failed: ($r.stderr | str trim)"; return }
|
|
|
|
|
|
$r.stdout | lines | each { |l|
|
|
|
|
|
|
let parts = $l | split row " " | enumerate
|
|
|
|
|
|
let hash = $parts | where index == 0 | get item.0
|
|
|
|
|
|
let msg = $parts | skip 1 | get item | str join " "
|
|
|
|
|
|
{ commit: $hash, message: $msg }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── playbook (extensions/playbooks/) ────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
def playbooks-root []: nothing -> string {
|
|
|
|
|
|
let root = project-root
|
|
|
|
|
|
[$root, "..", "..", "provisioning", "extensions", "playbooks"] | path join | path expand
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "playbook list" []: nothing -> nothing {
|
|
|
|
|
|
let root = playbooks-root
|
|
|
|
|
|
if not ($root | path exists) { print "No extensions/playbooks/ directory found."; return }
|
|
|
|
|
|
^ls $root | where type == dir | get name | each { |d|
|
|
|
|
|
|
let playbook_path = [$d, "playbook.ncl"] | path join
|
|
|
|
|
|
let has_run = ([$d, "run.nu"] | path join | path exists)
|
|
|
|
|
|
{ name: ($d | path basename), has_run: $has_run, has_playbook: ($playbook_path | path exists) }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "playbook describe" [name: string]: nothing -> nothing {
|
|
|
|
|
|
let root = playbooks-root
|
|
|
|
|
|
let playbook_path = [$root, $name, "playbook.ncl"] | path join
|
|
|
|
|
|
if not ($playbook_path | path exists) {
|
|
|
|
|
|
print $"Playbook not found: ($name)"
|
|
|
|
|
|
print $"Expected at: ($playbook_path)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let r = do { ^nickel export $playbook_path } | complete
|
|
|
|
|
|
if $r.exit_code != 0 { print $"Failed to load playbook: ($r.stderr | str trim)"; return }
|
|
|
|
|
|
let p = $r.stdout | from json
|
|
|
|
|
|
print $"name: ($p.name)"
|
|
|
|
|
|
print $"description: ($p.description)"
|
|
|
|
|
|
print $"version: ($p.version)"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "preconditions:"
|
|
|
|
|
|
$p.preconditions? | default [] | each { |c| print $" - ($c)" }
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "steps:"
|
|
|
|
|
|
$p.steps? | default [] | enumerate | each { |s|
|
|
|
|
|
|
print $" ($s.index + 1). ($s.item.id): ($s.item.description)"
|
|
|
|
|
|
}
|
|
|
|
|
|
if ($p.rollback_strategy? | default "none") != "none" {
|
|
|
|
|
|
print $"\nrollback: ($p.rollback_strategy)"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "playbook run" [name: string, --dry-run]: nothing -> nothing {
|
|
|
|
|
|
let root = playbooks-root
|
|
|
|
|
|
let run_path = [$root, $name, "run.nu"] | path join
|
|
|
|
|
|
if not ($run_path | path exists) {
|
|
|
|
|
|
print $"run.nu not found for playbook: ($name)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let ws = workspace-id
|
|
|
|
|
|
if $dry_run {
|
|
|
|
|
|
let dry_path = [$root, $name, "tests", "dry_run.nu"] | path join
|
|
|
|
|
|
if ($dry_path | path exists) {
|
|
|
|
|
|
let r = do { ^nu $dry_path --workspace $ws } | complete
|
|
|
|
|
|
if $r.exit_code != 0 { error make { msg: $"dry-run failed: ($r.stderr | str trim)" } }
|
|
|
|
|
|
print $r.stdout
|
|
|
|
|
|
} else {
|
|
|
|
|
|
print $"[dry-run] would execute: nu ($run_path) --workspace ($ws)"
|
|
|
|
|
|
print "No dry_run.nu found — simulating step listing only."
|
|
|
|
|
|
playbook describe $name
|
|
|
|
|
|
}
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let r = do { ^nu $run_path --workspace $ws } | complete
|
|
|
|
|
|
if $r.exit_code != 0 {
|
|
|
|
|
|
error make { msg: $"playbook run failed: ($r.stderr | str trim)" }
|
|
|
|
|
|
}
|
|
|
|
|
|
print $r.stdout
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "playbook history" []: nothing -> nothing {
|
|
|
|
|
|
let ws = workspace-id
|
|
|
|
|
|
let repo_path = $env.HOME | path join ".local/share/radicle/repos" $"state-($ws)"
|
|
|
|
|
|
if not ($repo_path | path exists) {
|
|
|
|
|
|
print $"Radicle state repo not found at ($repo_path)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let r = do { ^git -C $repo_path log --oneline --no-decorate --grep="playbook:" -20 } | complete
|
|
|
|
|
|
if $r.exit_code != 0 { print $"git log failed: ($r.stderr | str trim)"; return }
|
|
|
|
|
|
if ($r.stdout | is-empty) { print "No playbook audit entries found."; return }
|
|
|
|
|
|
$r.stdout | lines | each { |l|
|
|
|
|
|
|
let parts = $l | split row " " | enumerate
|
|
|
|
|
|
let hash = $parts | where index == 0 | get item.0
|
|
|
|
|
|
let msg = $parts | skip 1 | get item | str join " "
|
|
|
|
|
|
{ commit: $hash, message: $msg }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── keeper (ADR-037 dual-mode signing) ──────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
export def "keeper status" []: nothing -> nothing {
|
|
|
|
|
|
let ws = workspace-id
|
|
|
|
|
|
if not (keeper-cli-available) { print "keeper-cli not found"; return }
|
|
|
|
|
|
let r = do { ^keeper-cli --workspace $ws status } | complete
|
|
|
|
|
|
if $r.exit_code != 0 {
|
|
|
|
|
|
print $"keeper-cli unavailable: ($r.stderr | str trim)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
print $r.stdout
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "keeper policy" []: nothing -> nothing {
|
|
|
|
|
|
let ws = workspace-id
|
|
|
|
|
|
let policy_repo = $env.HOME | path join ".local/share/radicle/repos" $"policy-($ws)"
|
|
|
|
|
|
if not ($policy_repo | path exists) {
|
|
|
|
|
|
print $"Policy repo not cloned locally: policy-($ws)"
|
|
|
|
|
|
print "Run: rad clone rad:<rid> policy-($ws)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let policy_path = [$policy_repo, "policy.ncl"] | path join
|
|
|
|
|
|
if not ($policy_path | path exists) { print "policy.ncl not found in policy repo"; return }
|
|
|
|
|
|
let r = do { ^nickel export $policy_path } | complete
|
|
|
|
|
|
if $r.exit_code != 0 { print $"Failed to load policy: ($r.stderr | str trim)"; return }
|
|
|
|
|
|
let p = $r.stdout | from json
|
|
|
|
|
|
print $"workspace: ($p.workspace)"
|
|
|
|
|
|
print $"version: ($p.version)"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "auto_sign rules:"
|
|
|
|
|
|
$p.auto_sign? | default [] | each { |rule|
|
|
|
|
|
|
print $" op_type=($rule.op_type) target=($rule.target? | default '*') scope=($rule.scope? | default 'any')"
|
|
|
|
|
|
}
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "require_manual rules:"
|
|
|
|
|
|
$p.require_manual? | default [] | each { |rule|
|
|
|
|
|
|
print $" op_type=($rule.op_type) target=($rule.target? | default '*')"
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "keeper switch" [mode: string]: nothing -> nothing {
|
|
|
|
|
|
let valid_modes = ["auto", "operator-only"]
|
|
|
|
|
|
if not ($valid_modes | any { |m| $m == $mode }) {
|
|
|
|
|
|
error make { msg: $"Invalid mode '($mode)'. Valid modes: ($valid_modes | str join ', ')" }
|
|
|
|
|
|
}
|
|
|
|
|
|
let playbook = if $mode == "auto" { "switch_to_vm_ops" } else { "switch_to_operator_only" }
|
|
|
|
|
|
print $"Delegating to playbook: ($playbook)"
|
|
|
|
|
|
playbook run $playbook
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
# ─── governance (ADR-038 Radicle delegation) ─────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
export def "governance delegations" []: nothing -> nothing {
|
|
|
|
|
|
let ws = workspace-id
|
|
|
|
|
|
let repos = ["policy", "desired", "state"] | each { |r| $"($r)-($ws)" }
|
|
|
|
|
|
$repos | each { |repo_name|
|
|
|
|
|
|
let r = do { ^rad id --repo $repo_name --json } | complete
|
|
|
|
|
|
if $r.exit_code != 0 {
|
|
|
|
|
|
{ repo: $repo_name, error: ($r.stderr | str trim), delegates: [] }
|
|
|
|
|
|
} else {
|
|
|
|
|
|
let info = $r.stdout | from json
|
|
|
|
|
|
{ repo: $repo_name, threshold: ($info.threshold? | default 1), delegates: ($info.delegates? | default []) }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "governance signers" []: nothing -> nothing {
|
|
|
|
|
|
let ws = workspace-id
|
|
|
|
|
|
if not (nats-available) { print "nats CLI not found"; return }
|
|
|
|
|
|
let r = do { ^nats auth account ls --json } | complete
|
|
|
|
|
|
if $r.exit_code != 0 {
|
|
|
|
|
|
print $"NATS auth query failed: ($r.stderr | str trim)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let accounts = $r.stdout | from json
|
|
|
|
|
|
let ops_accounts = $accounts | where { |a| ($a.name? | default "") | str contains $ws }
|
|
|
|
|
|
if ($ops_accounts | is-empty) { print $"No NATS accounts found for workspace: ($ws)"; return }
|
|
|
|
|
|
$ops_accounts | each { |a|
|
|
|
|
|
|
{ account: $a.name, subject: ($a.subject? | default ""), signers: ($a.signing_keys? | default []) }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat: domain extension system, VCS abstraction, personal/provisioning domains, web subpages
Domain extension system (ADR-012): bash-layer dispatch activates repo_kind-conditional CLI
domains. install.nu copies domains/ tree; short_alias wrappers generated (personal, prov).
ore help and describe capabilities domain-aware.
personal domain (PersonalOntology): career skills/talks/publications/positioning, CFP
pipeline (Watching→Delivered), opportunities lifecycle, content pipeline, Sessionize
integration. Daemon pages: /career, /personal.
provisioning domain (DevWorkspace/Mixed): FSM state, next transitions, connections graph,
gates, workspace card, capabilities, backlog. Daemon page: /provisioning.
VCS abstraction layer (ADR-013): reflection/modules/vcs.nu — uniform jj/git API via
filesystem detection (.jj/ vs .git/). opmode.nu and git-event.nu migrated off ^git.
reflection/bin/jjw.nu — jj + ontoref + Radicle agent workspace lifecycle. jjw-ncl-merge.nu
registered as jj merge tool for .ontology/ NCL conflicts. init-repo.nu for new_project mode.
jj/rad not in ontoref requirements — belong in orchestration project manifests.
'Framework RepoKind: ontology/schemas/manifest.ncl gains 'Framework variant; ontoref
self-identifies as framework — no domain activates for the protocol itself.
Web presence: personal.html and provisioning.html domain subpages. index.html gains
"Project Types — Domain Extensions" section with type cards and subpage links. Nav
compacted (Arch/Prov labels, solid backdrop-filter background).
on+re: vcs-abstraction (adrs: adr-013) and agent-workspace-orchestration Practice nodes;
21 manifest capabilities; state.ncl catalysts updated.
2026-04-07 23:08:29 +01:00
|
|
|
|
# ─── help + main ──────────────────────────────────────────────────────────────
|
|
|
|
|
|
|
feat: #[onto_mcp_tool] catalog, OCI credential vault layer, validate ADR-018 mode hierarchy
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).
2026-05-12 04:46:15 +01:00
|
|
|
|
# ─── registry (i sub-domain) ──────────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
const DEFAULT_REGISTRY = "reg.librecloud.online"
|
|
|
|
|
|
|
|
|
|
|
|
def _find-capabilities-ncl []: nothing -> string {
|
|
|
|
|
|
let ws_path = ($env | get -o PROVISIONING_WORKSPACE_PATH | default "")
|
|
|
|
|
|
if ($ws_path | is-not-empty) {
|
|
|
|
|
|
let candidates = (do { glob $"($ws_path)/infra/*/capabilities.ncl" } | default [])
|
|
|
|
|
|
if ($candidates | is-not-empty) { return ($candidates | first) }
|
|
|
|
|
|
}
|
|
|
|
|
|
mut dir = $env.PWD
|
|
|
|
|
|
for _ in 0..6 {
|
|
|
|
|
|
let cur = $dir # immutable copy for closure capture in glob
|
|
|
|
|
|
let candidates = (do { glob $"($cur)/infra/*/capabilities.ncl" } | default [])
|
|
|
|
|
|
if ($candidates | is-not-empty) { return ($candidates | first) }
|
|
|
|
|
|
let parent = ($dir | path dirname)
|
|
|
|
|
|
if $parent == $dir { break }
|
|
|
|
|
|
$dir = $parent
|
|
|
|
|
|
}
|
|
|
|
|
|
""
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "i resolve-registry" []: nothing -> string {
|
|
|
|
|
|
let from_env = ($env | get -o PROVISIONING_REGISTRY | default "")
|
|
|
|
|
|
if ($from_env | is-not-empty) { return $from_env }
|
|
|
|
|
|
let caps = (_find-capabilities-ncl)
|
|
|
|
|
|
if ($caps | is-not-empty) {
|
|
|
|
|
|
let ip = ($env.NICKEL_IMPORT_PATH? | default ($env.PROVISIONING? | default ""))
|
|
|
|
|
|
let ncl = (do { ^nickel export --import-path $ip $caps } | complete)
|
|
|
|
|
|
if $ncl.exit_code == 0 {
|
|
|
|
|
|
let data = ($ncl.stdout | from json)
|
|
|
|
|
|
let reg_default = ($data | get -o provides.registries.default | default "")
|
|
|
|
|
|
let registries = ($data | get -o provides.registries.registries | default [])
|
|
|
|
|
|
if ($reg_default | is-not-empty) and ($registries | is-not-empty) {
|
|
|
|
|
|
let entry = ($registries | where { |e| $e.id == $reg_default } | first | default null)
|
|
|
|
|
|
if ($entry != null) and ($entry.endpoint? | default "" | is-not-empty) {
|
|
|
|
|
|
return $entry.endpoint
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
$DEFAULT_REGISTRY
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
export def "i list" [--live]: nothing -> nothing {
|
|
|
|
|
|
let reg = (i resolve-registry)
|
|
|
|
|
|
if not $live {
|
|
|
|
|
|
print $"registry : ($reg)"
|
|
|
|
|
|
print "Use --live to query the live catalog."
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let url = $"https://($reg)/v2/_catalog"
|
|
|
|
|
|
let body = try { http get $url } catch {
|
|
|
|
|
|
print $"Registry catalog unavailable at ($url)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
let repos = ($body | get -o repositories | default [])
|
|
|
|
|
|
|
|
|
|
|
|
let domains = ($repos | where { |r| $r | str starts-with "domains/" } | each { |r|
|
|
|
|
|
|
let parts = ($r | str replace "domains/" "" | split row "/")
|
|
|
|
|
|
{ kind: "domain", participant: ($parts | first), id: ($parts | skip 1 | str join "/"), ref: $"($reg)/($r)" }
|
|
|
|
|
|
})
|
|
|
|
|
|
let modes = ($repos | where { |r| $r | str starts-with "modes/" } | each { |r|
|
|
|
|
|
|
let parts = ($r | str replace "modes/" "" | split row "/")
|
|
|
|
|
|
{ kind: "mode", participant: ($parts | first), id: ($parts | skip 1 | str join "/"), ref: $"($reg)/($r)" }
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
let all = ($domains | append $modes)
|
|
|
|
|
|
if ($all | is-empty) {
|
|
|
|
|
|
print $"No domains/ or modes/ artifacts found in ($reg)"
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
print $"registry: ($reg) artifacts: ($all | length)"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
$all | each { |a|
|
|
|
|
|
|
print $" ($a.kind) ($a.participant)/($a.id) → ($a.ref)"
|
|
|
|
|
|
}
|
|
|
|
|
|
null
|
|
|
|
|
|
}
|
|
|
|
|
|
|
feat: domain extension system, VCS abstraction, personal/provisioning domains, web subpages
Domain extension system (ADR-012): bash-layer dispatch activates repo_kind-conditional CLI
domains. install.nu copies domains/ tree; short_alias wrappers generated (personal, prov).
ore help and describe capabilities domain-aware.
personal domain (PersonalOntology): career skills/talks/publications/positioning, CFP
pipeline (Watching→Delivered), opportunities lifecycle, content pipeline, Sessionize
integration. Daemon pages: /career, /personal.
provisioning domain (DevWorkspace/Mixed): FSM state, next transitions, connections graph,
gates, workspace card, capabilities, backlog. Daemon page: /provisioning.
VCS abstraction layer (ADR-013): reflection/modules/vcs.nu — uniform jj/git API via
filesystem detection (.jj/ vs .git/). opmode.nu and git-event.nu migrated off ^git.
reflection/bin/jjw.nu — jj + ontoref + Radicle agent workspace lifecycle. jjw-ncl-merge.nu
registered as jj merge tool for .ontology/ NCL conflicts. init-repo.nu for new_project mode.
jj/rad not in ontoref requirements — belong in orchestration project manifests.
'Framework RepoKind: ontology/schemas/manifest.ncl gains 'Framework variant; ontoref
self-identifies as framework — no domain activates for the protocol itself.
Web presence: personal.html and provisioning.html domain subpages. index.html gains
"Project Types — Domain Extensions" section with type cards and subpage links. Nav
compacted (Arch/Prov labels, solid backdrop-filter background).
on+re: vcs-abstraction (adrs: adr-013) and agent-workspace-orchestration Practice nodes;
21 manifest capabilities; state.ncl catalysts updated.
2026-04-07 23:08:29 +01:00
|
|
|
|
def show-help [] {
|
|
|
|
|
|
print "Provisioning — ontoref domain extension"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "USAGE"
|
|
|
|
|
|
print " ore provisioning <command> [args]"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "COMMANDS (all repo_kinds)"
|
|
|
|
|
|
print " state Current FSM position across all dimensions"
|
|
|
|
|
|
print " next Next valid transitions with blockers/catalysts"
|
|
|
|
|
|
print " validate <decision> Check against ontological invariants"
|
|
|
|
|
|
print " connections Upstream/downstream project dependency graph"
|
|
|
|
|
|
print " gates Membrane status and opening conditions"
|
|
|
|
|
|
print " capabilities Platform capabilities from manifest"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "COMMANDS (DevWorkspace only)"
|
|
|
|
|
|
print " card Workspace card: identity, clusters, status"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "COMMANDS (Mixed/platform only)"
|
|
|
|
|
|
print " backlog [--priority] Backlog items filtered by High|Medium|Low"
|
|
|
|
|
|
print " backlog show <id> Full detail of a backlog item"
|
feat: #[onto_mcp_tool] catalog, OCI credential vault layer, validate ADR-018 mode hierarchy
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).
2026-05-12 04:46:15 +01:00
|
|
|
|
print " install [--mode] [--platform] Install provisioning platform services"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "COMMANDS (DevWorkspace — ops contract, ADR-037)"
|
|
|
|
|
|
print " ops list Pending ops queue depth for this workspace"
|
|
|
|
|
|
print " ops describe <id> Full op detail: JWT claims, scopes, expected_version"
|
|
|
|
|
|
print " ops sign <id> Operator signs a pending op via keeper-cli"
|
|
|
|
|
|
print " ops history [<workspace>] Applied ops from <workspace>-state Radicle ledger"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "COMMANDS (DevWorkspace — playbooks)"
|
|
|
|
|
|
print " playbook list Available playbooks for this workspace"
|
|
|
|
|
|
print " playbook describe <name> Steps, params, preconditions of a playbook"
|
|
|
|
|
|
print " playbook run <name> Execute a playbook (use --dry-run first)"
|
|
|
|
|
|
print " playbook history Past playbook executions from audit ledger"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "COMMANDS (DevWorkspace — keeper daemon, ADR-037)"
|
|
|
|
|
|
print " keeper status Keeper mode (auto|operator-only|down) + policy version"
|
|
|
|
|
|
print " keeper policy Active keeper policy from policy-<workspace> Radicle repo"
|
|
|
|
|
|
print " keeper switch <mode> Switch keeper mode (delegates to switch_to_<mode> playbook)"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "COMMANDS (DevWorkspace — governance, ADR-038)"
|
|
|
|
|
|
print " governance delegations Radicle delegation sets for policy/desired/state repos"
|
|
|
|
|
|
print " governance signers Active NATS JWT signers and M-of-N quorum status"
|
|
|
|
|
|
print ""
|
|
|
|
|
|
print "COMMANDS (all repo_kinds — registry)"
|
|
|
|
|
|
print " i resolve-registry Resolved OCI registry endpoint (env → capabilities.ncl → default)"
|
|
|
|
|
|
print " i list Show resolved registry endpoint"
|
|
|
|
|
|
print " i list --live Query _catalog and list live domains/ and modes/ artifacts"
|
feat: domain extension system, VCS abstraction, personal/provisioning domains, web subpages
Domain extension system (ADR-012): bash-layer dispatch activates repo_kind-conditional CLI
domains. install.nu copies domains/ tree; short_alias wrappers generated (personal, prov).
ore help and describe capabilities domain-aware.
personal domain (PersonalOntology): career skills/talks/publications/positioning, CFP
pipeline (Watching→Delivered), opportunities lifecycle, content pipeline, Sessionize
integration. Daemon pages: /career, /personal.
provisioning domain (DevWorkspace/Mixed): FSM state, next transitions, connections graph,
gates, workspace card, capabilities, backlog. Daemon page: /provisioning.
VCS abstraction layer (ADR-013): reflection/modules/vcs.nu — uniform jj/git API via
filesystem detection (.jj/ vs .git/). opmode.nu and git-event.nu migrated off ^git.
reflection/bin/jjw.nu — jj + ontoref + Radicle agent workspace lifecycle. jjw-ncl-merge.nu
registered as jj merge tool for .ontology/ NCL conflicts. init-repo.nu for new_project mode.
jj/rad not in ontoref requirements — belong in orchestration project manifests.
'Framework RepoKind: ontology/schemas/manifest.ncl gains 'Framework variant; ontoref
self-identifies as framework — no domain activates for the protocol itself.
Web presence: personal.html and provisioning.html domain subpages. index.html gains
"Project Types — Domain Extensions" section with type cards and subpage links. Nav
compacted (Arch/Prov labels, solid backdrop-filter background).
on+re: vcs-abstraction (adrs: adr-013) and agent-workspace-orchestration Practice nodes;
21 manifest capabilities; state.ncl catalysts updated.
2026-04-07 23:08:29 +01:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def main [
|
|
|
|
|
|
...args: string
|
|
|
|
|
|
--priority: string = ""
|
feat: #[onto_mcp_tool] catalog, OCI credential vault layer, validate ADR-018 mode hierarchy
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).
2026-05-12 04:46:15 +01:00
|
|
|
|
--mode: string = "solo"
|
|
|
|
|
|
--platform: string = ""
|
|
|
|
|
|
--dry-run
|
|
|
|
|
|
--live
|
feat: domain extension system, VCS abstraction, personal/provisioning domains, web subpages
Domain extension system (ADR-012): bash-layer dispatch activates repo_kind-conditional CLI
domains. install.nu copies domains/ tree; short_alias wrappers generated (personal, prov).
ore help and describe capabilities domain-aware.
personal domain (PersonalOntology): career skills/talks/publications/positioning, CFP
pipeline (Watching→Delivered), opportunities lifecycle, content pipeline, Sessionize
integration. Daemon pages: /career, /personal.
provisioning domain (DevWorkspace/Mixed): FSM state, next transitions, connections graph,
gates, workspace card, capabilities, backlog. Daemon page: /provisioning.
VCS abstraction layer (ADR-013): reflection/modules/vcs.nu — uniform jj/git API via
filesystem detection (.jj/ vs .git/). opmode.nu and git-event.nu migrated off ^git.
reflection/bin/jjw.nu — jj + ontoref + Radicle agent workspace lifecycle. jjw-ncl-merge.nu
registered as jj merge tool for .ontology/ NCL conflicts. init-repo.nu for new_project mode.
jj/rad not in ontoref requirements — belong in orchestration project manifests.
'Framework RepoKind: ontology/schemas/manifest.ncl gains 'Framework variant; ontoref
self-identifies as framework — no domain activates for the protocol itself.
Web presence: personal.html and provisioning.html domain subpages. index.html gains
"Project Types — Domain Extensions" section with type cards and subpage links. Nav
compacted (Arch/Prov labels, solid backdrop-filter background).
on+re: vcs-abstraction (adrs: adr-013) and agent-workspace-orchestration Practice nodes;
21 manifest capabilities; state.ncl catalysts updated.
2026-04-07 23:08:29 +01:00
|
|
|
|
] {
|
|
|
|
|
|
if ($args | is-empty) or ($args | first) == "help" { show-help; return }
|
|
|
|
|
|
let sub = ($args | str join " ")
|
|
|
|
|
|
match $sub {
|
|
|
|
|
|
"state" => { state }
|
|
|
|
|
|
"next" => { next }
|
|
|
|
|
|
"connections" => { connections }
|
|
|
|
|
|
"gates" => { gates }
|
|
|
|
|
|
"card" => { card }
|
|
|
|
|
|
"capabilities" => { capabilities }
|
feat: #[onto_mcp_tool] catalog, OCI credential vault layer, validate ADR-018 mode hierarchy
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).
2026-05-12 04:46:15 +01:00
|
|
|
|
"install" => { if $dry_run { install --mode $mode --platform $platform --dry-run } else { install --mode $mode --platform $platform } }
|
feat: domain extension system, VCS abstraction, personal/provisioning domains, web subpages
Domain extension system (ADR-012): bash-layer dispatch activates repo_kind-conditional CLI
domains. install.nu copies domains/ tree; short_alias wrappers generated (personal, prov).
ore help and describe capabilities domain-aware.
personal domain (PersonalOntology): career skills/talks/publications/positioning, CFP
pipeline (Watching→Delivered), opportunities lifecycle, content pipeline, Sessionize
integration. Daemon pages: /career, /personal.
provisioning domain (DevWorkspace/Mixed): FSM state, next transitions, connections graph,
gates, workspace card, capabilities, backlog. Daemon page: /provisioning.
VCS abstraction layer (ADR-013): reflection/modules/vcs.nu — uniform jj/git API via
filesystem detection (.jj/ vs .git/). opmode.nu and git-event.nu migrated off ^git.
reflection/bin/jjw.nu — jj + ontoref + Radicle agent workspace lifecycle. jjw-ncl-merge.nu
registered as jj merge tool for .ontology/ NCL conflicts. init-repo.nu for new_project mode.
jj/rad not in ontoref requirements — belong in orchestration project manifests.
'Framework RepoKind: ontology/schemas/manifest.ncl gains 'Framework variant; ontoref
self-identifies as framework — no domain activates for the protocol itself.
Web presence: personal.html and provisioning.html domain subpages. index.html gains
"Project Types — Domain Extensions" section with type cards and subpage links. Nav
compacted (Arch/Prov labels, solid backdrop-filter background).
on+re: vcs-abstraction (adrs: adr-013) and agent-workspace-orchestration Practice nodes;
21 manifest capabilities; state.ncl catalysts updated.
2026-04-07 23:08:29 +01:00
|
|
|
|
"backlog" => { backlog --priority $priority }
|
feat: #[onto_mcp_tool] catalog, OCI credential vault layer, validate ADR-018 mode hierarchy
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).
2026-05-12 04:46:15 +01:00
|
|
|
|
"ops list" => { ops list }
|
|
|
|
|
|
"ops history" => { ops history }
|
|
|
|
|
|
"keeper status" => { keeper status }
|
|
|
|
|
|
"keeper policy" => { keeper policy }
|
|
|
|
|
|
"governance delegations" => { governance delegations }
|
|
|
|
|
|
"governance signers" => { governance signers }
|
|
|
|
|
|
"playbook list" => { playbook list }
|
|
|
|
|
|
"playbook history" => { playbook history }
|
|
|
|
|
|
_ if ($sub | str starts-with "backlog show ") => { backlog show ($args | get 2) }
|
|
|
|
|
|
_ if ($sub | str starts-with "validate ") => { validate ($args | skip 1 | str join " ") }
|
|
|
|
|
|
_ if ($sub | str starts-with "ops describe ") => { ops describe ($args | get 2) }
|
|
|
|
|
|
_ if ($sub | str starts-with "ops sign ") => { ops sign ($args | get 2) }
|
|
|
|
|
|
_ if ($sub | str starts-with "playbook describe ") => { playbook describe ($args | get 2) }
|
|
|
|
|
|
_ if ($sub | str starts-with "playbook run ") => {
|
|
|
|
|
|
if $dry_run { playbook run ($args | get 2) --dry-run } else { playbook run ($args | get 2) }
|
|
|
|
|
|
}
|
|
|
|
|
|
_ if ($sub | str starts-with "keeper switch ") => { keeper switch ($args | get 2) }
|
|
|
|
|
|
_ if ($sub | str starts-with "ops history ") => { ops history --workspace ($args | get 2) }
|
|
|
|
|
|
"i resolve-registry" => { i resolve-registry | print }
|
|
|
|
|
|
"i list" => { if $live { i list --live } else { i list } }
|
feat: domain extension system, VCS abstraction, personal/provisioning domains, web subpages
Domain extension system (ADR-012): bash-layer dispatch activates repo_kind-conditional CLI
domains. install.nu copies domains/ tree; short_alias wrappers generated (personal, prov).
ore help and describe capabilities domain-aware.
personal domain (PersonalOntology): career skills/talks/publications/positioning, CFP
pipeline (Watching→Delivered), opportunities lifecycle, content pipeline, Sessionize
integration. Daemon pages: /career, /personal.
provisioning domain (DevWorkspace/Mixed): FSM state, next transitions, connections graph,
gates, workspace card, capabilities, backlog. Daemon page: /provisioning.
VCS abstraction layer (ADR-013): reflection/modules/vcs.nu — uniform jj/git API via
filesystem detection (.jj/ vs .git/). opmode.nu and git-event.nu migrated off ^git.
reflection/bin/jjw.nu — jj + ontoref + Radicle agent workspace lifecycle. jjw-ncl-merge.nu
registered as jj merge tool for .ontology/ NCL conflicts. init-repo.nu for new_project mode.
jj/rad not in ontoref requirements — belong in orchestration project manifests.
'Framework RepoKind: ontology/schemas/manifest.ncl gains 'Framework variant; ontoref
self-identifies as framework — no domain activates for the protocol itself.
Web presence: personal.html and provisioning.html domain subpages. index.html gains
"Project Types — Domain Extensions" section with type cards and subpage links. Nav
compacted (Arch/Prov labels, solid backdrop-filter background).
on+re: vcs-abstraction (adrs: adr-013) and agent-workspace-orchestration Practice nodes;
21 manifest capabilities; state.ncl catalysts updated.
2026-04-07 23:08:29 +01:00
|
|
|
|
_ => { print $"Unknown command: ($sub)"; show-help }
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|