Smart git auto-commit: deterministic gates decide what may enter history; the LLM only writes messages and researches unknown paths — and never blocks a commit.
Project description
smart-autocommit (sac)
Smart git auto-commit. Deterministic rules decide what may enter your history; the LLM only writes the commit message and researches unfamiliar paths — and it never blocks a commit.
Traditional autocommit (cron + git add -A, or a hand-maintained allowlist) has
two chronic problems:
- A static allowlist rots. The moment your repo layout changes you must hand-edit the list — miss one and it isn't backed up, add one too many and it's noise.
add -Ais reckless. It rakes dependency dirs, caches, nested repos, and orphan data straight into history — and git history is a one-way door; you can't fully delete it.
sac replaces the allowlist with a controlled add -A behind six deterministic
gates, then hands the two judgement-heavy, fault-tolerant jobs (writing the message,
classifying an unknown path) to an LLM that is always optional.
tracked changes ─┐
├─▶ 6 deterministic gates ─▶ git commit ─▶ git push
untracked entries┘ (zero LLM) ▲
│ commit message: LLM → template → auto:
unknown top-level paths ──▶ research (LLM) ──▶ suggestion + warning (never auto-applied)
Why it's safe
- The LLM never blocks a commit. Any LLM/network/timeout/error silently degrades to
the pure deterministic path. A global off switch (
message.enabled/research.enabledfalse) returns you to rules-only. - Unknown paths default to excluded, not included. A brand-new top-level directory is held back and flagged — never auto-committed into history.
- The LLM only ever sees
--stat/--name-status(filenames + add/del counts), never the diff body — so secret contents can't leak into a message or be sent out. - Gates are directory-level, not single-file — because real junk is thousands of small files.
- Push never
--forces. A diverged remote keeps your local commit and asks for a human. - Push allowlist. Set
push_allowed_hostsand sac refuses to push anywhere else — a secret-bearing config repo can't be pushed to the wrong remote. - Provenance. Every autocommit carries an
auto(sac):subject prefix and anAuto-committed-by:trailer, so it's never mistaken for a human commit ingit log.
The six gates
| # | Gate | What it stops |
|---|---|---|
| 1 | denylist | .gitignore pre-filters junk; an optional engine glob denylist adds defense-in-depth |
| 2 | nested repo skip | a path containing .git would become a gitlink polluting the parent |
| 3 | unknown top-level path | a new top-level segment not in the known set — excluded + researched (the core safety gate) |
| 4 | dir size / file count | a new entry over the size or file-count cap (measured on the entry itself) |
| 5 | sensitive files | only --stat/--name-status ever reach the LLM; sensitive-looking filenames are flagged |
| 6 | bulk delete | too many staged deletions aborts the commit (guards against a wiped directory) |
Install
Requires Python ≥ 3.14 and git. Recommended (isolated, on your PATH):
uv tool install smart-autocommit # or: pipx install smart-autocommit
From a checkout, for system-service hosting:
./install.sh # installs `sac` + writes ~/.config/smart-autocommit/config.json
Use
In-place (like git) — zero registration
cd /any/git/repo
sac --dry-run # show the decisions + message, commit nothing
sac # smart-commit the repo you're standing in
sac init # drop a .smart-autocommit.json so policy travels with the repo
Managed — one config, many repos, unattended
sac --all # process every enabled repo in the central config
sac --repo openclaw-config # just one
sac --all --dry-run # rehearse the whole batch
Run it on a schedule with the systemd user timer in systemd/ (see
ARCHITECTURE.md).
CI / scripts
sac --repo build-artifacts --json # structured result on stdout
echo "exit: $?" # 0 ok · 1 a repo failed a gate · 2 usage/config error
Configure (three layers)
Lowest to highest precedence: built-in defaults → central defaults → repo-local
.smart-autocommit.json → the repo's repos[] entry → CLI flags.
{
"defaults": {
"push": true, "remote": "origin", "branch": "main",
"gates": { "max_dir_size_mb": 5, "max_dir_files": 200, "max_deletes": 20, "denylist": [] },
"message": { "enabled": true, "language": "en", "provider": "default", "timeout": 45 },
"research": { "enabled": true, "provider": "default", "timeout": 120, "skip_on_dry_run": true }
},
"providers": {
"default": { "type": "openai", "base_url": "https://api.openai.com/v1",
"model": "gpt-4o-mini", "api_key_env": "OPENAI_API_KEY" }
},
"repos": [
{ "name": "openclaw-config", "path": "/home/me/.openclaw" }
]
}
If you set nothing, sac builds an OpenAI-compatible provider from the environment
(SAC_API_KEY/OPENAI_API_KEY, SAC_BASE_URL, SAC_MODEL). No key → messages fall
back to a template, and the commit still happens.
Providers are pluggable (base_url + model + apiKey): any OpenAI-compatible
endpoint via openai, the Aliyun bl CLI via bailian, or any command via command.
Unknown-path research uses a coding agent (agent, e.g. pi) or, by default, the same
chat model over read-only evidence the engine gathers. See
config.example.json and ARCHITECTURE.md.
Note: the optional
agentresearch provider runs a real coding agent with file-reading tools, so it is outside the "only filenames reach the LLM" guarantee — it may read file contents while investigating an unknown path. The defaultchatresearcher does not (it only sees metadata the engine gathers). Useagentonly where sending file contents to your model is acceptable.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file smart_autocommit-0.1.0.tar.gz.
File metadata
- Download URL: smart_autocommit-0.1.0.tar.gz
- Upload date:
- Size: 38.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a24dc79f44b3e6022a3ee18f8e1901397604a8b8eb7953af2c02dc05d84d7310
|
|
| MD5 |
89a7d1a7c56eda855136606fbf72e49d
|
|
| BLAKE2b-256 |
5c52d37d0819b22b2ff5c9e5e4f8690ca9e4f341a60b136a9c9cb2c2e00092d7
|
Provenance
The following attestation bundles were made for smart_autocommit-0.1.0.tar.gz:
Publisher:
release.yml on crhan/smart-autocommit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
smart_autocommit-0.1.0.tar.gz -
Subject digest:
a24dc79f44b3e6022a3ee18f8e1901397604a8b8eb7953af2c02dc05d84d7310 - Sigstore transparency entry: 1702547621
- Sigstore integration time:
-
Permalink:
crhan/smart-autocommit@049bca01763a84ed183c6b93a33db869cf5ca4b6 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/crhan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@049bca01763a84ed183c6b93a33db869cf5ca4b6 -
Trigger Event:
push
-
Statement type:
File details
Details for the file smart_autocommit-0.1.0-py3-none-any.whl.
File metadata
- Download URL: smart_autocommit-0.1.0-py3-none-any.whl
- Upload date:
- Size: 38.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
54abcbc40ec24141757ce0a48cb1c1dc64f57318ed8f51a6a3dc0c8db30ff3d9
|
|
| MD5 |
dc435335c9e389ad2d2dcf62089dceaa
|
|
| BLAKE2b-256 |
a38e088bc3c1a3107be91ef20bf21df8725d77eb1f30f0f39a81b3bb6af74522
|
Provenance
The following attestation bundles were made for smart_autocommit-0.1.0-py3-none-any.whl:
Publisher:
release.yml on crhan/smart-autocommit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
smart_autocommit-0.1.0-py3-none-any.whl -
Subject digest:
54abcbc40ec24141757ce0a48cb1c1dc64f57318ed8f51a6a3dc0c8db30ff3d9 - Sigstore transparency entry: 1702547640
- Sigstore integration time:
-
Permalink:
crhan/smart-autocommit@049bca01763a84ed183c6b93a33db869cf5ca4b6 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/crhan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@049bca01763a84ed183c6b93a33db869cf5ca4b6 -
Trigger Event:
push
-
Statement type: