aura save

The unified commit command: snapshot, log intent, commit, and push in one call.

Synopsis

aura save [--intent "<message>"] [--no-push] [--no-verify] [--paths <pathspec>...] [--strict]

Description

aura save is the primary command most users run. It replaces the classic git add . && git commit -m "..." && git push loop with a single, semantically-aware operation that protects your work at every stage.

Under the hood, save performs four things in order: it takes a pre-edit snapshot of each modified file (so aura rewind can recover a function later), writes an intent record describing what you are trying to accomplish, creates the commit on the underlying Git branch, and optionally pushes the resulting function bodies to your Mothership (for teammate sync) and the commit to the configured Git remote. Because each step is recorded in the Aura semantic index, every function that changed as part of this save becomes traceable by its logic-node identity, not by file path or line number. This means that if you later rename authenticateUser to logIn, every aura trace, aura rewind, and aura diff will still follow the function's identity across the rename.

If --intent is omitted, Aura will attempt to infer one from the staged AST diff and your recent conversation with the active agent. Inferred intents are marked with a leading ~ in logs so you can distinguish them from human-authored ones during review.

Flags

| Flag | Description | | --- | --- | | --intent "<message>" | Human-readable description of what this change is trying to do. Compared against the AST diff by the pre-commit hook. | | --no-push | Create the commit locally but skip pushing to Mothership and Git remote. | | --no-verify | Skip the pre-commit hook. Disabled entirely when strict_mode_locked is true. | | --paths <pathspec>... | Limit the save to specific files or directories. Defaults to the full working tree. | | --strict | Fail the save if the intent does not match the AST diff, instead of merely flagging it. | | --amend | Append to the previous save instead of creating a new one. Re-runs the hook. | | --dry-run | Show what would be snapshotted, committed, and pushed without performing any writes. |

Examples

1. The typical workflow

aura save --intent "Switch retry_logic to exponential backoff to respect upstream rate limits"

Snapshots every modified file, logs the intent, runs the pre-commit hook, commits, and pushes. The pre-commit hook parses both the intent and the AST diff. If the intent says "exponential backoff" but the diff only touches logging code, the commit is flagged as Intent Poisoning and (in strict mode) rejected. Use aura status to see flagged commits.

2. Saving without pushing

aura save --intent "WIP: refactor auth module, not ready for team" --no-push

Keeps the commit local. Nothing lands on the Mothership, so teammates will not see your function changes via aura pull. Useful when you are mid-refactor and want a local checkpoint without broadcasting half-done work.

3. Saving a subset of files

aura save --paths src/auth/ src/session/ --intent "Extract session validation out of auth.rs"

Only files under the listed paths are snapshotted and staged. Everything else in the working tree is left untouched — it is not committed and not stashed. This is the closest Aura analog to git add -p, but operating at the file level.

4. Dry-running a complex save

aura save --dry-run --intent "Rename User to Account throughout the codebase"

Output:

aura save (dry-run)

Would snapshot 14 files
Would log intent: "Rename User to Account throughout the codebase"
Would commit 47 AST changes:
  renamed  fn User::new -> Account::new
  renamed  fn User::validate -> Account::validate
  modified fn SessionStore::get_user
  modified fn api::users::handler
  ... (43 more)
Would push to mothership:   origin-mothership
Would push to git remote:   origin (branch: feat/account-rename)

No changes written.

The dry-run is cheap — it reuses the current AST index and does not invoke the hook.

5. Amending the previous save

aura save --amend --intent "Rename User to Account (also update integration tests)"

Rolls the new changes into the previous commit, rewrites the intent, and re-runs the pre-commit hook against the combined diff. The existing Mothership push is superseded by a new one tagged with the same save_id; teammates who already pulled will receive a corrective update on their next aura pull.

Exit Codes

| Code | Meaning | | --- | --- | | 0 | Save completed successfully (commit created, push attempted if applicable). | | 1 | Generic failure (I/O error, lock contention, working tree dirty for an unexpected path). | | 2 | Pre-commit hook rejected the save — intent mismatch or layer violation. | | 3 | Mothership unreachable and --strict was set. The local commit was created but the push failed. | | 4 | Strict mode is locked and --no-verify was passed. Save was aborted before staging. | | 5 | Team zone is BLOCKED on one or more included paths. Save was aborted. | | 10 | Nothing to save — working tree is clean. |

Notes

  • Snapshots are always taken, even if the save later fails. Use aura snapshot list to see them and aura rewind to recover.
  • Intent is mandatory in strict mode. When strict_mode is on (see aura status), omitting --intent causes exit 2.
  • Mothership push is best-effort by default. If the Mothership is down, the local Git commit still succeeds and the function bodies are queued locally; the next successful aura push or aura save will drain the queue.

The pre-commit hook in detail

Every aura save invokes a pre-commit hook that runs three checks before the commit is allowed to land.

The first check is intent match. The staged AST diff is summarized into a list of verbs (added, removed, modified, renamed) and noun-phrases (function names, module names, type names). The intent string is parsed for its own verbs and noun-phrases. If the overlap is below a threshold, the save is flagged. The threshold is deliberately generous; intent text does not need to enumerate every change, only describe the reason. A save that says "fix the rate limiter" but only adds logging in an unrelated module will fail. A save that says "fix the rate limiter" and modifies the rate limiter and also touches a caller to adapt to its new signature will pass.

The second check is layer violations. Aura's repository configuration can declare architectural layers (e.g. http may call service, service may call repo, repo may not call http). If your save introduces an edge that violates the declared layering, the hook rejects the save with a pointer to the offending call site.

The third check is delete-without-reason. Any function removed by the save must be explained — either by the intent text mentioning it, or by the intent being one of the reserved verbs (remove, delete, drop, retire). An accidental deletion rarely says "delete X"; this check catches most of them.

All three checks can be disabled individually in aura.toml under [save.hook], but when strict mode is locked, local disabling has no effect.

Relationship to the underlying Git commit

aura save still produces a real Git commit. The commit message is composed from the intent text plus a structured footer that Aura can re-parse later:

Switch retry_logic to exponential backoff to respect upstream rate limits

Aura-Save-Id: sv_019abc...
Aura-Intent-Hash: 7c3e...
Aura-Nodes-Modified: 3
Aura-Nodes-Added: 0
Aura-Nodes-Removed: 0

Stripping the footer gives you a normal commit message for tools that do not understand Aura. The save id is the stable handle you pass to aura rewind --to, aura diff, and aura trace.

Interaction with agents

When an AI agent (Claude, Gemini, Cursor, etc.) authors a save, the agent field in the intent record is populated automatically from the MCP session. This makes agent-authored changes auditable: aura trace --authors claude-opus-4.6 isolates everything produced by a specific model across the project's history. Teams use this for review sampling, regression analysis, and for tuning their prompts.

Agents are expected to log intent before calling aura save, not as part of it. The separate aura log-intent call gives the pre-commit hook something concrete to compare against; a save without a prior intent call will prompt the agent for one.

Tips

  • Write the intent for a future reader, not for the hook. A good intent answers why, not what. The diff shows the what.
  • Save often, push less. aura save --no-push gives you cheap checkpoints without broadcasting.
  • Do not batch unrelated changes. Two intents in one save is a code smell; the hook will often catch it as a mismatch.
  • After a conflict resolution, save each side separately if the conflict had semantically different causes on each side. The resulting trace is much easier to read.

See Also

  • aura push — push only, without creating a new commit
  • aura pull — pull teammate function changes
  • aura status — see tracked nodes and pending saves
  • aura rewind — surgically revert a function from a save snapshot
  • aura diff — preview the AST changes a save would record