Knowledge store
The knowledge base's tools work on a KnowledgeStore, never on files. The kit ships one over markdown files; an agent can plug in another one (a database, a vector store) and the tools, the prompt and the skills stay the same.
The kit's store
createFileKnowledgeStore(knowledgeDir, { pageTypes?, sourcesDir? }) keeps pages as markdown files in the layout the knowledge base always had (see On disk). buildSessionOptions() creates it for you, with spec.knowledgePageTypes and config.sourcesDir, and returns it as knowledgeStore, so a host can read the knowledge base too (to show it in a desktop app, say):
const { options, knowledgeStore } = await buildSessionOptions(config, runDir, spec);
const topics = (await knowledgeStore?.list())?.filter((page) => page.type === "topic");
It's usable on its own as well, in a script or a test:
import { createFileKnowledgeStore } from "@falkenslab/agent-kit";
const store = createFileKnowledgeStore("course/knowledge", { sourcesDir: "course/sources" });
console.log(await store.index());
const report = await store.check();
The interface
interface KnowledgeStore {
types(): readonly PageType[];
list(): Promise<PageInfo[]>; // every page but the retired ones
read(id: string): Promise<KnowledgePage | null>; // with linkedFrom: the pages that link to it
create(type: string, slug: string, title: string, content: string, fields?: FieldChanges): Promise<string>;
createMany(pages: readonly NewPage[]): Promise<string[]>; // links among them allowed; all or none
edit(id: string, oldText: string, newText: string, fields?: FieldChanges): Promise<void>;
rewrite(id: string, content: string, fields?: FieldChanges): Promise<void>;
supersede(id: string, by: string, reason?: string): Promise<void>;
retire(id: string, reason: string): Promise<void>;
search(query: string, limit?: number): Promise<SearchHit[]>;
index(): Promise<string>;
log(operation: string, what: string, pages?: readonly string[]): Promise<void>;
recentLog?(limit?: number): Promise<string[]>; // optional: the latest log entries, newest first
check(): Promise<CheckReport>;
overview(): Promise<string>;
writeOverview(content: string): Promise<void>;
}
What a store must keep, whatever it stores the pages in:
- Ids are
type/slug, and links in content are[text](type/slug): return them that way fromread(), whatever you keep internally.parseId()andlinkedIds()are exported to help. - Links must resolve:
create,createMany,edit,rewriteandwriteOverviewrefuse a link to a page that doesn't exist, with a message the model can act on (the tools pass errors through as they are). - Pages are never deleted or renamed.
supersedeandretiremark them (fields.status:supersededorretired); a retired page leaveslist(),index()andsearch(), butread()still returns it. editreplaces exactly one occurrence, and fails if there's none or several.recentLog()is optional: without it,knowledge_read("log")says the store can't show its log.check()returns broken links, orphans, links to retired pages and summaries whose original is gone. The tool adds the sources folder's part itself.
BUILT_IN_PAGE_TYPES are the kit's four types with their templates; a store gets the agent's declared ones too, and should treat a page's type as a label, so it can hold any type.
Plugging in your own
import type { AgentSpec, KnowledgeStore } from "@falkenslab/agent-kit";
import { createPgKnowledgeStore } from "./pgStore.js"; // yours
const spec: AgentSpec<Config> = {
// …
knowledgeStore: (config) => createPgKnowledgeStore(process.env.DATABASE_URL!, { pageTypes: myTypes }),
};
With knowledgeStore, the kit doesn't touch knowledgeDir's files; it still needs knowledgeDir set, since that's what turns the knowledge base on (and keeps the file tools out of that folder).
A vector store usually keeps the curated pages as the source of truth and indexes them for search(): similarity search on embeddings of each page (or each section), with the same SearchHit result. Anthropic has no embeddings API; Voyage AI is the usual choice, and local options exist (LanceDB or sqlite-vec with a local model). index() and check() don't change.
Wiring the tools yourself
A host that builds its own session options gets the same tools with createKnowledgeServer(store, options):
import { createKnowledgeServer } from "@falkenslab/agent-kit";
mcpServers: {
knowledge: createKnowledgeServer(store, { runDir, interactive: true, sourcesDir, projectDir, knowledgeDir }),
},
interactive adds knowledge_retire, which asks a person first; leave it off where there's nobody to ask. Name the server knowledge, so the plan gate, the step gate and the tool labels recognize its tools.