A Claude-maintained, self-syncing knowledge base engine for code teams. It targets code knowledge: conventions, decisions, gotchas, recipes, glossary terms, and repo inventory. It is not a PARA or second-brain note system.
The engine ships two parts that stay separate:
- Engine - the scripts, hooks, presets, and skill that live in this repo.
- Content - a standalone git repo (or submodule) scaffolded by the engine and owned by your project.
/plugin marketplace add larstonder/kb-engine
/plugin install knowledge-baseThis registers the engine as a plugin: it wires the five lifecycle hooks automatically (via hooks/hooks.json, resolved through ${CLAUDE_PLUGIN_ROOT}) and adds the /kb slash command used to scaffold content (below).
To develop against a local checkout instead, point the marketplace at the directory: /plugin marketplace add ~/path/to/kb-engine. (Prefer the GitHub source for normal use: a local directory source copies untracked files into the plugin cache.)
./install.sh --project <project-dir>This copies hooks/, lib/, and skills/knowledge-base/ under <project-dir>/.claude/kb-engine/ and merges the hook entries into <project-dir>/.claude/settings.json. Re-running is idempotent.
With the plugin installed, run the /kb slash command from inside the project you want a KB for:
/kb init <kb-dir> --preset general|monorepo [--mode standalone|submodule|inrepo] [--branch <branch>] [--auto-commit|--no-auto-commit]
/kb sync
/kb doctor
/kb wraps the bundled CLI (the plugin doesn't put kb on your PATH). If you installed via install.sh or a plain clone instead, call the CLI directly from the engine repo, passing --project:
./bin/kb init <kb-dir> --preset general|monorepo \
[--categories a,b,c] \
[--mode standalone|submodule|inrepo] \
[--branch <branch>] \
[--auto-commit|--no-auto-commit] \
--project <project-dir>
./bin/kb sync --project <project-dir>
./bin/kb doctor --project <project-dir>init creates the category folders, copies content-template files (CONVENTIONS.md, INDEX.md, BACKLOG.md, README.md, .gitignore, .gitattributes), vendors the validators into <kb-dir>/.kb/bin/, installs the git pre-commit hook (standalone/submodule only), and writes .kbconfig in the project root. sync re-vendors the validators and re-installs the pre-commit hook after an engine update. doctor checks dependencies, config, kb.json validity and version, vendored validators, and git state. The lifecycle hooks no-op in any project without a .kbconfig, so the KB only becomes active once init has run (and from the next session start).
Three modes are available, selected via --mode at kb init time:
standalone(default) -kb initrunsgit initon<kb-dir>, making it a self-contained repo.initdoes not add a remote.submodule-<kb-dir>is a git submodule, i.e. still its own repo, mounted in the parent project.inrepo- the KB is plain files tracked inside your main project repo. See below.
A standalone KB works with no remote at all. Commits are recorded locally each session; the Stop hook's push and the SessionStart fast-forward simply no-op (logged, exit 0). Add a remote whenever you want syncing:
git -C <kb-dir> remote add origin <url>
git -C <kb-dir> push -u origin <branch> # one-time; afterwards the hooks pull/push automaticallyIf <kb-dir> lives inside another git repo (e.g. .knowledge/ in your app), the KB is a nested repo: the parent repo sees it as a single embedded entry (git won't recurse into it). The engine does not modify the parent's .gitignore, so add the KB dir there yourself to keep the parent clean:
echo '<kb-dir>/' >> .gitignore # in the PARENT project--mode inrepo places the KB as plain files inside your application's own git history - do not gitignore it.
At Stop, the hook commits only the KB directory via a scoped pathspec commit (git commit -- <kb-relative-paths>). It never pushes and never pulls: the KB rides your normal branch workflow.
Caveat: with AUTO_COMMIT=true, KB commits land on whatever branch you have checked out, so they interleave with your feature work and ride along in PRs. If that is undesirable, set AUTO_COMMIT=false (the default for inrepo) and commit the KB dir yourself.
The engine does not install a pre-commit hook in inrepo mode (there is no separate .git to hook). Validation still runs at Stop. To validate KB entries on your own commits, wire <kb-dir>/.kb/bin/validate.sh into your project's pre-commit hook.
Two config files are involved.
Written by kb init. Read by every hook and kb sync at runtime.
KB_DIR=".knowledge" # relative (or absolute) path from project root to the content repo
MODE="standalone" # standalone | submodule | inrepo
AUTO_COMMIT="true" # true | false; default true for standalone/submodule, false for inrepo
BRANCH="main"Universal knob that controls what the Stop hook does with KB changes:
true- Stop commits the KB. For standalone/submodule it then pushes to the remote; for inrepo it commits but never pushes.false- Stop validates only; no staging or committing. You commit the KB yourself.
Defaults: true for standalone and submodule, false for inrepo.
Override at init time:
kb init <dir> --mode inrepo --auto-commit # force true
kb init <dir> --mode standalone --no-auto-commit # force falseWritten by kb init from the chosen preset. Defines the category schema and enables/disables the opt-in checks.
{
"version": 1,
"categories": [
{ "name": "glossary", "type": "glossary" },
{ "name": "decisions", "type": "decision",
"extraFields": [{ "name": "status", "allowed": ["active", "superseded"] }] }
],
"checks": {
"frontmatter": true,
"wikilinks": false,
"ghostLinks": false,
"graphConnectivity": false
},
"staleMonths": 3
}| Preset | Categories | Checks enabled |
|---|---|---|
general |
glossary, conventions, decisions, recipes, gotchas | frontmatter only |
monorepo |
glossary, conventions, decisions, recipes, gotchas, repos | frontmatter + wikilinks + ghostLinks + graphConnectivity |
Use --categories a,b,c to override the category list from a preset.
All hooks guard on .kbconfig and exit 0 immediately if the project has no KB configured.
| Event | Hook | Behaviour |
|---|---|---|
SessionStart |
kb-pull.sh |
Fast-forwards the content repo to origin/<branch>. Skips silently if offline, dirty tree, or local commits are ahead. |
SessionStart |
kb-stale-sweep.sh |
Flags entries whose updated frontmatter date is older than staleMonths. |
Stop |
kb-capture-checkpoint.sh |
Once per session, blocks the stop with a self-check nudge when no KB changes have been made. |
Stop |
kb-auto-push.sh |
Validates staged entries; quarantines invalid ones; commits and pushes the clean remainder. |
PostToolUse(Read) |
kb-log-read.sh |
Logs a consult entry to .usage.log when Claude reads a KB entry file. De-duplicates per session. |
The entry validator (validate.sh) and opt-in checks (check-wikilinks.sh, check-ghostlinks.sh, check-graph.sh) are vendored into <kb-dir>/.kb/bin/ at init and sync time. The git pre-commit hook in the content repo calls validate.sh so entries are checked locally before any commit, without requiring the engine repo to be on PATH.
Validation reads category types, allowed extra-field values, and enabled checks directly from kb.json. No hardcoded category names.
validate.sh uses a plain generated git pre-commit hook (not lefthook or any external hook manager).
Strict YAML parsing uses ruby or python3 when available; falls back to grep-based parsing otherwise.
bash(>= 3.2)jqgitpython3orruby(optional - for strict YAML frontmatter parsing; falls back to grep)
bin/kb # init and sync CLI
content-template/ # files copied into every new content repo
hooks/ # five lifecycle hook scripts + hooks.json
hooks/hooks.json # plugin hook wiring (uses ${CLAUDE_PLUGIN_ROOT})
lib/ # config.sh, gitops.sh, validate.sh, check-*.sh,
# template.sh, precommit.tmpl
presets/general.json # preset: code team, frontmatter check only
presets/monorepo.json # preset: multi-repo, all checks enabled
skills/knowledge-base/ # SKILL.md + scripts/log-consult.sh
.claude-plugin/plugin.json # plugin metadata
.claude-plugin/marketplace.json
install.sh # non-plugin install path
tests/ # test_*.sh + run.sh
MIT - see LICENSE. Copyright (c) 2026 Lars Tønder.