capability-os
README.md
# CapabilityOS
**Searchable memory of what a codebase already knows how to do.**
Two failure modes, one index:
- A coding agent can't see your conventions, so it writes a fourth JSON helper.
- A team re-debugs the same production failure every few months.
CapabilityOS indexes two Markdown collections — the **capabilities** your code
already has, and the **incidents** it has already survived — and serves them over
[MCP](https://modelcontextprotocol.io) so an AI agent consults them *before* writing code.
Retrieval is SQLite and file reads. **No model calls, no API keys, no per-query cost.**
That's the design constraint that matters: a lookup that's free is a lookup you can
make mandatory. A lookup that costs tokens is one people skip.
```
$ capability-os find "json"
1 capability match(es) for 'json':
**batch_json_writer** [Formal] — utility — json, batch, file io — `src/shared/io.py`
Read and write JSON with consistent encoding and paths.
risk: LOW
REUSE these instead of writing new code. Call get_capability_detail(<name>) for
the API and usage examples, and impact_analysis(<name>) before modifying one.
```
---
## Why this isn't just grep
Three things grep doesn't do.
**1. It tells the agent what to do, not just what exists.**
Tool output is written as instruction — `REUSE these instead of writing new code` —
because a model handed a bare list of filenames will acknowledge it and then write
the duplicate anyway. The MCP tool docstrings are part of the interface, phrased as
`ALWAYS call this before writing any new function`.
**2. It knows the blast radius before you change something.**
```
$ capability-os impact progress_tracker
Blast radius: HIGH (59 caller(s) across 537 scanned files)
Declared risk in index: LOW
WARNING: real usage (HIGH) exceeds the declared risk (LOW). Update the index —
a stale risk label is how a 'safe' refactor breaks forty callers.
```
That output is from a real repository. The index claimed LOW; 59 modules disagreed.
**3. It fails CI when the knowledge base starts lying.**
`capability-os check --strict` exits non-zero when a capability marked `Formal`
has no documentation, or when declared risk has drifted below actual usage.
Documentation that isn't enforced becomes fiction; this is the enforcement.
---
## Install
```bash
pip install "capability-os[mcp]" # from a clone: pip install -e ".[mcp]"
```
Python 3.11+. Zero required dependencies — `mcp` is needed only for the server,
and both SDK majors (`mcp` 1.x and 2.x) are supported.
## Quick start
```bash
cd your-project
capability-os init # scaffold knowledge/ and capability-os.toml
capability-os index # build the search index
capability-os list
```
`init` writes a working scaffold you edit in place:
```
your-project/
├── capability-os.toml # paths + scan settings (all defaults shown)
└── knowledge/
├── capability-index.md # the registry — a Markdown table
├── capabilities/<name>.md # one doc per capability
└── incidents/<slug>.md # one postmortem per failure
```
### Register a capability
`knowledge/capability-index.md` is an ordinary Markdown table:
```markdown
| Capability | Type | Tags | Risk | File | Status |
|---|---|---|---|---|---|
| batch_json_writer | utility | json, batch, file io | LOW | src/shared/io.py | Formal |
| auth_guard | backend | jwt, auth | MEDIUM | src/backend/auth.py | Core |
```
Columns are matched **by header name, not position** — reorder them, add your own,
or use another language (`能力`, `风险`, `文件` all work). Multiple tables merge by
capability name, so a separate status or summary table lands on the same records.
### Record an incident
One file per failure. Frontmatter is optional; headings are parsed when it's absent.
```markdown
---
title: CDN served a stale audio file for a year
date: 2026-06-02
keywords: cache, cdn, immutable
lesson: Append a version query string when replacing any immutable-cached asset.
---
## Problem
Updated audio kept serving the old recording in production.
## Root cause
The CDN sent `Cache-Control: immutable` with a one-year max-age.
```
Write the `lesson` as advice to your future self at 2am, not as a summary.
It's what search surfaces first.
---
## Connect it to an AI agent
Add to your MCP client config (Claude Code, Claude Desktop, or any MCP host):
```json
{
"mcpServers": {
"capability-os": {
"command": "capability-os-mcp",
"env": { "CAPABILITY_OS_ROOT": "/absolute/path/to/your-project" }
}
}
}
```
Six tools become available:
| Tool | When the agent calls it |
|---|---|
| `find_capability(query)` | Before writing any new function or module |
| `find_incident(query)` | The moment something breaks, before debugging |
| `get_capability_detail(name)` | To read the API before calling it |
| `list_all_capabilities()` | Once at session start, for orientation |
| `impact_analysis(name)` | Before modifying shared code |
| `reindex()` | After editing the knowledge base |
Then make it non-optional. In `CLAUDE.md` or your agent's system prompt:
```markdown
Before writing any new function: call find_capability first.
If it returns a match, reuse it — do not reimplement.
Before modifying anything in src/shared/: call impact_analysis first.
When you hit an error: call find_incident before debugging.
```
---
## The capability lifecycle
A status isn't decoration; it's a claim about how much trust the code has earned.
```
Ghost → Candidate → Formal → Core → Deprecated → Archived
```
| Status | Meaning |
|---|---|
| **Ghost** | Duplicated logic spotted in the wild, not yet extracted |
| **Candidate** | Appeared in 3+ places — extraction is due |
| **Formal** | Extracted and documented |
| **Core** | Widely called; change via a new version, never in place |
| **Deprecated** | Superseded; migrate callers |
| **Archived** | No callers remain; kept for history |
`check --strict` holds `Formal` and `Core` to their claim: they must have a
document, and their declared risk must not be below actual usage.
---
## CLI
```bash
capability-os init # scaffold a knowledge base
capability-os index # rebuild the index from Markdown
capability-os find <query> # search capabilities
capability-os incident <query> # search postmortems
capability-os show <name> # print one capability's docs
capability-os list # catalog grouped by status
capability-os impact <name> [--strict] # callers + blast radius
capability-os check [--strict] # validate the knowledge base (CI)
capability-os serve # run the MCP server on stdio
```
### In CI
```yaml
- run: pip install capability-os
- run: capability-os check --strict
```
---
## Configuration
Every field in `capability-os.toml` has a working default; an empty file is valid.
```toml
[project]
name = "your-project"
[knowledge]
dir = "knowledge"
index_file = "capability-index.md"
capabilities_dir = "capabilities"
incidents_dir = "incidents"
db_file = ".capability-os/capability.db" # generated; safe to gitignore
[scan]
source_dirs = ["src", "lib", "scripts", "backend", "app"]
source_globs = ["*.py", "*.ts", "*.tsx", "*.js", "*.go", "*.rs", "*.java"]
exclude_dirs = [".git", ".venv", "node_modules", "__pycache__", "dist", "build"]
blast_thresholds = [4, 11] # caller counts at which risk becomes MEDIUM, then HIGH
```
---
## Design notes
**Markdown is the source of truth; SQLite is a cache.** The database is rebuilt
by full replace, never migrated — delete a row and it actually leaves the index.
Humans and models both read and edit the Markdown; nobody edits the database.
**Impact analysis is textual on purpose.** A real call graph needs a resolver per
language. The question being answered — *how many places would I have to look at?* —
is answered well enough by matching the name and its import spellings. False
positives are listed for a human to dismiss; false negatives are the dangerous
kind, so search terms are deliberately broad.
**Search degrades instead of failing.** FTS5 when available, LIKE scanning when
not, identical result shape either way. Queries are tokenized and quoted, so
`c++` and `dash-word` search instead of raising.
See [`docs/design.md`](docs/design.md) for the longer argument, and
[`docs/README.zh-CN.md`](docs/README.zh-CN.md) for Chinese documentation.
## Development
```bash
pip install -e ".[dev]"
pytest # 75 tests
```
## License
MIT
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues