The Pre-Commit Hook, Explained
The moment Aura earns its place in your workflow.
Every concept in Aura — semantic diff, function-level identity, intent tracking, shadow branches — converges at one point: the pre-commit hook. It is where the tool actually says yes or no to a change. It is the moment the difference between a text-based VCS and a semantic one becomes a difference you can feel.
A Git pre-commit hook runs a script. Typical scripts: linters, formatters, test runners. Useful, narrow, mechanical. They say "your code compiles" or "your tests pass." They cannot say "this change matches what you said it was." They cannot say "you accidentally deleted a public function." They cannot say "this commit is inconsistent with your own description."
Aura's pre-commit hook can say all three. It is not a linter. It is a semantic consistency check.
A good pre-commit hook is the last line of defense against a well-intentioned mistake.
What the hook does, at a glance
When you run git commit, the hook intercepts. Its work:
- Parse the staged changes. Every touched file is parsed into an AST.
- Compute the semantic diff. The AST before vs the AST after, as a set of node-level operations.
- Load the intent. The most recent intent logged in the current session, covering the staged changes.
- Compare. A classifier asks whether the diff is a plausible realization of the intent.
- Run review. Additional checks: accidental deletions, layer violations, security red flags, signature changes on public APIs.
- Produce a verdict. Consistent, inconsistent, ambiguous. With a confidence score and reasons.
- Decide. In strict mode, block the commit on any serious finding. In non-strict mode, record the finding and let the commit proceed with a warning.
- Write the shadow commit. The AST operations, the intent, and the verdict are recorded on the shadow branch.
- Finalize. Control returns to git, which produces the ordinary git commit.
The whole flow typically runs in under a second. On large changes it takes longer, but the common case is fast enough to feel like normal commit latency.
Strict mode
Aura has two operating modes, configurable per repository.
Non-strict mode
The default on a new repo. The hook runs, produces a verdict, records it on the shadow, and lets the commit through no matter what. Warnings appear in the terminal; they do not block.
Non-strict mode is useful for:
- Adopting Aura incrementally on an existing repo.
- Teams still establishing conventions.
- Personal exploration where you want the signal without the friction.
In non-strict mode, the shadow accumulates a full record of verdicts. You can review them later and decide which ones deserve attention. The tool is informational.
Strict mode
Enabled with a single setting (and, optionally, a passcode that makes it unlockable only by a human). In strict mode, the hook blocks commits when:
- The verdict is inconsistent — stated intent disagrees with the AST delta.
- A function was deleted without an intent that acknowledges the deletion.
- A public API signature changed without an intent that declares the change.
- The review surface flagged a likely bug or security issue.
- Intent was not logged at all for a non-trivial change.
A blocked commit prints a clear explanation: which check failed, on which nodes, and what would unblock it. The author fixes the issue (either by revising the change, or by logging a more accurate intent) and retries.
Strict mode is where Aura earns its reputation. It refuses to let a change through that does not match its own description. For a team operating at scale — especially a team with AI agents contributing — this is the single most valuable property.
Locked strict mode
For production-critical repos, strict mode can be locked with a passcode. Agents and automated processes cannot disable strict mode. A human with the passcode can, but only after a deliberate action. This is a durability feature: it ensures that your safety net is actually load-bearing, not quietly turned off by the next agent that finds it inconvenient.
What gets checked
The checks are layered. Each builds on the previous.
Layer 1: Intent consistency
Given the intent and the diff, does the diff realize the intent?
The classifier looks at:
- Scope: did the diff change only the things the intent implies? An intent about docs should not correspond to a diff that modifies functions.
- Direction: did the diff do what the intent said? Adding vs removing, refactoring vs rewriting.
- Scale: is the size of the diff plausible for the stated intent? A one-sentence intent and a 500-function change are usually suspicious.
The output is a consistency score and a one-paragraph reason.
Layer 2: Structural safety
Regardless of intent, some changes are surface-level flags:
- Accidental deletion of a function that has live callers elsewhere in the repo.
- Silent removal of a public API without a deprecation or intent declaration.
- Signature change on a function used by other modules — callers surfaced for review.
- Dangling reference — a function references a node that no longer exists.
- Layer violation — a domain module calls into a presentation module, if layer rules are configured.
These run regardless of the intent text. A "fix typo" intent does not excuse deleting a public function; the hook notices either way.
Layer 3: AI review
When the diff is non-trivial, the hook invokes aura_pr_review — a model-driven pass that looks for:
- Likely bugs (off-by-one, inverted boolean, missing error handling).
- Security red flags (hard-coded secrets, unescaped queries, unsafe deserialization).
- Architectural drift (new global state, circular dependencies, duplicated logic).
These findings are advisory by default, enforceable by policy in strict mode. They are produced at commit time so they are cheap — commits are small, the review is targeted, and the findings arrive before the change lands anywhere.
What the author sees
A successful, consistent commit looks almost like a normal git commit, plus a brief verdict:
Aura: intent consistent (confidence 0.94)
- 2 functions modified: retry_logic, backoff_delay
- 1 function added: exponential_interval
- No signature changes
[main 7c9f21a] Refactored retry_logic for exponential backoff
A flagged commit in non-strict mode:
Aura: intent INCONSISTENT (confidence 0.87)
Reason: intent mentions docs-only changes, but 2 functions
were modified (authenticate, refresh_token).
Recommendation: revise intent, or split the commit.
[main a4b2d9c] (committed with warning)
A blocked commit in strict mode:
Aura: commit BLOCKED
Finding: Function `validate_session` was deleted. It has
3 callers in the repo. Your intent did not declare a deletion.
To proceed:
1. Revise the commit to keep the function, OR
2. Log intent acknowledging the deletion:
aura_log_intent "Removed validate_session — replaced by
verify_token throughout the codebase"
and update the callers, then retry.
The block is explanatory, not dictatorial. The author knows why, and knows how to unblock.
Intent, done well
The hook is only as useful as the intents it is checking against. A few patterns for logging intent well:
Say what, and why, specifically.
- Weak: "refactor"
- Strong: "Refactor
retry_logicto use exponential backoff for rate limit compliance"
Declare deletions and breaking changes explicitly.
- Weak: "clean up auth module"
- Strong: "Remove deprecated
login_v1— all callers migrated toauthenticatein last release"
When touching many things, log multiple intents.
- Weak: one giant intent covering four unrelated edits
- Strong: one intent per logical unit of work, each with its own focus
For small, obvious changes, a short intent is fine.
- "Fix typo in error message for auth failure" is perfectly reasonable for a one-line change.
The classifier is not looking for prose. It is looking for a declaration that matches the diff. A few words of honest specificity outperform a paragraph of vague ceremony.
What the hook does not do
It is worth being precise about the limits.
- Not a type checker. The hook does not rerun your compiler. If your code fails to compile, the compiler tells you; the hook does not duplicate that work. (You can, of course, still run a compile in the hook chain.)
- Not a test runner. Tests are their own discipline. The hook is about consistency between intent and delta, not correctness of delta.
- Not an approval. A consistent verdict means "your description matches your change," not "your change is good." Code review, tests, and deployment gates still apply.
- Not magic. If you log "refactor" and the diff is a refactor, the verdict is consistent — even if the refactor introduces a bug. The hook is a consistency layer; correctness is still your job.
The hook catches a specific class of mistake: the mistake of saying one thing and doing another. For the other classes — incorrectness, bad design, missing tests — other tools apply. But this class of mistake is surprisingly common, surprisingly destructive, and surprisingly hard to catch any other way.
Interaction with git's own hooks
The Aura hook coexists with any other pre-commit hooks you have installed. It registers itself as one of the steps in the chain, not the only one. Your lint-staged, your pytest, your cargo test, your custom checks all continue to run. The Aura step is additive.
Uninstalling is clean: aura doctor can add or remove the hook registration, and the rest of your hook chain is untouched.
The hook and AI agents
The hook's most consequential role is as a check on AI-generated commits. An agent edits. An agent runs git commit. The hook runs. If the agent's intent does not match the agent's diff, the commit is blocked.
This is a remarkable property. It means an agent that misunderstands its task, or drifts during execution, or pastes the wrong change, cannot silently commit the wrong thing. The error surfaces at the moment of commit, before the change escapes into shared history. A human reviewing an agent's work can trust that the intent label, the diff, and the code are coherent — because the hook verified that they are.
In summary
The pre-commit hook is where Aura stops being a set of diagnostics and becomes a contract. You tell the tool what you mean to do. The tool compares what you did. If they agree, the commit lands. If they disagree, the tool refuses — or warns, if you have told it to — and hands you back a precise description of the disagreement.
It is the simplest possible embodiment of a deep idea: that version control should record what you meant, not just what you shipped, and should verify the two agree.
Related
The hook consumes intents, computes a semantic diff, writes to the shadow branch, and enforces a consistency contract between the author's description and the actual AST operations. It is the point at which session-level intent meets the commit it will validate.