Your First Intent-Logged Commit

Why stating what you meant to do — before the commit hook inspects what you actually did — changes how bugs get caught.

Every Aura commit carries two pieces of information: the code change itself, and your stated intent for the change. The intent is a short natural-language description of what you were trying to accomplish. Aura compares it against the AST-level diff at commit time and flags any mismatch. This single mechanism is the most effective thing in the system for catching a specific, expensive failure mode: intent poisoning.

Intent poisoning is when a commit claims to do one thing and silently does another. It happens in human commits ("fix typo" that removes a validation check), and it happens much more frequently in AI-generated commits, where an over-eager model rewrites a helper it was told to leave alone. Aura cannot stop a determined attacker, but it can stop almost every accidental case, and it creates an audit trail for the rest.

This page explains what makes a good intent message, shows examples of good and bad intents against the same diff, and walks through the commit flow end-to-end.

The minimum viable flow

From inside an Aura-initialized repository:

# Edit some files
vim src/auth.rs

# Stage the change as usual
git add src/auth.rs

# Log what you meant to do
aura log-intent "Switched password hashing from bcrypt to argon2id"

# Commit normally — the hook validates intent vs. diff
git commit -m "Switch to argon2id for password hashing"

If your intent and diff agree, the commit succeeds. If they diverge, the hook prints a semantic diff report and exits non-zero:

aura pre-commit: intent/diff mismatch

Stated intent: "Switched password hashing from bcrypt to argon2id"

Actual semantic changes:
  Modified  auth::hash_password
  Modified  auth::verify_password
  Deleted   auth::legacy_md5_fallback        <-- not mentioned in intent
  Added     auth::Argon2Config

Fix one of:
  1. Update your intent to include the deletion.
  2. Unstage the unrelated changes.
  3. Override with `aura log-intent --amend`.

You then either update the intent with aura log-intent --amend "..." or re-stage the files to match what you actually meant to commit. The hook re-runs on the next git commit.

Why intent matters

Consider this scenario, which happens often enough that the Aura core team has a name for it: scope creep by accident.

You asked Claude Code to rename getUserById to fetchUserById across the codebase. The agent did that, correctly, and also inlined a helper function it thought was redundant, and removed a deprecation warning because it looked like dead code. Two of those three changes were not in the plan. Your tests pass because the inlined helper was equivalent and the deprecation warning had no runtime effect. You review the diff, see a lot of fetchUserById appearing, skim past the other two changes, and merge.

Three weeks later, a customer's integration breaks because the deprecation warning was how they learned about the impending API change. The agent did not do anything wrong — it made reasonable choices — but it did more than it was asked. Without a stated intent, there is no mechanical way to catch "more than it was asked." Aura's hook catches it because the intent said "Rename getUserById to fetchUserById" and the diff contained a deletion of a function unrelated to that rename.

The same mechanism catches accidental human over-commits: staging a dotfile edit by mistake, leaving a debug println! in a refactor, or committing two unrelated features in one go.

Writing a good intent

A good intent is specific about the semantic change, not about the mechanics. It should answer: what logic did I intend to add, modify, or remove, and why?

Good intents share a few properties:

  • They name the functions, classes, or modules touched.
  • They describe the why, not just the what.
  • They are scoped to the diff — if the diff touches ten things, the intent covers all ten or the diff should be split.
  • They are short. One sentence, occasionally two.

Bad intents tend to be:

  • Generic ("fix bug", "refactor", "cleanup").
  • Lying by omission — mentioning one change, ignoring another in the same commit.
  • Scoped to implementation detail ("changed line 42") rather than semantics.
  • Copied from the commit message when the commit message itself is useless.

Examples

Given a diff that modifies parse_config to return Result instead of panicking, and adds a new ConfigError enum:

Good: Made parse_config return Result<Config, ConfigError> instead of panicking on malformed input; added ConfigError enum with variants for each failure mode.

Also good: Switched parse_config to fallible error handling to support the new --validate-only CLI flag.

Bad: error handling — too vague. The hook accepts it; your future self will curse you.

Bad: Added ConfigError enum. — omits the signature change to parse_config. Hook will flag the mismatch.

