The Catalog is the persistence layer for all agent configuration. Resources (agents, models, tools, knowledge bases) are stored as Kubernetes CR YAML files in a Git-backed store. The Catalog class is the top-level entry point; it holds one WorkspaceCatalog per workspace, each backed by a GitClient appropriate to the workspace's persistence type.
Catalog
└── Map<workspaceId, { workspace, gitClient, catalog: WorkspaceCatalog }>
WorkspaceCatalog
├── models: ModelCatalog
├── tools: ToolCatalog
├── kbs: KBCatalog
├── documents: DocumentCatalog
├── agents: AgentCatalog
├── stacks: StackCatalog
└── secrets: SecretCatalog
*Catalog
├── list()
├── listChanges(id) → PR history + commit log for that resource's file
├── create(entity)
├── update(entity)
└── delete(id)
Catalog is initialized by Server at startup. getWorkspaceCatalog(workspaceId) returns the WorkspaceCatalog for the requested workspace ID; route handlers call this using locals.workspace.id.
GitCatalog<T> is an abstract base class that implements the full CRUD lifecycle for any entity type. Concrete subclasses (GitModelCatalog, GitToolCatalog, GitKBCatalog, GitDocumentCatalog, GitAgentCatalog) extend it, supplying entity-specific YAML parse and serialize functions.
Initialization + sync: on the first list() call, GitCatalog reads the directory tree and parses all YAML files into entity objects. After that, it also registers gitClient.onFileChange and reloads entities when matching files change on the configured branch.
Mutation flow:
create / update / delete
→ render CR YAML
→ gitClient.createFile / updateFile / deleteFile (commits to branch)
→ gitClient.createPR(title, branch)
→ if PR is auto-merged: update in-memory list immediately
For the local persistence type, createPR returns a synthetic merged PR, so the in-memory list is always updated immediately.
ID generation: create() derives the resource ID from the entity name via slugify() (lowercase, spaces → hyphens, non-alphanumeric stripped).
Branch naming: feat/create-entity-{name}, feat/update-entity-{id}, feat/delete-entity-{id}.
GitClient is a provider-agnostic interface with operations for reading and writing files, traversing directory trees, listing and creating pull requests, and listing commits. The normalized PR and commit types carry only the fields needed by the catalog.
Used when workspace.persistence.type === 'local'. Reads and writes files directly on the local filesystem using isomorphic-git for commit tracking.
branch parameter is ignored; all operations target the working tree.listPRs returns []; createPR returns a synthetic already-merged PR so catalog mutations always take the auto-merge path..git does not exist.Used when workspace.persistence.type === 'git'. Auth via Authorization: Bearer <TOKEN>. Supports GitHub Enterprise via optional baseUrl. Uses BranchCache for all read operations.
BranchCache (used by GitHubClient) avoids per-file HTTP round-trips by downloading the entire repository as a gzip-compressed tar archive in a single request, parsing it in memory, and serving subsequent reads from the snapshot.
Refresh strategy: stale-while-revalidate (TTL: 60 s). A background refresh is triggered on the first access after the TTL elapses or after explicit invalidate(). Concurrent accesses during a refresh share the same in-flight promise and see the previous snapshot until the refresh completes.
Invalidation happens automatically when any mutation completes (invalidate after write), and lazily when the TTL elapses on the next read.