Your git history records what changed, never why
Open git log on any codebase older than a year and read twenty messages in a row.
Most describe the diff: "update user service", "fix null check", "refactor auth". You could have
learned all of that from the diff itself. What you cannot learn — the thing you actually opened the
log to find — is why anyone thought it was a good idea.
That gap has a cost you pay constantly without itemising it. Every time an engineer stares at an odd-looking retry loop and can't tell whether it's essential or leftover. Every time someone "cleans up" a workaround and reintroduces the bug it was silently preventing. Every onboarding week spent reconstructing decisions from archaeology.
The why has always lived somewhere else
It's not that teams don't record reasoning. They record it in pull request descriptions, in review threads, in Slack, in a Jira ticket, in a design doc, in someone's head. All of those have the same two properties: they are outside the repository, and they decay.
Pull requests survive only as long as you stay on that host and that host keeps them. Chat messages age out of retention. Ticket systems get migrated, and the links in your commit messages turn into 404s. The code, meanwhile, lives forever. Over a long enough horizon, every codebase converges on the same state: perfect knowledge of what changed, near-total amnesia about why.
The comment explains the code. The commit message explains the change. Nothing explains the decision.
Why AI makes this worse, quickly
An agent can produce a week of changes in an afternoon. The volume of code rises sharply while the volume of recorded reasoning stays flat or falls, because the agent doesn't attend the standup, doesn't argue in the review thread, and doesn't remember its own session tomorrow.
Worse, the reasoning that did exist — the prompt, the constraint the model was given, the alternative it rejected — lives in a conversation transcript that is almost never preserved anywhere near the code. Six months later a second agent reads the diff with no idea what problem it was solving, and confidently "improves" it.
If your team's answer to "why does this exist" is already "check the PR," notice what happens when the PR author is a model that no longer exists in the same form.
Conventions help, until they don't
The usual response is a commit convention: Conventional Commits, a template with a "why" section, a lint rule requiring a ticket reference. These genuinely help, and if you have none of them, adopt one this week.
But they share a weakness. The why ends up as unstructured prose inside a free-text field that
also holds the what, the ticket number, the scope prefix and occasionally an emoji. You cannot query
it. git log --grep is substring matching, so you can find the word "retry" but not the
concept. And nothing enforces that the field actually contains reasoning rather than a restatement
of the diff.
Make the reason a field, not a paragraph
The alternative is to treat intent as first-class data with its own slot, separate from the message. That's the bet kal makes:
kal snap -m "add retry with backoff" \\
-i "the IdP rate-limits bursts of logins; linear retry still spiked p95"-m is what changed. -i is why it exists, stored as a structured field
inside the immutable snapshot. Because it's a field rather than prose, three things become
possible:
kal why auth.pyreturns the full provenance chain for a file — every snapshot that touched it, each with the reasoning captured at the time.kal ask "why do we retry logins"does relevance-ranked search across intents, messages and paths, offline.kal contexthands an AI agent a briefing that includes the intents, so the next model to touch that code starts with the reasoning rather than guessing.
The part that surprises teams
The interesting effect isn't retrieval. It's that a dedicated field changes what people write. Given one message box, engineers describe the diff, because the diff is what's in front of them. Given a separate box labelled "why," they answer the question — and they notice when they can't, which is a useful signal in itself. A change nobody can justify in one sentence is worth a second look before it merges.
There's a related discipline worth stealing even if you never adopt a new tool: when an experiment fails, write down why before you delete the branch. kal formalises this — archiving a branch requires a reason, and those reasons surface in search and in the briefings agents read — but you can approximate it with a decisions file in the repo. The goal is the same: keep the lesson in the repository, where it lives as long as the code does.
A test for your own repository
Pick the strangest-looking function in your codebase. Something with a hard-coded number, an odd retry, a workaround with no comment. Now try to find out why it's there, using only what's in the repository — no asking colleagues, no searching chat.
How long it takes you is the size of the gap. For most teams it's somewhere between twenty minutes and never, and it's about to get bigger.
Try kal on a repository you already have
kal runs alongside git — kal init inside an existing repo changes nothing until you
ask it to. Snapshots record intent and human-vs-AI authorship, every operation is undoable, and
kal git sync mirrors everything back into git.