Wrong: Added retry logic to network fetch. — describes a different change entirely. This is the intent-poisoning failure mode; the hook catches it.

Given a diff that deletes three deprecated helpers and their tests:

Good: Removed deprecated helpers: user::legacy_login, user::legacy_logout, user::legacy_session_check. All three were behind a deprecation warning since v0.9 and no longer called anywhere in the tree.

Bad: Cleanup. — technically true. Useless as an audit record. In strict mode, the hook requires an explicit enumeration of deletions and this intent is rejected.

Wrong: Renamed legacy_login to login. — would suggest the functions moved, not that they were deleted. The hook would flag a mismatch because no user::login appears in the diff as a new symbol.

The mechanics of aura log-intent

aura log-intent writes an entry to .aura/intent_log.jsonl. Each entry records:

  • A timestamp.
  • The current session ID.
  • The current branch.
  • The Git HEAD at the time of logging.
  • The natural-language intent.
  • A hash of the staged diff (so later rebases can detect that the intent was recorded against a different base).

The entry is append-only. Later log entries do not overwrite earlier ones; they supersede. This is deliberate — the log is an audit trail, not a working file.

Amending an intent

If the pre-commit hook rejects your commit because the intent and diff disagree, and the right fix is to update the intent rather than unstage files:

aura log-intent --amend "Switched password hashing from bcrypt to argon2id; also removed legacy_md5_fallback which was unused."

--amend appends a new entry that supersedes the previous intent for the current staged diff. The hook re-runs on the next git commit.

Listing recent intents

aura log-intent --list

Prints the last ten intents with timestamps, branches, and the commit SHAs they eventually became (or a "pending" marker if the commit has not happened yet).

Intent for work-in-progress commits

For a WIP commit that will be amended or rebased later, log an intent anyway. Use --wip:

aura log-intent --wip "Stubbed out Argon2Config; real implementation coming next"

WIP intents are not enforced as strictly — the hook tolerates unrelated changes — but they still enter the audit trail. When you eventually finalize the work, log a non-WIP intent that supersedes them.

Strict mode

The behavior above is the default. In strict mode, the rules tighten:

  • Every commit must have an intent. No implicit commits.
  • git commit --no-verify is blocked.
  • Deletions must be enumerated in the intent by name.
  • AI-authored commits (detected via Co-Authored-By or the MCP agent signature) must carry an intent produced by aura_log_intent from within an MCP tool call, not a shell wrapper.

Enable strict mode in .aura/config.toml:

[policy]
strict_mode = true
strict_mode_locked = true   # requires passcode to disable

If strict_mode_locked is true, turning strict mode off requires a passcode recorded at lock time. This is how teams ensure that an AI agent cannot disable its own guardrails; see the CLAUDE.md protocol for how Claude Code interacts with this.

Doing it from an AI agent

When Claude Code or another MCP-aware agent is the one committing, the flow is the same but the entry points are MCP tools rather than CLI commands:

  1. aura_status — the agent checks session and sync state.
  2. aura_snapshot — the agent snapshots files before editing.
  3. The agent writes code.
  4. aura_log_intent — the agent logs its stated intent. This automatically pushes the changed functions to any connected Mothership for teammates' Live Sync.
  5. git commit — the hook fires and validates.

Every MCP tool invocation is recorded. An agent that skips aura_log_intent and tries to commit will be stopped by the hook the same way a human would be.

Common first-time mistakes

"The hook says mismatch, but my intent looks right." — Check whether you staged files you did not mean to. git diff --cached --stat often reveals a stray change.

"I logged an intent, committed, then amended the commit with git commit --amend. The hook complains."git commit --amend changes the diff under the already-logged intent. Re-log with aura log-intent --amend "..." before amending.

"I rebased and the intents look detached." — Rebasing changes commit SHAs. The intent log tracks semantic identity, not SHAs, so the entries remain valid, but aura log-intent --list may show "pending" for a beat until the rebase settles. aura doctor can resynchronize if needed.

"My intent is fine but the hook still fails." — Run aura pr-review --base HEAD~1 to see the exact semantic diff. The hook's view and your mental model may disagree about what changed, especially in generated code.

Next steps