Open source · Rust · MIT · kybmemory.com

The shared memory your AI agent fleet keeps forgetting it needs.

KYB — Know Your Business is a git-backed, searchable knowledge base for fleets of AI agents. Which servers exist, how services are wired, what broke and how it ended, what is still open — the operational truth that survives between sessions and across machines. Every write keeps the attribution its client supplied: which agent, and when known, which session and workspace.

licenseMIT tests421 test cases searchhybrid · ~7–9ms LAN rustedition 2021 releasev0.3.1 · brew · docker · cargo
★ Star on GitHub Install → Read the docs
agent@fleet — kyb — 96×26
$ kyb query "which servers run clickhouse?"orders-api-architecture  ·  score 0.867  ·  #infra #clickhouse  "orders_api on host-a is the single write path into ClickHouse (gRPC :9000)" $ kyb incident --key inc-2026-08-06-orders-api-oom --severity criticalcreated · status open · hints: add a `detection` check, link `knowledge` $ kyb task-status task-raise-log-retention --status in_progress --assignee agent-amoved · assignee=agent-a · title, body, tags and priority untouched $ kyb query "why did the order service keep restarting"   # no keyword overlapinc-2026-08-06-orders-api-oom  ·  resolved  ·  semantic hit ✓$ 
The problem

Agents forget everything between sessions. Multiple agents — Claude Code, Codex, Antigravity — on multiple machines rediscover the same infrastructure over and over, and every hard-won incident lesson evaporates the moment the context window closes.

Concrete scenario
Session 1: An agent diagnoses an outage, discovers that a write buffer exhausted container memory, fixes it, and files inc-orders-api-oom with an executable detection check and resolution.

Session 2 (weeks later): Another agent on a different machine asks "why did the order service keep restarting?" Hybrid search can surface that resolution even when the wording differs from the entry — instead of re-investigating what was already solved.
Fast setup in 3 steps
1. Launch the server: brew install alex09x/apps/kyb && brew services start kyb (or Docker / Cargo: cargo install knowyourbusiness --locked && kyb-server).

2. Wire your fleet: Drop the skill into local agents via bash skills/install.sh (from a git checkout), or connect directly over native HTTP MCP via POST /mcp.

3. Ask before reasoning: Agents query KYB first, claim tasks, and enrich the shared knowledge base before finishing.
// How it works

Seven ideas, one operational truth.

No database, no namespaces, no ceremony. Just git, a disposable index, and a search that actually finds things.

⎇

Git is the canon

One markdown file per entry, one commit per change. A commit sha is a version id. There is no database — history, diff and rollback come for free, and any text editor can read the canon.

⌕

Hybrid search

BM25 fused (reciprocal rank) with vector search over every entry — e5-small, int8 ONNX locally on CPU. Describe a problem in your own words and the right entry surfaces; exact technical terms still rank first.

⚠

Incidents & tasks built in

Not just facts: operational events and work in flight are first-class entries with real lifecycles — and every closing demands an outcome in writing.

↺

Upserts by key

Writes are keyed and deterministic — a no-op when content did not change, so no empty commits. Flat key space plus tags; predictable key patterns are the deduplication mechanism.

✎

Every write says who

A commit records the attribution its client supplied — the agent, and when known its session and the workspace it ran in — as git trailers, as by in history and the ledger, on each version in the console. A write without context has none; older commits are not attributed after the fact. Forensics, not identity: attribution grants nothing; tokens do.

⌂

Local, private, no secrets

Binds to 127.0.0.1 by default. To serve a trusted LAN, opt into one exact private interface; out of the box tokens are off and the service speaks plain HTTP, so never publish port 9310 to the internet as it is: turn tokens on and put TLS in front first. Writes that look like a token, key or password are rejected: store pointers, never credentials.

🦀

Rust, all the way down

axum + tantivy 0.22 + git2 + ort (ONNX Runtime). One write mutex, lock-free reads. The index is a disposable cache — lose it and it rebuilds from git on the next start.

// Architecture

Git in, ranked answers out.

KYB architecture: AI agents, Rust server, Git history and derived BM25 plus optional vector search
Git keeps the durable history. The server rebuilds search state from Git and combines BM25 with optional vector search. Without a model, lexical search still works. View full size ↗
// Entry kinds

Three kinds, one flat key space.

Only the closing states archive an entry — and every one of them requires an outcome in writing.

knowledge

What is true now

A fact under a stable key: architecture, topology, deploys, decisions, gotchas.

live → retracted
incident  ·  inc-…

What happened

An operational event: what broke, the impact, the runbook, the resolution.

open → mitigated → resolved
task  ·  task-…

What is in flight

Work and ideas: who holds it right now, what it waits on, what came of it.

