docs

  meerkat · knows

meerkat

A knowledge base served as a single static Go binary — three ways, CLI, MCP, and HTTP — so your developers and agents start from what is actually true at your org.

meerkat exposes a Markdown wiki as a CLI (mk search/show/list), an MCP server over stdio for agent harnesses, and an HTTP/OpenAPI server with bearer auth for tools like OpenWebUI. Content can be compiled into the binary at build time, or resolved at runtime from a directory or a signed archive. Either way search runs in-process with no external service and no network. It is the knows leg of the platform.

No credentials in the binary

The binary ships with no LLM credentials and is read-only over the knowledge base. The only "live" action — ingestion — shells out to your agent CLI, running under your own account.

Installation

The binary is meerkat, with a short alias mk. The repo is public and Apache-2.0, so installation works anonymously — no login or token required.

install — macOS arm64bash
PLATFORM=darwin_arm64
mkdir -p ~/.local/bin
gh release download --repo zegit-zoo/meerkat \
  -p "meerkat_*_${PLATFORM}.tar.gz" --output - \
  | tar -xz -C ~/.local/bin meerkat
ln -sf meerkat ~/.local/bin/mk
meerkat version

No tag is pinned above — gh release download with no tag argument fetches the latest release. Keep current with mk update --check then mk update. Releases are cosign-signed as a Sigstore bundle; mk update verifies the signature over the checksum file before trusting any hash, then does an atomic swap.

Core concepts

Content sources

The wiki body, the ingestion source registry, prompts, and templates are configuration, not code. The mechanism is content-source.yaml (copy from the example in the repo). The open-source build ships no content at all — every example returns nothing until you point it at your own.

content-source.yamlyaml
content:
  type: git              # none | local | git | submodule | url
  repo: your-org/meerkat-kb
  host: github           # github | gitlab — selects the gh/glab token
  ref: v1.2.0            # tag or commit SHA (pin for reproducibility)
  layout:
    wiki:      wiki                    # markdown pages
    sources:   ingestion/sources.yaml  # the source registry
    prompts:   ingestion/prompts       # per-source prompts
    templates: templates               # page templates

Build time vs. runtime

Not every source type works at both ends. git and submodule are build-time only — they are resolved by make sync and baked in. local and url also resolve at runtime, so one released binary can serve different knowledge bases without a rebuild.

SourceBuild timeRuntimeNotes
noneyesyesEmbedded placeholders — the default.
localyesyesA directory on disk. Unverified.
gityesCloned at build; borrows a cached gh token for GitHub.
submoduleyesA git submodule in the repo.
urlyesAn HTTPS .tar.gz. sha256 is required and verified before extraction.

At startup meerkat resolves content in a fixed order, first match wins: --kb-dir (or MEERKAT_KB_DIR), then --content-source (or MEERKAT_CONTENT_SOURCE), then content-source.yaml in the user config dir, then one in the working directory, and finally the embedded build.

terminalbash
mk --kb-dir ~/kb list                       # serve a directory directly
mk --content-source ./content-source.yaml list
mk version --json | jq .kb_source           # what am I actually serving?

Provenance is explicit

mk version reports kb_source as embedded, disk:<path>, or url:<url>@<digest>. Only the url form is digest-verified — disk: means meerkat read whatever was on disk and checked nothing. The separate kb_commit field always describes the build-time embedded content and does not change to reflect runtime content.

OKF bundles

meerkat serves an OKF (Open Knowledge Format) knowledge bundle directly, with no conversion step — OKF is a directory of Markdown files with YAML frontmatter, which is already meerkat's storage model. meerkat implements the consumer side only: it reads bundles, it does not produce them.

A bundle's root is its content root, so point layout.wiki at it:

content-source.yamlyaml
content:
  type: local
  path: /path/to/the-bundle   # the bundle root itself
  layout:
    wiki: "."                 # concepts sit directly under it

Use --content-source, not --kb-dir

--kb-dir always assumes the default layout (a wiki/ subdirectory) and has nowhere to carry a layout: override, so pointing it at a bundle root finds no pages and reports an empty knowledge base.

Two OKF frontmatter fields are promoted into meerkat's core: type (OKF's only required key, and a filter facet — see mk list --type) and description. The trust family — generated, verified, stale_after — is surfaced on every read path as two computed fields, trust_tier and stale. Everything else OKF defines (resource, sources, okf_version, the Attested Computation keys) is preserved verbatim under front.extra.

verifiedtrust_tier
absentunverified
present, no entry's by starts with human:machine-confirmed
present, at least one by starts with human:human-reviewed

trust_tier is advisory, not verified

The tier is asserted by whoever produced the bundle — meerkat derives it from the frontmatter but checks nothing. A producer can write verified: {by: human:anyone} freely. Read it the way you read the disk: provenance label, not as an integrity guarantee.

OKF reserves index.md and log.md for navigation, and meerkat skips them — but keyed on whether the file has frontmatter, not on the filename, so meerkat's own knowledge bases can keep using index.md as an ordinary landing page. OKF v0.2 is early and unratified, and meerkat is an independent third-party consumer, not affiliated with or endorsed by its authors. Full reference: docs/OKF.md.

Ingestion

meerkat is the planner; an agent CLI (OpenCode by default) is the executor. Pages begin as placeholders pointing at an upstream source; mk ingest renders one task per page, and mk ingest --execute spawns an agent session per page (under a wall-clock cap) to write the page, commit, and push.

terminalbash
mk ingest sources                       # list the source registry
mk ingest --source policies             # plan only (writes a JSONL batch)
mk ingest --source policies --execute --max-parallel 4

An in-process Bleve BM25 index over the served markdown — no external service, no network, no embedding model. Built in-memory at startup; three indexed fields with boosts (title ×5, id ×3, body ×1). The body field accepts Bleve query strings.

Frontmatter filtering is post-search

Field filters like --owner and --type compose after the BM25 query — frontmatter is not indexed, so don't present owner:team-x as a working query term. Those filters exist on mk list, not on mk search.

Next

Authoritative reference, generated from the component repos. Spot something stale? Tell us.