Skip to content

Git integration ​

kontext uses git itself as the collaboration layer: files for truth, commits for review, trailers for links, hooks for enforcement.

Hooks ​

HookWhat kontext doesCan block?
pre-commitvalidates staged knowledge and scans it for secrets; re-renders .ai/README.md from the staged tree and stages it; reminds you of inbox candidates that touch staged pathsyes, on errors
prepare-commit-msgadds Decision:, Convention:, Learning:, Incident: trailers for staged entries (skipped for merge commits; an amend is measured from the parent of HEAD)no
post-commitqueues sync events for knowledge that changed at HEAD, removes promoted inbox items that are now committed, starts a background deliveryno
post-merge, post-rewritequeues sync events after pulls, merges and rebasesno

Bypass once with KONTEXT_SKIP=1 git commit … or git commit --no-verify.

Installation rules ​

kontext hooks install (also run by kontext init) never replaces your hooks:

  • The target is core.hooksPath when it is set (husky's .husky/_ is mapped to .husky/), otherwise .git/hooks (git rev-parse --git-path hooks, shared by all worktrees).
  • In an existing shell hook a marked block is inserted right after the shebang, so it runs even if the rest of the script exits early.
  • A non-shell hook (e.g. a Node script) is renamed to <hook>.kontext-chained and called after kontext's block.
  • Each block looks for kontext on PATH, in ~/.local/bin and ~/.cargo/bin, and does nothing when it is missing, so shared hook directories do not break teammates who have not installed kontext.
  • If the hook directory is tracked (e.g. .githooks/), the change shows up in git status: commit it to share the hooks with the team.
  • If a tracked hook directory exists but is not active yet (for example npm install sets core.hooksPath later), kontext tells you and kontext hooks install --hooks-dir .githooks covers it.
  • Hook managers that regenerate hook files (lefthook, pre-commit) are detected; add kontext hook <name> to their configuration instead.

kontext hooks status shows what is installed; kontext hooks uninstall removes the blocks and restores chained originals.

jj (Jujutsu) ​

A colocated jj repository is a git repository to kontext, with two differences: jj never runs git hooks, and it never stages. Nothing checks a commit for you, so run the checks by hand before jj commit / jj describe or jj git push:

  • kontext prepare-commit (or ctx_prepare_commit): with nothing staged it reads the working tree's changes against HEAD, which is the jj working copy, and lists the knowledge covering them;
  • kontext drift: the knowledge your change, committed or not, left behind since the default branch;
  • kontext check: validation and the secret scan the pre-commit hook would have run.

For the team, put the gate where every commit passes, whatever made it: the check script (bun run check, make check) or CI runs kontext drift --fail (exit status 2 when a change left recorded knowledge behind) or kontext ci --strict. kontext adds no git hook that blocks a commit for drift, since a jj commit would never meet it; kontext hooks status says the same.

kontext confirm and the promotions stage files in git's index; jj takes the files from the working copy and ignores the index, so this is harmless. Trailers are not added for you: write them into the description (prepare-commit lists them).

Guards that look for a dirty tree (a verify run marks [dirty: <paths>] in the ledger and is not run over MCP, confirm refuses a file with unstaged edits) see jj's working copy as uncommitted changes in git's terms. Run jj commit or jj new first, so the files you confirm are in a commit; a colocated jj smoke test runs in CI when jj is installed.

Trailers ​

For every knowledge file staged in a commit, prepare-commit-msg adds a trailer (git interpret-trailers --if-exists addIfDifferent):

text
fix(billing): round in cents

Decision: 2026-09-28-prices-are-integer-cents

Trailer keys come from store.kinds.<kind>.trailer. Plain git answers questions with them:

sh
git log --format='%h %s%n%(trailers:key=Decision,valueonly)' -- src/billing
git log --grep 'Decision: 0007'

kontext why ranks commits with kontext trailers first.

Entries mined by kontext init get none: they come from the older commits listed in their commits field.

Rewording with git commit --amend -m … keeps the trailers: the hook recognizes the amend (from its arguments, or from the committing git process) and measures what the commit adds from HEAD's parent. A git merge --squash commit gets the trailers of everything it carries.

Sync events ​

After a commit, merge or rebase, kontext compares the knowledge files at HEAD with the snapshot of the last sync (per worktree) and queues a sync event for every added or changed entry. The first run in a worktree only records the snapshot; kontext sync --all mirrors every entry once. Nothing happens unless an adapter subscribes to sync.

The outbox ​

Hooks never talk to the network. Events are appended to <git-common-dir>/kontext/outbox.jsonl and a detached kontext outbox flush delivers them. Deliveries are tracked per adapter and op, and only one flush runs per clone. An attempt counts only for the adapter that was actually tried, so one adapter's outage does not use up the others' retries; events for an adapter that when skipped stay queued. After eight failed attempts an event moves to outbox.dead.jsonl, which kontext status shows, and kontext outbox retry puts back. Nothing is dropped silently. kontext outbox lists what is pending and the last error; sync reports deletions and renames; adapter logs rotate.

Merges ​

  • Entries are separate files: parallel branches rarely touch the same one.
  • .ai/README.md is regenerated and marked merge=union (in .ai/.gitattributes).
  • Sequential ADR numbers can collide between branches, the same as with any ADR practice; date-based ids (the default for new stores) avoid it.

Worktrees ​

Everything local lives under the git common directory, so all worktrees of a clone share the inbox, the outbox and bootstrap progress, while each worktree keeps its own search index and sync snapshot (they follow the checked-out branch; commits that leave the history through an amend or rebase are dropped from the index).

Each inbox candidate records the worktree and branch it was captured in. With parallel agents in separate worktrees (Superset, Codex, Claude Code), ctx_prepare_commit, the pre-commit reminder and the brief offer only the current worktree's own candidates; another live worktree's appear apart as "not for this commit", and a removed worktree's may be adopted by anyone. kontext inbox shows where each one came from.

Released under the MIT or Apache-2.0 license.