open → in_progress → blocked → done | dropped
// Incidents

A report is a control panel, not a story.

The server teaches structure instead of gating on it — a bare report is accepted, but the reply names every missing actionable part. Two hard rules: keys start with inc-, and closing requires a resolution.

detection
An executable "is it still happening?" check, with the expected healthy result.
affected
Machine-readable poisoned windows — a backtest excludes them programmatically.
knowledge
Links to the knowledge entries the incident concerns.
resolution
How it ended — searchable, so "how did we fix this last time" has an answer.
runbook
Each step marked SAFE (an agent may act alone) or APPROVAL (human required).
follow-ups
Checkbox loose ends in the body — the server counts them and warns when you close over them.
RESOLVED severity: critical

inc-2026-08-06-orders-api-oom

orders_api OOM loop: the write buffer grows until the container restarts.

started14:02
detected14:09
mitigated14:31
resolved16:48
✓ resolution recorded · 0 open follow-ups
// Tasks

A board your agents can actually share.

A task is a short actionable note with a real lifecycle. Claim it before you start so two agents don't do the same work; block it with the reason it waits on; close it with what came of it. Every change is a git commit, so history replays who held what, in which status, at any point in time.

kyb tasks — live only, freshest on top
in_progress high assignee=agent-a
task-raise-log-retention
72h retention, 2G disk budget
blocked critical assignee=agent-b
task-swap-failing-disk
waits on: the replacement disk
open unclaimed
task-audit-log-rotation
audit.jsonl grows unbounded

Partial transitions

kyb task-status sends the status and nothing else — title, body, tags, priority and links stay exactly as stored. A transition never has to fetch and resend the task.

pick up--status in_progress --assignee agent-a
get stuck--status blocked --blocked-reason "…"
hand back--status open --assignee ""
finishkyb done <key> <<< "what came of it"

Nothing is inferred

Unranked stays unranked, unclaimed stays unclaimed. A blocked_reason is only valid while blocked — moving off blocked clears it, so a task never advertises a block it is out of. parent_task hangs child work under the task it belongs to.

// The agent skill

One command wires it into every agent on the machine.

A skill an agent never opens is a skill it never uses — so the installer drops a pointer into each agent's always-loaded global instructions. Marker-delimited and idempotent: re-running updates the section in place.

Claude Code

~/.claude/skills/kyb
+ CLAUDE.md

Codex

~/.codex/skills/kyb
+ AGENTS.md

Antigravity

~/.gemini/…/skills/kyb
+ GEMINI.md

$ KYB_SERVER=your-server:9310 bash skills/install.sh

Executed from a clone of the KYB repository. (The Homebrew package installs the client CLI and wires this automatically.)

What no database can enforce — governance

01

The loop is ask → assess → enrich: query before reasoning, write back what you learned before finishing.

02

Always query before adding. Found something close? Overwrite the same key — duplicates kill a shared base.

03

Entries are self-contained and hold verified facts only — never a guess dressed as knowledge.

04

Working a task means claiming it first, blocking it with a reason, closing it with an outcome.

05

Broke something? File an incident, close it with a real resolution, then fold the lesson back into knowledge.

06

Secrets never in bodies — pointers in refs, and the server rejects the rest.

// Model Context Protocol

Native MCP over HTTP.

KYB is not an MCP alternative — it speaks Model Context Protocol natively. The server serves the MCP protocol directly over HTTP at POST /mcp. No client-side adapters, no subprocesses, and no client packages to install or update.

# any client that speaks MCP over HTTP; one URL, no package $ claude mcp add --transport http kyb http://<host>:9310/mcp # Claude Code $ codex mcp add kyb --url http://<host>:9310/mcp # Codex $ agy mcp add -t http kyb http://<host>:9310/mcp # Antigravity $ gemini mcp add -t http kyb http://<host>:9310/mcp # Gemini CLI # Cursor, Windsurf, VS Code and any other client that speaks MCP over HTTP: the same URL, in that client’s own configuration file and schema

Zero client adapters

The tool list is generated by the server. Clients discover capabilities when listing tools, without updating a local KYB adapter, and may need to refresh or reconnect after an upgrade.

Shared audit log

Tool calls forwarded through /mcp execute against the same API routes and share the audit log; when tokens are on, the actor is recorded too. Eligible operations (entry gets, search queries, and mutations) are recorded with caller IP and duration, while routine health (/healthz), taxonomy (/tags), and all incident and task list reads are excluded to avoid polling noise.

Agent skills or MCP

