Documentation
¶
Overview ¶
Package catalog loads and searches an OKF knowledge catalog (a directory of markdown files with YAML frontmatter) — the read half of RunLore's Learn pillar.
Index ¶
- type Catalog
- func (c *Catalog) Entries() []Entry
- func (c *Catalog) HasVectors() bool
- func (c *Catalog) Len() int
- func (c *Catalog) Ready() bool
- func (c *Catalog) Reload(dir string) ([]string, error)
- func (c *Catalog) ReloadContext(ctx context.Context, dir string) ([]string, error)
- func (c *Catalog) Search(query string, k int) ([]Entry, error)
- func (c *Catalog) SearchHybrid(ctx context.Context, query string, k int) ([]ScoredEntry, error)
- func (c *Catalog) SearchScored(query string, k int) ([]ScoredEntry, error)
- func (c *Catalog) SetEmbedder(e Embedder)
- type Embedder
- type Entry
- type HybridSearcher
- type ScoredEntry
- type ScoredSearcher
- type Searcher
- type Syncer
- type TokenFunc
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Catalog ¶
type Catalog struct {
// contains filtered or unexported fields
}
Catalog is an in-memory BM25 index over OKF entries. It is safe for concurrent Search while a background sync calls Reload (the index is swapped atomically).
func NewEmpty ¶
func NewEmpty() *Catalog
NewEmpty returns a catalog with no entries — used before the first git sync.
func (*Catalog) Entries ¶
Entries returns a snapshot of the currently-indexed entries. Used by callers that validate catalog content out-of-band (kbvalidate at load time).
func (*Catalog) HasVectors ¶
HasVectors reports whether hybrid retrieval is live — a vector per entry.
func (*Catalog) Ready ¶
Ready reports whether the catalog has completed at least one successful load. It stays false for a git-sync catalog (NewEmpty) until the first sync indexes, so readyz can keep the leader out of rotation until its KB is warm.
func (*Catalog) Reload ¶
Reload rebuilds the index from dir and swaps it in atomically. The new index is built outside the lock so concurrent Search is only blocked for the swap. It returns the list of skipped (unparseable) entry paths so the caller can warn; these are non-fatal — the good entries are still indexed.
func (*Catalog) ReloadContext ¶
ReloadContext is Reload with a caller context bounding the (optional) embedding pass. When an embedder is configured, entry vectors are rebuilt here; an embedding failure is NON-fatal — vectors fall back to nil and the catalog stays BM25-only (hybrid retrieval degrades gracefully rather than breaking the reload).
func (*Catalog) SearchHybrid ¶
SearchHybrid combines lexical and semantic retrieval for instant recall. It pools candidates by Reciprocal Rank Fusion of the BM25 and embedding-cosine rankings (so an entry strong in EITHER signal is reachable), then returns up to k of them ORDERED BY COSINE with Score set to the cosine similarity — a [0,1] semantic confidence the recall gate keys off, kept score-descending so the gate's top-vs-runner-up margin stays well-defined. Falls back to BM25 (SearchScored) when vectors are unavailable or the query can't be embedded — hybrid never regresses recall, it only adds a vector signal when one is present.
The fusion choice and the cosine gate thresholds are eval-tunable knobs: recall records its score even on rejection (see recall.lookup) so they can be measured against the live instant-recall scenarios rather than guessed.
func (*Catalog) SearchScored ¶
func (c *Catalog) SearchScored(query string, k int) ([]ScoredEntry, error)
SearchScored returns up to k hits with their relevance scores.
func (*Catalog) SetEmbedder ¶
SetEmbedder enables hybrid retrieval: entry vectors are (re)built on the next Reload. Call once at startup, before the first Reload/Search.
type Embedder ¶
Embedder turns texts into vectors (one per input, in order). Satisfied by internal/embed.Client — defined here (consumer side) so the catalog needn't import a concrete embedder.
type Entry ¶
type Entry struct {
Type string // frontmatter: type (Playbook, Incident, …)
Title string // frontmatter: title
Description string // frontmatter: description
Resource string // frontmatter: resource
Tags []string // frontmatter: tags
Body string // markdown body (after frontmatter)
Path string // file path relative to the bundle root
}
Entry is one OKF knowledge entry.
func Load ¶
Load walks dir and parses every concept .md file into an Entry. The reserved OKF files index.md and log.md are skipped.
A file that fails to parse (e.g. malformed YAML frontmatter) is skipped rather than failing the whole load — its path is returned in skipped so the caller can warn — so one bad entry never empties the catalog. A genuine walk/IO error is still returned as the fatal error.
type HybridSearcher ¶
type HybridSearcher interface {
SearchHybrid(ctx context.Context, query string, k int) ([]ScoredEntry, error)
HasVectors() bool
}
HybridSearcher fuses BM25 and embedding similarity. HasVectors reports whether the vector side is live (an embedder configured AND vectors built for the corpus); callers fall back to SearchScored when it is false.
type ScoredEntry ¶
ScoredEntry is a search hit with its BM25 relevance score.
type ScoredSearcher ¶
type ScoredSearcher interface {
SearchScored(query string, k int) ([]ScoredEntry, error)
}
ScoredSearcher exposes relevance scores (used by instant recall).
type Syncer ¶
type Syncer struct {
URL string
Branch string
Dir string
Token TokenFunc // nil / empty => anonymous (public repo)
Log *slog.Logger
// contains filtered or unexported fields
}
Syncer keeps a local mirror of an OKF catalog Git repo up to date, calling onSync after each successful sync so the reader can re-index. This closes the read/write loop: the curator's merged PRs flow back into what the agent searches.