AI-assisted Git utility that turns staged changes into validated, atomic Conventional Commits. Generated plans are reviewed interactively before committing by default, and generated commits are signed by default.
After native Rust build/test execution and after evidence consumers and
uploads have finished, run bash scripts/ci-clean-cargo.sh inside the
declared nix develop shell. The cleanup uses Cargo's package-scoped
cargo clean --package git-autocommit with an explicit target directory
inside the current worktree. It is a no-op if no local target exists,
rejects symlinked/unexpected target paths, and never follows an external
CARGO_TARGET_DIR. It also invokes
cargo llvm-cov clean --workspace for an existing task-owned
target/llvm-cov-target/. Both that directory and
target/llvm-cov/ are preflight-checked against symlink or unusual file
modes, and all Cargo/coverage environment overrides are bound to this
worktree. It does not clear dependency registries, system caches, Nix
store outputs, release archives in dist/, or other worktrees.
Ordinary CI runs this finalizer after uploading coverage and validating the final release/Nix package. Preserve test logs and evidence independently if earlier stages fail; the finalizer reports its own result and never overrides an earlier job failure. Tagged release builds have a separate multi-platform artifact-consumer boundary and are not covered by this ordinary CI finalizer.
Most AI commit tools generate a message for one commit. git-autocommit instead plans a sequence of commits while keeping repository mutation deterministic:
- groups whole staged files into coherent commits;
- validates complete, bounded Conventional Commit messages;
- requires every staged path exactly once;
- rejects invented, omitted, or duplicated paths;
- reviews the validated plan before repository mutation by default;
- verifies the final commit tree matches the captured staged tree;
- updates
HEADonly if bothHEADand the index are unchanged.
The model proposes grouping and messages. Human review decides whether a valid plan should proceed, and Git plus deterministic validation control what is committed.
flowchart LR
A[Staged index] --> B[Capture HEAD and staged tree]
B --> C[Build bounded staged context]
C --> D[Request commit plan]
D --> E[Validate messages and paths]
E --> F{Review}
F -->|commit| G[Build commits with temporary indexes]
F -->|retry| D
F -->|abort| X[Exit without mutation]
G --> H[Verify final tree]
H --> I[Compare-and-swap HEAD]
The configured model is asked only to propose commit messages and group repository-root-relative staged paths. It may return invalid output, but plans that invent, omit, or duplicate paths are rejected before any repository mutation. The model cannot modify file contents, execute Git, or update repository refs.
Predictive commit-structure research, if pursued, is constrained to non-authoritative advisory signals and deterministic fallback behavior; see docs/predictive-intelligence.md.
The returned plan must:
- be valid JSON;
- contain between one and
max_commitsentries; - use a strictly parsed Conventional Commit subject of at most 72 characters;
- keep the complete message within 4096 bytes and free of control, bidirectional, or zero-width formatting characters;
- use only an optional prose body separated by one blank line, with no trailer-like metadata;
- assign every staged path to exactly one commit.
Interactive review is enabled by default. After a plan passes deterministic validation, git-autocommit displays the complete commit sequence and waits for an explicit action:
[c] commit [r] retry [a] abort
>
Pressing Enter alone does not approve the plan.
ccommits the displayed plan.rrejects the valid plan and asks the model for an alternative plan against the same captured staged snapshot. The alternative must pass the same deterministic validation and automatic one-repair limit before it is shown again.aexits successfully without creating commits or movingHEAD.
Before retrying or committing, git-autocommit verifies that both HEAD and the staged tree still match the captured snapshot. A concurrent change therefore fails closed instead of applying a stale reviewed plan.
Review requires an interactive standard input. Non-interactive callers must make the trust decision explicit with --no-review, GIT_AUTOCOMMIT_REVIEW=false, or review_before_commit = false. --dry-run, --show-prompt, and --show-config do not require an interactive terminal because they cannot create commits.
git-autocommit captures HEAD and the staged tree before contacting the model. It constructs each approved commit from that captured tree through temporary Git indexes, then verifies that the generated commit chain reproduces the captured staged tree exactly.
Before updating HEAD, it acquires Git's worktree-specific index lock, then rechecks the live HEAD and staged tree while holding that lock. The lock remains held through Git's expected-old-value compare-and-swap ref update, so cooperating Git index writers cannot enter between validation and the HEAD move, while concurrent ref changes still cause the operation to fail. Unstaged worktree content is never committed.
Generated commits are signed by default using Git's configured signing mechanism. Disable signing only when required:
git autocommit --no-signor:
sign_commits = falseSigning authenticates the configured Git identity. Before signing, git-autocommit validates the complete generated message, rejects trailer-like attribution or policy metadata, and bounds its size. Signing still does not prove that the model's grouping or prose are correct.
The configured OpenAI-compatible endpoint receives:
- staged path names and status;
- staged diff statistics;
- staged per-file diff excerpts;
- limited staged-file context for very small source/config diffs;
- the commit-planning prompt.
By default, diff evidence is adaptive rather than using one large fixed allowance. The total staged textual diff selects an evidence budget of 12 KB for small changes, 32 KB for medium changes, or at most 64 KB for large changes. The existing weighted per-file allocator then distributes that budget, favoring source/config changes over generated files and lockfiles; binary contents are omitted. Explicit GIT_AUTOCOMMIT_MAX_DIFF_BYTES or max_diff_bytes configuration disables the adaptive diff default and uses the requested fixed limit instead.
After all placeholders are expanded, the combined system and plan prompt text is bounded by max_prompt_bytes, including path lists, statistics, headings, and custom prompt content. The implicit prompt ceiling is 96 KB. If max_diff_bytes is explicitly increased while max_prompt_bytes remains implicit, the prompt ceiling retains 40 KB of headroom above the explicit diff limit, with a minimum of 96 KB; this preserves compatibility for intentionally high-context configurations. Explicit prompt limits remain authoritative. Oversized prompts are rejected before the endpoint is contacted.
A remote endpoint may receive source code, credentials, or other sensitive staged content. Review the endpoint's transport, access, retention, and training policies before using it with private repositories.
If the first model response fails deterministic plan validation, git-autocommit makes at most one repair request. That request contains the same rendered staged-change prompt plus a bounded JSON-encoded validation error, so the configured endpoint may receive the staged context twice for one planning attempt. The repaired response must pass the same message, path, commit-count, and single-commit validation before any repository mutation. To guarantee that the repair request stays within max_prompt_bytes, 1024 bytes of that limit are reserved for repair metadata; an initial system-plus-plan prompt that does not leave this headroom is rejected before the endpoint is contacted.
Each explicit human retry starts another planning attempt and therefore sends the staged context to the configured endpoint again. The retry prompt states that the previous valid plan was rejected and requests an alternative without embedding the previous model response. A retry is rejected before contacting the endpoint if the added retry instruction would leave insufficient room for the normal repair reserve.
--show-usage reports model-request usage to standard error without changing the commit-plan output on standard output and without making any additional model requests. Usage is accumulated across the initial planning request, an automatic repair request when needed, and any explicit human retries.
When the OpenAI-compatible endpoint includes usage.prompt_tokens, usage.completion_tokens, or usage.total_tokens, the reported fields are summed. Each field also shows how many successful responses supplied that field, so partial usage objects are not mistaken for complete totals. If the endpoint omits usage entirely, git-autocommit reports the request count and states that token counts were not provided; it does not estimate tokens from bytes.
Model usage: 2 requests; 8412 prompt tokens (2/2); 206 completion tokens (2/2); 8618 total tokens (2/2)
Usage reporting is local and opt-in. It is not persisted or exported.
HTTPS is required for every non-loopback model endpoint. Plaintext HTTP is accepted only for the exact hostname localhost or a literal loopback IP address such as 127.0.0.1 or ::1; private-network addresses and alternate hostnames are rejected before a connection is attempted.
base_url must contain only the endpoint origin and optional API path. Embedded credentials, query parameters, and fragments are rejected before connecting. The client appends chat/completions as URL path segments rather than through string concatenation.
Authenticated endpoints can use either GIT_AUTOCOMMIT_BEARER_TOKEN or GIT_AUTOCOMMIT_BEARER_TOKEN_FILE. The variables are mutually exclusive. The file form supports regular files and symlinked mounted secrets, accepts the token with no terminator, one LF, or one CRLF, and enforces a 16 KiB token limit; no other whitespace is trimmed. The credential is sent as a sensitive Authorization: Bearer header and rendered as <redacted> by --show-config, while the configured file path is omitted. Credentials are not accepted through CLI arguments, TOML, or URL user information, and both variables are removed from child Git and signing-process environments. Prefer the file form for mounted secrets and avoid placing direct tokens in shell history.
System and environment proxy settings are disabled for model requests. HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, platform proxy configuration, and their lowercase variants are ignored so staged repository content is sent only to the host named by base_url.
HTTP redirects are disabled. Any 3xx response is rejected rather than forwarding staged repository content to another URL; configure base_url to the final endpoint directly.
The HTTP response body is capped at 256 KiB before JSON deserialization. A declared Content-Length above the limit is rejected before reading the body. Responses without a trustworthy length, including chunked responses, are streamed only through the limit plus one byte and rejected if oversized.
Normal commit hooks are intentionally not run because hooks can mutate content after analysis and invalidate the captured-tree guarantees. Run required formatting, linting, tests, secret scanning, DCO checks, or other policy gates before invoking git-autocommit, or enforce them in CI.
- Git available in
PATH; - Rust and Cargo for source installation;
- an OpenAI-compatible Chat Completions endpoint;
- a model that can reliably return strict JSON;
- working Git commit signing unless signing is disabled.
For a durable installation, consume a reviewed release tag rather than floating main. To install v0.3.1:
nix profile install github:ryjen/git-autocommit/v0.3.1The Nix package installs both git-autocommit and git-autocommit(1). Flake-managed hosts should pin the same versioned input and commit the resulting consumer flake.lock; see docs/nix.md and the release/integration contract.
For source development from a repository checkout:
cargo install --path .To install a specific released source revision with Cargo:
cargo install --git https://github.com/ryjen/git-autocommit --tag v0.3.1A floating Git install is appropriate only when deliberately testing current development source:
cargo install --git https://github.com/ryjen/git-autocommitWhen git-autocommit is available in PATH, Git discovers it as a subcommand. The preferred invocation is therefore:
git autocommit <args>Calling the executable directly as git-autocommit <args> is equivalent.
git add src/ tests/
git autocommit
# inspect the validated plan, then choose c, r, or a
git log --show-signature --onelineFor inspection without any commit path:
git autocommit --dry-run--dry-run contacts the model and prints a fully validated plan, but does not prompt, create commits, or move HEAD.
To emit the stable machine-readable plan contract:
git autocommit --dry-run --format jsonTo inspect actual token usage when the endpoint reports it:
git autocommit --dry-run --show-usageFor explicit unattended execution:
git autocommit --no-reviewgit autocommit [OPTIONS]
| Option | Behavior |
|---|---|
--base-url <URL> |
Override the OpenAI-compatible API base URL. |
--model <MODEL> |
Override the model name. |
--timeout <SECONDS> |
Override the HTTP timeout. |
--prompt-dir <PATH> |
Load system.md and plan.md from another directory. |
--single |
Require exactly one commit containing every staged path. |
--no-single |
Disable single-commit mode configured in TOML or the environment. |
--sign |
Enable commit signing, overriding lower-precedence configuration. |
--no-sign |
Disable commit signing, overriding lower-precedence configuration. |
--review |
Require interactive plan review before committing; this is the default. |
--no-review |
Explicitly allow a validated plan to commit without interactive review. |
--dry-run |
Contact the model, validate the plan, and print it without creating commits. |
--format <FORMAT> |
Select validated-plan output (human or json); JSON requires --dry-run. |
--show-usage |
Print accumulated model request/token usage to stderr; makes no additional requests. |
--show-prompt |
Render prompts from staged content and exit without contacting the model. |
--show-config |
Print resolved configuration and exit before reading staged changes. |
--single and --no-single, --sign and --no-sign, and --review and --no-review are mutually exclusive pairs.
Create .git/autocommit.toml in the repository:
base_url = "http://127.0.0.1:8000/v1"
model = "dubnium-local"
timeout_seconds = 120
# max_diff_bytes = 64000
# max_prompt_bytes = 96000
max_commits = 8
single_commit = false
sign_commits = true
review_before_commit = true
# prompt_dir = "/home/me/.local/share/git-autocommit"Leave max_diff_bytes unset to use adaptive 12/32/64 KB evidence budgeting. Setting it explicitly selects a fixed evidence limit. Leave max_prompt_bytes unset to use the default prompt policy described above.
Configuration precedence is:
CLI > GIT_AUTOCOMMIT_* environment variables > .git/autocommit.toml > defaults
| Setting | CLI | Environment | TOML | Default |
|---|---|---|---|---|
| API base URL | --base-url |
GIT_AUTOCOMMIT_BASE_URL |
base_url |
http://127.0.0.1:8000/v1 |
| Model | --model |
GIT_AUTOCOMMIT_MODEL |
model |
dubnium-local |
| Bearer token | — | GIT_AUTOCOMMIT_BEARER_TOKEN |
— | unset |
| Bearer token file | — | GIT_AUTOCOMMIT_BEARER_TOKEN_FILE |
— | unset |
| Timeout | --timeout |
GIT_AUTOCOMMIT_TIMEOUT |
timeout_seconds |
120 seconds |
| Prompt directory | --prompt-dir |
GIT_AUTOCOMMIT_PROMPT_DIR |
prompt_dir |
platform-local data directory |
| Maximum diff bytes | — | GIT_AUTOCOMMIT_MAX_DIFF_BYTES |
max_diff_bytes |
adaptive 12000 / 32000 / 64000 |
| Maximum prompt bytes | — | GIT_AUTOCOMMIT_MAX_PROMPT_BYTES |
max_prompt_bytes |
96000 implicit ceiling* |
| Maximum commits | — | GIT_AUTOCOMMIT_MAX_COMMITS |
max_commits |
8 |
| Single-commit mode | --single / --no-single |
GIT_AUTOCOMMIT_SINGLE_COMMIT |
single_commit |
false |
| Sign commits | --sign / --no-sign |
GIT_AUTOCOMMIT_SIGN_COMMITS |
sign_commits |
true |
| Review before commit | --review / --no-review |
GIT_AUTOCOMMIT_REVIEW |
review_before_commit |
true |
* If only max_diff_bytes is explicitly raised, the implicit prompt ceiling becomes at least max_diff_bytes + 40000 bytes so intentional high-context configurations keep compatible headroom.
The legacy DUBNIUM_LOCAL_LLM_BASE_URL and DUBNIUM_LOCAL_LLM_MODEL variables remain supported as fallback aliases.
Use git autocommit --show-config to inspect the resolved configuration. Because --show-config intentionally exits before reading staged changes, it reports the default adaptive diff ceiling (64000) rather than the per-invocation 12/32/64 KB tier. A configured bearer credential appears only as <redacted>; token-file paths are not printed.
For an authenticated endpoint, provide either the token directly:
GIT_AUTOCOMMIT_BEARER_TOKEN="$(cat /secure/path/token)" git autocommit --dry-runor point to a mounted credential file:
GIT_AUTOCOMMIT_BEARER_TOKEN_FILE=/run/secrets/model-token git autocommit --dry-runDo not set both variables. Token files must resolve to regular files, may end in one LF or CRLF, and may contain at most 16 KiB before that optional terminator. Additional or embedded whitespace is rejected.
The binary includes built-in prompts. To override them, provide both files in the configured prompt directory:
system.md
plan.md
The default directory is typically:
~/.local/share/git-autocommit
The custom plan.md must contain all required tokens:
{{grouping_instruction}}{{max_commits}}{{files_json}}{{context}}
If either override file is absent, the built-in prompt pair is used. Custom prompts can request narrower messages, but generated output must still pass the built-in message policy.
- Grouping is file-level: one file cannot be split across multiple generated commits.
- Only staged state is considered; unstaged changes are ignored.
- Rename detection is disabled, so renames appear to the model as deletion/addition changes.
- Default diff evidence is adaptively truncated to 12, 32, or 64 KB; configure
max_diff_bytesexplicitly when a repository genuinely needs a larger fixed context window. - The complete expanded prompt must fit within
max_prompt_bytes, with 1024 bytes reserved for bounded repair metadata; repositories with unusually many or long paths may require a larger ceiling or a smaller staged set. - The endpoint must implement the expected OpenAI Chat Completions response shape.
- Token usage is available only when the endpoint returns OpenAI-compatible
usagefields; missing fields are reported as unavailable rather than estimated. - Interactive review can commit, retry, or abort a complete validated plan; it does not provide an inline plan editor.
- Commit hooks do not run.
- Model quality still affects grouping and message quality; review the generated plan before committing.
| Error | Likely cause |
|---|---|
no staged changes |
The Git index is empty. Stage changes with git add. |
review is enabled but stdin is not interactive... |
Default review cannot obtain an explicit decision from this caller. Run interactively or explicitly disable review with --no-review, GIT_AUTOCOMMIT_REVIEW=false, or review_before_commit = false. |
local AI unavailable |
The endpoint is unreachable or the request timed out. |
local AI returned an error |
The endpoint returned a non-success HTTP status. |
plaintext HTTP model endpoints are allowed only on loopback... |
A non-loopback base_url uses HTTP; configure HTTPS or use an exact loopback endpoint for local development. |
local AI base_url must not include... |
base_url contains embedded credentials, a query string, or a fragment; configure only the endpoint origin/path and use one bearer-token environment variable when authentication is required. |
GIT_AUTOCOMMIT_BEARER_TOKEN and GIT_AUTOCOMMIT_BEARER_TOKEN_FILE cannot... |
Both credential sources are configured; unset one of them. |
GIT_AUTOCOMMIT_BEARER_TOKEN must... |
The direct token is empty, exceeds 16 KiB, contains whitespace or non-ASCII characters, is not UTF-8, or cannot form a valid HTTP header value. |
unable to read GIT_AUTOCOMMIT_BEARER_TOKEN_FILE |
The configured credential file is missing or unreadable. |
GIT_AUTOCOMMIT_BEARER_TOKEN_FILE must... |
The file path is empty, does not resolve to a regular file, or its content is empty, exceeds 16 KiB, is invalid UTF-8, contains unsupported whitespace or non-ASCII characters, or cannot form a valid HTTP header value. |
local AI endpoint returned HTTP redirect... |
base_url points to a redirecting URL; configure the final endpoint directly. |
rendered prompt is ... exceeding the ...-byte limit |
Expanded prompt text, including metadata and custom prompts, exceeds max_prompt_bytes. |
rendered prompt is ... leaving fewer than the ...-byte repair reserve |
The initial or retry prompt fits the hard limit but leaves insufficient headroom for the bounded repair request; reduce staged context or increase max_prompt_bytes. |
local AI response exceeds the ...-byte limit |
The endpoint returned more than the fixed 256 KiB safety ceiling. |
local AI did not return a JSON commit plan |
The first response was invalid JSON and the repair request also failed validation or could not be completed. |
commit plan entry ... invalid Conventional Commit message |
A response violated the deterministic message policy; the error now identifies the rejected rule. |
commit plan ... paths |
A response omitted, invented, or duplicated staged paths. |
local AI repair request failed after invalid commit plan |
The first plan was invalid and the single repair request could not be completed. |
local AI returned an invalid commit plan after one repair attempt |
Both the original response and the single repaired response failed deterministic plan validation. |
HEAD changed... |
Another process or user moved HEAD during planning or review. |
staged index changed... |
The index changed while the model request or review was in progress. |
unable to lock staged index... |
Another Git process holds or is creating the index lock; let it finish and retry. |
| Git signing failure | Configure Git signing or rerun with --no-sign. |
cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --all-features
cargo build --releaseLicensed under the Apache License 2.0. See LICENSE.