Both reach the same server. The agent skill (skills/install.sh) gives Claude Code, Codex and Antigravity the kyb command and the rules for using it; MCP is for any client that would rather call tools than run a shell — IDEs, desktop apps, or those same agents. Either path records attribution when the client supplies it: the CLI reads its environment, MCP needs the hook, the client’s metadata or the headers described under Attribution; a client registered with nothing but the URL writes unattributed.

// Attribution

Who wrote what, on every version.

Since 0.3.0 a write is committed with up to four trailers: the agent, its session, the workspace it ran in and where that record came from — whichever of them the client could tell; empty fields are left out, and a write with no context carries none. History and the activity ledger return them as by; the console shows them on each version; kyb whoami shows what the current shell would write. Workspaces are a repository name and a path inside it, never an absolute path. The git author stays the service’s unless tokens name a principal.

kyb: upsert inc-2026-10-11-orders-api-oom Kyb-Agent: codex Kyb-Session: example-session-001 Kyb-Workspace: orders-api Kyb-Via: cli

via: cli

The kyb command read the environment the agent runs it in: which provider, which session, which repository.

via: hook

Claude Code calls the MCP tools over HTTP; a decision-free PreToolUse hook adds the record to each call, and the server takes it out of the arguments before the API sees them.

via: meta

The MCP client’s own call metadata named the conversation (Codex, Antigravity) when there is no hook. Fixture-tested; live evidence so far is for cli and hook.

via: headers

Any client: X-Kyb-Agent, X-Kyb-Session, X-Kyb-Workspace. Sources are read in order — hook, then the client’s metadata, then headers. The first source that names an agent selects the agent and the session it has; a missing session may be filled by a source naming the same agent or no agent, and the workspace is the first available value. via names the agent’s source; which source filled each field is not recorded.

The record is what the caller supplied, not an authenticated identity. GET /whoami echoes it back. Access is a separate matter: tokens with read, write and admin roles, off by default.

// Console

A console for people, served from the binary.

Open http://<host>:9310/. No build step, no separate service, one quiet type scale; colour only where state demands it. Every screen and every write a person can make is driven by a browser test in CI, with block coverage of the page script held at 100%.

Queues, not boards

Incidents and tasks are attention queues: what needs a person now, with the reason in the row — blocked and why, open with no detection check, stale for how long.

Versions

An entry’s own ledger: every version, newest first, with the whole of what it changed and, when the client said, who wrote it and from where. Any version is one click away as it was first written.

Ledger

Activity is a change ledger: the whole change, not a feed. Each row names the author when tokens identify one, otherwise the agent and workspace when the client supplied them, otherwise unknown.

Services and hosts

For each service or host an incident names: what is open on it right now, the notes those incidents cite, the open tasks pointing at them. Every row says why it is listed; nothing is inferred from tags.

// Search quality

Vectors earn their keep.

Evaluated with scripts/eval-search.sh using paraphrase questions that share few or no tokens with the entries they land on. In-memory Tantivy BM25 fused with an int8 multilingual ONNX model running locally on CPU.

SETUP
TOP-1
TOP-3
TYPICAL LATENCY
lexical only (BM25)
1 / 14
2 / 14
~7 ms
+ e5-small int8 118 MB · default in container
3 / 14
4 / 14
~9 ms
Documented measurement (2026-09-22): Measured over LAN against a 643-entry base with e5-small int8 using the 14 reference paraphrase questions in scripts/eval-search.sh. The example queries were originally drafted against a different test base (three target keys are absent from this 643-entry corpus, capping the reachable score well below 14/14). On identical queries against the same corpus, hybrid vector fusion roughly doubles retrieval hit rate over lexical BM25 alone. Replace example queries and target keys with your own base before drawing production conclusions.
// HTTP API

A small, honest surface.

Eligible API operations are appended to a JSONL audit log — timestamp, ip, method, path, status, duration — while routine health (/healthz), taxonomy (/tags), and all incident and task list reads are excluded to avoid polling noise.

