docs(R5): rewrite knowledge schema + llm-wiki for DB-native model; deprecate root inventory.yaml

Rewrote .agents/domains/knowledge/schema.md and .agents/shared/llm-wiki.md
which described the deleted Python substrate (bin/homelab, oikos/cards/,
oikos/ledger.py, root inventory.yaml, knowledge/sources/, get_page/
search_docs MCP tools). Now reflect ADR 0003: Postgres DB is the single
source of truth for structured data and narrative knowledge; seeds/*.yaml
are bootstrap+DR manifests (content-hashed via seed_versions); archive/
knowledge/ is the frozen legacy wiki; MCP search_knowledge/get_entity_
knowledge replace get_page/search_docs.

Swept substrate refs in .agents/shared/{writing-style,page-templates}.md
and .agents/domains/operations/schema.md: bare inventory.yaml ->
seeds/inventory.yaml; knowledge/sources/ -> archive/knowledge/sources/
(historical); get_changelog/oikos/ledger.py -> DB audit trail / structured
document changelog field; HERMES -> Nomos.

Root inventory.yaml (618-line Python-era file superseded 2026-07-07 by
seeds/inventory.yaml) replaced with a deprecation stub pointing to the seed
and DB. Kept as a stub rather than deleted because AGENTS.md §1/§2 still
point clients at /opt/homelab-context/inventory.yaml; full on-client path
reconciliation deferred to R13.

Flagged export gap: oikos export regenerates seeds/{ontology,inventory,
policy}.yaml but NOT seeds/knowledge.yaml — API-added knowledge lives only
in the DB until hand-edited into the seed.

VERSION 0.7.7 -> 0.7.8. Plan R5 marked done.
This commit is contained in:
2026-07-17 22:36:41 +02:00
parent d2950dd09d
commit a2410cf9c2
8 changed files with 175 additions and 702 deletions

View File

@@ -1,48 +1,93 @@
# Knowledge domain — schema
The knowledge domain is the durable, authoritative current-state documentation of the homelab: one
page per node and per cross-cutting system, synthesized from live state and evidence. It answers
"what exists and how does it work right now."
The knowledge domain is the durable, authoritative current-state documentation of the homelab:
narrative for every node and cross-cutting system, synthesized from live state and evidence. It
answers "what exists and how does it work right now."
It follows the [LLM Wiki layer model](../../shared/llm-wiki.md) and the
[writing-style](../../shared/writing-style.md) and [page-templates](../../shared/page-templates.md)
rules.
## The narrative / substrate split
## Source of truth — the database
The knowledge wiki is **narrative**. It sits alongside a **machine-readable substrate** that it
describes but never contains. The split is load-bearing: several programs read the substrate at
fixed paths, so the wiki reorganization never moves it.
Per ADR 0003, the Postgres database is the single source of truth for all structured data **and**
narrative knowledge. The narrative/substrate split of the Python era is gone: the DB holds both the
structured graph (entities, relationships, status, metrics) and the narrative layer (documents,
investigations, runbooks) in the `knowledge_entities` table.
| Layer | Location | Consumed by |
|-------|----------|-------------|
| Substrate — source of truth | `inventory.yaml` (root) | MCP server, `homelab` CLI, `oikos/` scheduler/drift/relations/gen-topology |
| Substrate — generated host records | `inventory.yaml` (root) | Go `internal/mcp/` server, `bin/homelab`; the single source of truth |
| Substrate — kernel + context cards | `oikos/` (code, `oikos/cards/`, `oikos/state.json`) | MCP `explain`, scheduler |
| Narrative — synthesized wiki | `archive/knowledge/{hosts,containers,vms,infrastructure}/` | humans, agents via MCP `get_page` / `search_docs` |
| Evidence — immutable sources | `knowledge/sources/` (references + investigations) | synthesis into wiki pages |
| Concern | Where it lives | How it gets there |
|---------|----------------|-------------------|
| Knowledge content — documents, investigations, runbooks | `knowledge_entities` table (rows linked to `entities` via `documents` / `about` edges) | Seeded from `seeds/knowledge.yaml` at deploy; mutated at runtime via the API |
| Seed manifest (bootstrap + DR) | `seeds/knowledge.yaml` | Hand-edited or regenerated; ingested idempotently (content-hashed via `seed_versions`) |
| Structured graph — hosts, services, entity types, relationships | `entities`, `relationships`, `entity_types` tables | Seeded from `seeds/{ontology,inventory}.yaml`; mutated via API/MCP |
| Archived narrative wiki (read-only history) | `archive/knowledge/` | Frozen 2026-07-07 when the DB became source of truth |
## Wiki pages
### Seed ingest
- **Node pages** (`archive/knowledge/containers/<id>-<name>.md`, `.../vms/<id>-<name>.md`,
`.../hosts/<name>.md`) follow the container/host template in
[page-templates.md](../../shared/page-templates.md): opening definition, `## At a glance`,
`## Role`, service/port map, storage, auto-deploy, `## Related`, `## Changelog`.
- **Cross-cutting pages** (`archive/knowledge/infrastructure/<topic>.md`) follow the cross-cutting
template: `## Why`, `## Components`, `## How to apply`, `## Gotchas`, `## Related`, `## Changelog`.
- Each `inventory.yaml` host entry carries a `doc_page:` field pointing at its narrative page.
Changing where a page lives means updating that field (read by `bin/homelab`).
`seeds/knowledge.yaml` has three top-level lists — `documents`, `investigations`, `runbooks` — each
entry carrying `slug`, `title`, `content` (markdown), and tags. `internal/knowledge/seed.go`
ingests each entry by:
1. `getOrCreateEntity` — ensures the slug exists in `entities` (type `document` / `investigation` /
`runbook`).
2. `upsertKnowledgeEntity` — writes the markdown body into `knowledge_entities`, keyed by
`content_hash` so re-ingest is a no-op when nothing changed.
3. `createEdge` — links the knowledge entity to its subject(s) via `documents` (for `document`) or
`about` (for `investigation`) edges. Runbooks bind to an `entity_type` via `applies_to_type`
rather than to a single entity.
### Runtime mutation
Agents register or update knowledge through the API, not by editing the seed:
- `POST /api/v1/knowledge/{entity_slug}` — upsert a document/investigation on an entity
(`upsert_knowledge` MCP tool).
- `update_entity_attributes` — merge a discovered fact (IP, version, port) into an entity.
- `create_relationship` — record a discovered edge (`depends-on`, `hosts`, `routes-to`).
> **Export gap.** `oikos export` regenerates `seeds/{ontology,inventory,policy}.yaml` from the DB
> for version control, but **not** `seeds/knowledge.yaml`. Knowledge added via the API today lives
> only in the DB until someone hand-edits the seed. Tracked as a follow-up.
## Knowledge kinds
- **Documents** (`document` entities, linked via `documents` edges) — node and cross-cutting
narrative pages. Carry `at_glance` (structured attributes) and a parsed `changelog`. Follow the
container / cross-cutting templates in [page-templates.md](../../shared/page-templates.md).
- **Investigations** (`investigation` entities, linked via `about` edges) — incident evidence,
written once at incident time. Sections: `## Summary`, `## Timeline`, `## Root cause`,
`## Mitigations applied`, `## Open questions`.
- **Runbooks** (`runbook` entities, bound by `applies_to_type`) — repeatable procedures. Carry
`risk_class` and a JSON-schema-validated `procedure`. **Runbooks also live as `SKILL.md` files
under `.agents/skills/<name>/`** — the DB row is the policy/lifecycle framing, the SKILL.md is
the executable procedure the agent loads. See
[the operations schema](../operations/schema.md).
## The two logs
- The per-page **`## Changelog`** records infrastructure changes and is machine-parsed
(`get_changelog`, the Oikos ledger). Keep the `### YYYY-MM-DD — title` shape.
- **`knowledge/log.md`** is append-only and records *documentation-maintenance* operations only
(restructures, source ingests, lint sweeps): `## [YYYY-MM-DD] <op> | <summary>`. It never
duplicates the Oikos change ledger (`oikos/ledger.py`).
- The per-document **`## Changelog`** records infrastructure changes to that node. Keep the
`### YYYY-MM-DD — title` shape so the parsed `changelog` field stays structured.
- **`archive/knowledge/log.md`** is the append-only record of *documentation-maintenance*
operations on the legacy wiki (restructures, source ingests, lint sweeps):
`## [YYYY-MM-DD] <op> | <summary>`. It is frozen with the rest of `archive/knowledge/`; new
doc-maintenance operations are recorded in the DB audit trail instead.
## Querying knowledge
Use MCP, not grep:
- `search_knowledge(query)` — ILIKE search over documents, investigations, and runbooks in
`knowledge_entities`.
- `get_entity_knowledge(entity_slug)` — every document, investigation, and runbook linked to one
entity, in one call.
- `get_entity(slug)` / `get_relations(entity)` — the structured graph around an entity.
Grep the clone only when MCP is unreachable, and prefer `archive/knowledge/` for historical
narrative (it is not updated when the DB changes).
## Same-session update rule
A change to a node updates every page that references it in the same session — the node page, the
section `README.md` table, the root `README.md`, the Caddy/DNS/ingress pages, the host page, and
`inventory.yaml`. See [page-templates.md](../../shared/page-templates.md#same-session-update-rule).
A change to a node updates the DB in the same session — the entity's attributes, the relationships
that reference it, and any document whose `at_glance` or changelog should reflect the new state. See
[page-templates.md](../../shared/page-templates.md#same-session-update-rule) for the legacy wiki
equivalent (now scoped to `archive/knowledge/` history).

View File

@@ -6,9 +6,10 @@ follows [writing-style](../../shared/writing-style.md); runbooks and plans use t
exception.
Where each kind lives: runbooks are skills under [`.agents/skills/`](../../skills/); operator
reference (command cheatsheet, enrollment, Hermes agent) lives in
[`.agents/operations/`](../../operations/); investigations are sources under
`knowledge/sources/investigations/`; plans stay in the repo-root `plans/` folder (below).
reference (command cheatsheet, enrollment, Nomos agent) lives in
[`.agents/operations/`](../../operations/); investigations are `investigation` entities in the DB
(historically `archive/knowledge/sources/investigations/`); plans stay in the repo-root `plans/`
folder (below).
## Plans always live in `plans/`
@@ -21,7 +22,7 @@ message.** An agent drafting a plan:
3. On completion, moves it to `plans/done/` and updates the index status.
This is the single source for homelab design intent; keeping it in-repo means the plan is
versioned, reviewable, and reachable by MCP `get_page`/`search_docs` like any other doc.
versioned, reviewable, and reachable by MCP `search_knowledge` like any other doc.
## Runbooks
@@ -44,12 +45,14 @@ transition: "<from> -> <to>" # only for lifecycle runbooks
## Investigations
Incident records live in `knowledge/sources/investigations/YYYY-MM-DD-slug.md` and are **evidence sources** — written
once at incident time, then linked from the changelogs of the nodes they implicate. Sections:
`## Summary`, `## Timeline`, `## Root cause`, `## Mitigations applied`, `## Open questions`. Resolved
incidents move to `knowledge/sources/investigations/archive/`.
Incident records are `investigation` entities in the DB, linked to the entities they implicate via
`about` edges. They are **evidence sources** — written once at incident time, then back-linked from
the changelogs of the nodes they implicate. Sections: `## Summary`, `## Timeline`, `## Root cause`,
`## Mitigations applied`, `## Open questions`. The legacy file-based investigations live at
`archive/knowledge/sources/investigations/` (frozen 2026-07-07); new investigations go in the DB.
## The operations log
`plans/log.md` and `knowledge/log.md` are append-only records of documentation operations on
those areas (`## [YYYY-MM-DD] <op> | <summary>`), distinct from the Oikos change ledger.
`plans/log.md` is the append-only record of documentation operations on plans
(`## [YYYY-MM-DD] <op> | <summary>`), distinct from the DB audit trail. The legacy
`archive/knowledge/log.md` is frozen with the rest of the archived wiki.