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.
94 lines
5.3 KiB
Markdown
94 lines
5.3 KiB
Markdown
# Knowledge domain — schema
|
|
|
|
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.
|
|
|
|
## Source of truth — the database
|
|
|
|
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.
|
|
|
|
| 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 |
|
|
|
|
### Seed ingest
|
|
|
|
`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-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 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).
|