METHOD
PATH
WHAT IT DOES
POST
/knowledge
Upsert by key → {key, sha, changed, action}. Identical content = no commit.
GET
/knowledge/{key}
Current entry; ?at=<sha> returns a version from history.
GET
/knowledge/{key}/history
Every version, newest first, with what changed.
DEL
/knowledge/{key}
Retract knowledge / archive an incident or task. History stays searchable.
POST
/incidents
Upsert a report; reply carries hints + unknown_knowledge.
GET
/incidents
Filter by status / service / follow-ups. Live first, freshest on top.
POST
/incidents/{key}/resolve
Flip status, record the outcome, stamp the timeline. Resolution required.
POST
/tasks
Upsert a task, or send a partial status / assignee / parent / blocked-reason update.
GET
/tasks
?status=&priority=&assignee=&parent_task= — live tasks, freshest on top.
POST
/tasks/{key}/resolve
done or dropped — resolution required, then archived.
GET
/search
Ranked hits with full bodies. ?q=&tag=&history=&kind=&status=&sort= · as_of= the base as it stood then — a date, an RFC 3339 instant or a git revision; the version current at that instant answers, never a superseded one · changed_between=
GET
/knowledge/{key}/diff
?from=&to= — the change between two versions: fields and body lines.
GET
/knowledge/{key}/related
What the entry refers to and what refers to it, each with how — a knowledge list, a parent_task, a link in the text. Never a shared tag.
GET
/places
Services and hosts named by incidents, open and total, the worst first.
GET
/impact
?service= or ?host= — incidents on it, the notes they cite, the open tasks pointing at either.
GET
/whoami
The role this request has and the attribution it carries — what a write from here would record.
GET
/api/activity
The change ledger: action, key, author, by, files, sha, time.
GET
/tags
Which topics the base covers, most used first.
GET
/healthz
entries · open_incidents · open_tasks · index_docs · last_commit
// Install

Up in two commands.

🍺 macOS · Apple Silicon
$ brew install alex09x/apps/kyb$ brew services start kyb
Installs both binaries, wires the skill into every agent on the machine, and keeps the server alive under launchd.
🐳 Docker
$ docker compose up -d# ghcr.io/alex09x/kyb:latest
The model is baked into the image, so the container has no network dependency at runtime.
🦀 Cargo & Crates.io
$ cargo install knowyourbusiness --locked$ kyb-server# or from source: cargo run --release
Installs and launches the kyb-server binary. Note: the client CLI and skills/install.sh require a separate git repository checkout.
⚠

Two things to know before you expose it

Tokens are off by default — keep port 9310 on a private network. Tokens with read, write and admin roles tell callers apart and name them as the author of their commits; they do not encrypt the traffic, so beyond a trusted network add TLS in front. And run the container as your host uid: otherwise the git canon ends up root-owned and unreadable by hand, and git-as-truth is the whole point.

Configuration — env, all optional
KYB_DATA./kyb-data
KYB_INDEX./index
KYB_ADDR127.0.0.1:9310
KYB_MODELdir · absent = lexical
KYB_AUDITaudit.jsonl
KYB_SERVERfor install.sh
KYB_AUTHoff · compat · required
KYB_AUTH_FILE./auth.json
KYB_ANONread · public demo
CLI cheatsheet
$ kyb tags / kyb health          # the map of the base, and its pulse$ kyb query "nats streams" --tag infra --history$ kyb add --key nats-streams --title "..." --tags nats,infra <<< "body"$ kyb get nats-streams --at <sha>      # any historical version$ kyb query "orders api" --as-of 2026-08-01   # the base as it stood then$ kyb incident --template               # the report skeleton$ kyb incidents --status open --open-followups$ kyb resolve inc-… <<< "what fixed it"  # resolution mandatory$ kyb task-status task-… --status in_progress --assignee agent-a$ kyb tasks --status blocked --priority critical$ kyb done task-… <<< "what came of it"$ kyb whoami                             # the agent, session and workspace a write would carry$ echo "$TOKEN" | kyb login                # when the server asks for tokens
// Fleet deploy

One idempotent command, whole pipeline.

Refuses to run with uncommitted changes, waits for CI green, health-checks the server, then rolls the skill and CLI to every machine. Sleeping laptops don't abort the rollout — unreachable hosts are skipped and the run ends with a per-machine health table.

git push → CI builds the image → server pulls & restarts → skill + CLI to every machine
$ scripts/deploy.sh # everything
$ scripts/deploy.sh --skills # only roll skills + CLI

Machine-specific config lives outside the repo in a gitignored fleet.local.sh. Releases are byte-reproducible: fixed member order, pinned mtimes, zeroed uid/gid, verified against a layout contract before the tag build can ship.

// Citation & Attribution

Citing KYB.

KYB is authored by Alexander Panasenko. If you use KYB in academic, archival, or technical research, cite the software via Zenodo:

v0.3.0 DOI: 10.5281/zenodo.23309457 Concept DOI: 10.5281/zenodo.22850723 Author Profile ↗
@misc{panasenko2026kyb,
  doi = {10.5281/zenodo.23309457},
  url = {https://zenodo.org/records/23309457},
  author = {Panasenko, Alexander},
  title = {KYB (Know Your Business): Git-backed knowledge base and incident tracker for AI agents},
  version = {0.3.0},
  publisher = {Zenodo},
  year = {2026}
}
K

Give your agents a memory.

One command to run it, one to wire every agent on every machine into the same operational truth.

★ Star on GitHub Install Read the docs →