docs: reshape runbooks into .agents/skills/<name>/SKILL.md (phase 4)

Problem: runbooks are agent-executable procedures but lived at the repo root,
separate from the other agent instruction now under .agents/.

Change:
- Move runbooks/<name>.md -> .agents/skills/<name>/SKILL.md (folder per skill,
  matching the wiki-hq skills layout). Frontmatter (name, risk_class, inputs,
  verification, docs_update_checklist, transition) preserved.
- Rewrite links (inbound from plans; between-skill siblings) via the move map.
- Update prose references in AGENTS.md, HERMES.md, .agents/OIKOS.md, and the
  operations schema; fix a pre-existing stale link to operations/commands.md.

No code consumed runbooks/ by path, so nothing else changes.

Verification: all SKILL.md frontmatter parses with valid risk_class; every
lifecycle transition resolves to an oikos/ontology.yaml state; broken-link
count 127 -> 126 (fixed one, introduced none).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-06 14:39:31 +02:00
parent 8a6422bd7d
commit 5c5016b3c7
16 changed files with 23 additions and 22 deletions

View File

@@ -40,7 +40,7 @@ one pass through **Observe → Orient → Decide → Act**:
|---|---|---|
| Host / Service | topology entities | `inventory.yaml` (+ generated `hosts/*.yaml`) |
| Secret | SOPS+age encrypted value, per-client recipients | `secrets/` + `.sops.yaml` |
| Runbook | executable workflow with risk class + verification | `runbooks/` (Week 2) |
| Runbook | executable workflow with risk class + verification | `.agents/skills/<name>/SKILL.md` |
| Signal | something needing attention, with lifecycle | `signals/` ledger (Week 3) |
| Change | one mutation: who, what, risk, approval, verification | `ledger/` (Week 2) |
| Approval | short-TTL signed grant for a gated action | approval engine (Week 3) |

View File

