---
name: lifecycle-activate-node
risk_class: config_mutation
inputs: [node_name]
verification: "MCP get_service_status (if it hosts a service); MCP whoami (if it's a client)"
docs_update_checklist: [doc_page_complete]
transition: "provisioning -> active"
---

# Lifecycle: activate a node

Per [seeds/ontology.yaml](../../../seeds/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 self-enrolls as a client: finish enrollment per
   [CLIENTS.md](../../../CLIENTS.md#enrollment) (`bootstrap.sh` →
   `/api/v1/clients/enroll`, mesh join, MCP `whoami` returns the entity).
2. If it hosts a public service: add the `services:` entry in
   `seeds/inventory.yaml` (backend, url, doc_page, config_repo,
   risk_notes) and wire the Caddy route in `dtoro/caddy-conf`.
3. Confirm the health check answers: MCP `get_service_status` or a
   direct `curl`.
4. Flip `state: provisioning` → `state: active` (or delete the `state:`
   field — `active` is the default) in `seeds/inventory.yaml`, then
   `oikos seed` to ingest.
5. Complete the doc page (stub → full narrative: role, specs, how it's
   configured, dependencies).
6. No manual record-keeping step needed — the activation (via whatever
   API call flipped the state) is recorded automatically in `audit_log`.

Regenerate: `oikos seed` re-ingests `seeds/inventory.yaml`; `oikos export`
writes DB state back out to the YAML if you mutated via the API/MCP
instead of editing the file directly.
