Knowledge Commons
A RunLore deployment starts with an empty catalog of its own. kb_search returns nothing
from it, and it stays that way until you have investigated enough incidents to curate entries
worth keeping. The knowledge commons fills that gap: a shared, read-only corpus of generic
playbooks — CrashLoopBackOff, ImagePullBackOff, unbound PVCs, stuck cert-manager
challenges, unschedulable pods — that covers failure classes every Kubernetes platform hits.
It is a second catalog root, indexed alongside your own, so the investigation loop has something to ground on from day one.
Note
It is on by default in the standard Helm profile. If you installed with
values-standard.yaml you already have it; minimal and the chart defaults leave it off,
and full enables it too. Remove the catalog.commons block to opt out — nothing else
depends on it.
What it does not do is make instant recall work on day one — see below. Day-one value is a better-grounded investigation, not a cheap instant answer.
catalog:
dir: /var/lib/runlore/catalog
commons:
url: https://github.com/Smana/runlore-kb-commons
branch: main
interval: 24h
dir: /var/lib/runlore/commons # MUST differ from catalog.dirTwo roots, four rules
The commons is deliberately not just “more entries in your catalog”. Four properties hold, and each one exists to stop a specific failure:
Both roots are indexed together. kb_search searches one index covering both. There is
no separate tool and no flag to remember mid-incident.
Commons entries are marked. Every entry carries its provenance, so a citation tells you whether the knowledge came from your cluster’s history or from the shared corpus. Those deserve different amounts of trust and you should be able to tell them apart at a glance.
Your entry wins ties. When a commons entry and one of your own score equally, yours ranks first. Knowledge written from your actual incidents beats a generic description of the same failure class. That decides equal scores only — which corpus leads on a given alert is a relevance question, answered below.
The curator never writes to it. Drafted entries always land in your own catalog repo. The commons directory is a mirror of an upstream repository and stays pristine; there is no configuration that makes it writable.
Why commons entries never fire instant recall
This is the property most worth understanding before you enable it.
Instant recall short-circuits the LLM loop entirely when the catalog
already holds a trustworthy answer. Before any scoring happens, it applies a structural
filter: an entry’s resource must agree with the alert’s workload. An entry with no
resource can only agree with a request that itself carries no workload — and real
Kubernetes alerts carry a namespace and a workload.
Commons entries are resource-less by construction. They describe a failure class, not one
cluster’s workload, so there is no honest resource to give them. The consequence follows
directly: a commons entry can never fire instant recall.
That is the correct behaviour, not a limitation to work around. Instant recall answers an
incident without looking at it. Doing that from a generic playbook would mean asserting that
your CrashLoopBackOff has the same cause as the textbook one — which is exactly the
confidently-wrong answer that makes cached knowledge worse than none.
What commons entries do instead is ground kb_search, which applies no structural filter.
The model finds and cites them mid-loop, where they belong: telling the investigation which
command to run next and which readings distinguish one cause from another. The evidence
still gets gathered; the playbook just makes gathering it faster.
To get instant recall you need entries scoped to your workloads (resource: <namespace>/<name>). Those are the ones RunLore drafts for you from your own incidents.
Which corpus leads, and when
kb_search is where commons entries do their work, and how much of it they keep depends on
what is failing. It is worth stating precisely, because nothing warns you when a playbook that
used to surface stops surfacing — or when one you assumed you had replaced surfaces anyway.
Every kb_search query is enriched with the incident’s workload. Whatever the model types,
RunLore appends the failing workload’s namespace and normalized name — plus the alert name —
server-side, before the query reaches the index. The reason is retrieval quality: a
label-derived alert’s text is one or two generic tokens, and the object that identifies the
incident lives only in the labels. That is the same vocabulary mismatch
instant recall already solves, fixed here the same way.
Enrichment is not a provenance rule and knows nothing about which root an entry came from. It lifts whichever entries contain those tokens — and demotes the ones that do not, because BM25 scores a partly-matched query below a fully-matched one, so adding terms an entry cannot match costs it rank. The entry that names the failing object leads. Which entries can do that depends on the object:
Application workloads — your entries, and only yours. payments and checkout-api appear
in no generic playbook: a commons entry names a failure class and carries no resource. So
once you have curated an incident for payments/checkout-api, an alert on that workload puts
your entry first — even when the two describe the same failure in nearly the same words, and
even when the commons entry scores higher on the symptom text alone (BM25 normalizes for
document length, and your entry carries a resource line the commons entry may not). On an
empty catalog the commons CrashLoopBackOff playbook leads that same alert; measured against
the shipped corpus, one curated incident of your own moves it behind yours by roughly an order
of magnitude. For this class the commons really is a floor that fades.
Platform components — the commons can lead, and usually should. The playbooks name
cert-manager, ArgoCD, CoreDNS and kube-system explicitly, in their tags and in the kubectl
commands they tell you to run. When the failing workload is one of those — namespace
cert-manager, workload cert-manager-webhook — the enrichment tokens match the shared
playbook too, and it can take the top slot from an entry of yours about a certificate on some
other service. It should: it describes the component that is actually broken, while yours
describes a different object.
The rule is per object, not per failure class. Curate an incident for the platform component
itself — resource: cert-manager/cert-manager-webhook — and your entry carries those same
tokens, competes on the symptom text again, and leads. Until then the shared playbook holds
that slot regardless of how much unrelated knowledge you have accumulated.
Your entry wins ties, as above. That settles equal scores only; it does not override a relevance gap in either direction, and the gaps enrichment opens are far larger than a tie.
There is no knob either way — enrichment is unconditional and the tie-break is not configurable — so plan for both directions. A commons entry can fall out of the top hits for a failure class you have learned, which is the intended outcome; if losing it costs you something, your own entry for that class is too narrow. And a commons entry can hold the top slot for a platform component you have not learned, well past the point where you assume your own catalog is answering. In both cases the fix is the same: write the entry for the object the alert actually names.
Scope discipline
Every commons entry ends with a # Not covered section naming the adjacent failure classes
it does not explain — the OOM playbook says it does not cover node memory pressure, the
scheduling playbook says it does not cover volume node affinity conflicts.
This is load-bearing rather than decorative. A generic playbook is most dangerous at its edges, where it looks applicable and is not, so each entry states its own boundary instead of leaving the model to infer one.
Operational notes
The commons syncs on its own schedule, separate from your catalog’s: its own directory, a much longer interval (a shared corpus changes slowly), and a sync failure that logs rather than propagates. An upstream repository being briefly unreachable must never degrade the catalog an incident actually depends on.
Its checkout is an emptyDir — re-cloned on startup, never persisted. Nothing is authored
there, so there is nothing to lose on restart, and keeping it off the persisted data path
means an upstream sync cannot dirty the volume holding your outcome ledger and audit log.
commons.dir must differ from catalog.dir. Both the agent’s config validation and the
Helm chart refuse to start with a shared root, because one directory serving both corpora
would let an upstream sync overwrite the entries you curate.
Tracking a branch, or pinning a revision
commons.branch tracks a moving branch: an upstream edit reaches kb_search at the next
interval. Shared corrections arrive without you doing anything — which is the point of a
commons, and also means the corpus moves without you looking.
commons.ref is the other side of that trade. Pin a tag or a full 40-character commit id
and the corpus is frozen until you move it, so you can read the upstream diff before it
grounds an investigation:
catalog:
commons:
url: https://github.com/Smana/runlore-kb-commons
ref: v1.2.0 # a tag name, or a full commit id
dir: /var/lib/runlore/commonsbranch and ref are mutually exclusive — setting both fails at startup rather than
quietly picking one. A pinned revision cannot move, so the periodic sync becomes a local
no-op rather than a fetch, and the index is rebuilt only on startup or when you move the
pin. Your own catalog.git repo is deliberately not pinnable: the curator opens PRs
against it, and freezing it would leave “merged” and “in use” permanently apart.
Be precise about what pinning buys, because an unpinned commons is not a hazard you are
patching. The properties that keep a shared corpus in its place hold either way: its
entries are read-only, the curator never writes to them, yours win ties, and none of them
can fire instant recall. What an upstream edit can still influence is what kb_search
puts in front of the model mid-investigation — evidence is still gathered, the verdict is
still reached against your cluster, but the prompt was shaped by someone else’s most
recent commit. Pinning narrows that to changes you have read. It cannot judge them for
you: a pin you bump without reading the diff buys exactly nothing.