@@ -20,8 +20,8 @@ versioned, reviewable, and reachable by MCP `get_page`/`search_docs` like any ot
## Runbooks
Repeatable procedures live in `runbooks/<name>.md` with YAML front-matter that the Oikos policy and
lifecycle machinery reads:
Repeatable procedures are skills — one folder per skill at `.agents/skills/<name>/SKILL.md`, with
YAML front-matter that the Oikos policy and lifecycle machinery reads:
```yaml
---

View File

@@ -11,12 +11,12 @@ docs_update_checklist: [hosts_narrative_page_if_lxc_or_vm]
Goal: bring a new host (workstation, LXC, VM) into inventory and the
secrets model, with mesh membership only where it's actually needed.
This wraps the existing `homelab client add` flow — see
[operations/agent-enrollment.md](../operations/agent-enrollment.md) for
[operations/agent-enrollment.md](../../../operations/agent-enrollment.md) for
the full walkthrough; this runbook is the risk/lifecycle framing.
1. On any enrolled client: `homelab client add <hostname>` — appends a
`hosts.<name>:` block to `inventory.yaml` (lifecycle `state: planned`
`provisioning`, per [oikos/ontology.yaml](../oikos/ontology.yaml)),
`provisioning`, per [oikos/ontology.yaml](../../../oikos/ontology.yaml)),
commits + pushes.
2. Netbird join is **optional, not a required step** — only needed for
hosts that must be reachable off-LAN (workstations that roam, e.g.

View File

@@ -18,10 +18,10 @@ own repo) and get it live, safely.
`oikos/policy.yaml`.
2. Clone/pull the `config_repo` (never edit the backend's working tree
directly — tracked configs change by commit + push, per
[OIKOS.md](../OIKOS.md) conventions).
[OIKOS.md](../../../OIKOS.md) conventions).
3. Make the change, commit, push to `main`.
4. The Gitea webhook fires the deploy pipeline for that repo (see
[infrastructure/auto-deploy.md](../knowledge/wiki/infrastructure/auto-deploy.md) for
[infrastructure/auto-deploy.md](../../../knowledge/wiki/infrastructure/auto-deploy.md) for
the exact receiver/reload for this service).
5. Run the preflight's verification command. If it fails, check
`homelab service <name> log` for the reload/restart error.

View File

@@ -9,13 +9,13 @@ transition: "provisioning -> active"
# Lifecycle: activate a node
Per [oikos/ontology.yaml](../oikos/ontology.yaml). Requires: age key
Per [oikos/ontology.yaml](../../../oikos/ontology.yaml). Requires: age key
enrolled if it needs secrets, mesh joined if it needs off-LAN reach,
ingress live if public, health check answering, doc page complete,
ledger entry.
1. If the node is a `homelab` client: finish enrollment per
[client-enrollment.md](client-enrollment.md) (`--finalize-pubkey`,
[client-enrollment.md](../client-enrollment/SKILL.md) (`--finalize-pubkey`,
mesh join, `homelab doctor` green).
2. If it hosts a public service: add the `services:` entry in
`inventory.yaml` (backend, url, doc_page, config_repo, risk_notes —

View File

@@ -9,7 +9,7 @@ transition: "active -> deprecated"
# Lifecycle: deprecate a node
Per [oikos/ontology.yaml](../oikos/ontology.yaml): a node keeps running
Per [oikos/ontology.yaml](../../../oikos/ontology.yaml): a node keeps running
but takes no new dependents. **Completion condition: zero remaining
inbound `depends-on`/`routes-to` edges** — this is a hard gate, not a
suggestion; `oikos/policy.yaml` `lifecycle_overrides.deprecated.refuse`
@@ -32,4 +32,4 @@ before proceeding — that's exactly the kind of drift the Week-3 detector
will catch automatically, but until then this manual check is the gate.
Next (once `affected_by` is empty):
[lifecycle-destroy-node.md](lifecycle-destroy-node.md).
[lifecycle-destroy-node.md](../lifecycle-destroy-node/SKILL.md).

View File

@@ -10,7 +10,7 @@ transition: "active -> migrating -> active"
# Lifecycle: migrate a node
Modeled on the strong Phase 1+2 migration
([plans/2026-06-03_110000-library-ssd-migration-to-ludo-mini.md](../plans/2026-06-03_110000-library-ssd-migration-to-ludo-mini.md)).
([plans/2026-06-03_110000-library-ssd-migration-to-ludo-mini.md](../../../plans/2026-06-03_110000-library-ssd-migration-to-ludo-mini.md)).
Requires (ontology): preflight + backup-verified before migrating;
post-verify + Caddy backends checked + mounts checked + docs updated
before returning to `active`.

View File

@@ -9,7 +9,7 @@ transition: "planned -> provisioning"
# Lifecycle: provision a node
Per [oikos/ontology.yaml](../oikos/ontology.yaml) `lifecycle.transitions`.
Per [oikos/ontology.yaml](../../../oikos/ontology.yaml) `lifecycle.transitions`.
Policy note: `provisioning` nodes get a lifecycle override —
`config_mutation` actions downgrade to `reversible_low` because nothing
depends on the node yet (see `oikos/policy.yaml` `lifecycle_overrides`).
@@ -30,4 +30,4 @@ chosen, doc page stub.
is enough to satisfy the transition requirement.
4. Reserve the IP in DNS/DHCP notes if it's a fixed LAN address.
Next: [lifecycle-activate-node.md](lifecycle-activate-node.md).
Next: [lifecycle-activate-node.md](../lifecycle-activate-node/SKILL.md).

View File

@@ -102,9 +102,9 @@ Then `systemctl status apt-recovery` from a fresh ssh to check progress.
## Related
- [Operations cheatsheet](commands.md)
- [Auto-deploy pipelines](../knowledge/wiki/infrastructure/auto-deploy.md)
- [Hubris host page](../knowledge/wiki/hosts/hubris.md)
- [Operations cheatsheet](../../../operations/commands.md)
- [Auto-deploy pipelines](../../../knowledge/wiki/infrastructure/auto-deploy.md)
- [Hubris host page](../../../knowledge/wiki/hosts/hubris.md)
## Changelog

View File

@@ -76,7 +76,8 @@ Grep is fine for browsing or when MCP is unreachable.
## 4. Wiki conventions
- Narrative pages live under `knowledge/wiki/{containers,hosts,vms,infrastructure}/`;
procedural pages under `investigations/`, `operations/`, `runbooks/`, `plans/`.
runbook procedures under `.agents/skills/<name>/SKILL.md`; other procedural
pages under `investigations/`, `operations/`, `plans/`.
Cross-link liberally; orphans are bugs.
- Every page ends with a `## Changelog` section, entries in reverse-chrono
order:

View File

@@ -19,8 +19,8 @@ When in doubt, check `/opt/homelab-context/` first.
For the canonical workflows (service health check, config change +
deploy, client enrollment, incident investigation, and each node
lifecycle transition), read the matching file in `runbooks/*.md` before
acting. Each runbook carries its risk class, required inputs, the
lifecycle transition), read the matching `.agents/skills/<name>/SKILL.md` before
acting. Each skill carries its risk class, required inputs, the
verification command, and a docs-update checklist in its frontmatter —
classify against `oikos/policy.yaml` using that risk class before any
mutation. Don't re-derive topology or the mutation path by grepping the

View File

@@ -42,7 +42,7 @@ is actually unused end-to-end.
## Provisioning steps (once pve_id is assigned)
Follow [runbooks/lifecycle-provision-node.md](../runbooks/lifecycle-provision-node.md):
Follow [lifecycle-provision-node](../.agents/skills/lifecycle-provision-node/SKILL.md):
1. `pct create <new-id> ...` on hubris — confirm the assigned ID doesn't
collide with 131 or anything else live.
@@ -53,7 +53,7 @@ Follow [runbooks/lifecycle-provision-node.md](../runbooks/lifecycle-provision-no
4. Point node_exporter at hubris + strong (either install locally on each,
or scrape via SSH-tunneled metrics — install locally is simpler and is
the standard approach).
5. Follow [runbooks/lifecycle-activate-node.md](../runbooks/lifecycle-activate-node.md)
5. Follow [lifecycle-activate-node](../.agents/skills/lifecycle-activate-node/SKILL.md)
to flip to `active`, complete the doc page, regenerate
`hosts/*.yaml` + `infrastructure/topology.md`.
6. Extend `oikos/scheduler.py`'s disk/temp probes to query Prometheus