smart-commit-guard
Stop real secrets (API keys, passwords, private keys, tokens, connection strings) from being committed.
Deterministic rules catch the obvious cases. A small decision model judges the ambiguous ones, such as
DB_PASS = "Winter2026!Admin" (real) versus API_KEY = "your-api-key-here" (placeholder). It runs as a git
pre-commit hook and as a CI step. Zero runtime dependencies, Python 3.12+.
Quickstart
Four steps. Steps 1 to 3 are once per machine; 3 is once per repository.
1. Pick a model. The default is a local model, jevk5:4b, served by ollaya at http://localhost:11435: run
ollaya pull jevk5:4b and ollaya serve, and nothing else is needed. You can use a hosted model instead (for example
TypeSafe Jev), or no model at all (rules only). How to set up each: docs/models.md.
2. Install the tool, or run it without installing through uvx (pin a range in hooks and CI,
since uvx caches releases):
uv tool install smart-commit-guard # or: pipx install smart-commit-guard
uvx --from 'smart-commit-guard>=0.2,<0.3' smart-commit-guard doctor # no install
3. Write your settings file (which model to use; it lives outside the repos, in ~/.config/smart-commit-guard/config.jsonc),
then check that everything answers:
smart-commit-guard config init # a commented template: the local default, and the hosted settings as comments
smart-commit-guard doctor # hooks, rules, settings file and model
With the default local model you can skip config init; doctor still tells you whether the model answers.
4. Add the git hooks to a repository. A committed .githooks/ gives everyone who clones the repo the gate:
smart-commit-guard install-hook --shared # or uvx smart-commit-guard install-hook --shared
git add .githooks .gitattributes && git commit -m "Add the smart-commit-guard hooks"
Or protect only your own clone with smart-commit-guard install-hook. It writes a pre-commit hook (the staged diff) and a
commit-msg hook (the message). Details, an existing hook (--chain) and a throwaway-repo test: docs/hooks.md.
Optional, per repository:
.secret-guard.toml: files to skip, findings to allow, a baseline for an existing repo: docs/project-config.md.- CI, the backstop for
--no-verify(GitHub Actions, SARIF, commit messages, a hosted model in CI): docs/ci.md.
How it works
- Only added lines are scanned. Binaries and
.env.exampleare skipped. Lockfiles and generated files (.min.js,.map) only get the high-confidence rules below, since they can carry inlined keys oruser:token@URLs but are too noisy for model candidates. - High-confidence rules (private keys, AWS keys, GitHub, GitLab, Slack, Stripe secret keys, Google, Anthropic/OpenAI-style, npm, PyPI, Hugging Face, SendGrid, Shopify, DigitalOcean and similar token shapes, chat webhook URLs, connection strings with a password) block immediately, with no model call, outside test/doc/example paths.
- A staged environment file (
.env,.env.local,prod.env; not.env.example/.sample/.template) blocks as a whole, with no model call, as long as it has any non-comment line. Add it to.gitignore, or allowlist it if intentional. - A staged file whose name marks it as sensitive blocks as a whole, with no model call, binaries included: SSH
private keys (
id_rsa,id_ed25519...), key stores (.p12,.pfx,.jks,.keystore,.ppk), KeePass databases,.netrc,.pgpass,.pypirc,.htpasswd,.git-credentials,.aws/credentials,.docker/config.json,.kube/config,kubeconfig, Terraform state and.tfvars,credentials.json, Googleclient_secret*.jsonand service-account keys, iOS provisioning profiles,.vault-token,.cargo/credentials,.gem/credentials,.composer/auth.jsonand.config/gh/hosts.yml. Names containingexample,sample,templateordefaultsare exempt. Public files (id_rsa.pub,.pem/.crtcertificates) are not matched by name; a private key inside them is still caught by content. - Candidates (
password = "...",Bearertokens,-pSECRETCLI flags, unquoted YAML values, high-entropy literals) go to the model, one per request. Obvious placeholders (changeme,your-...,xxxx) are dropped first. - The policy lives in code, not in the model: the model's probability
pblocks atp >= 0.5and warns atp >= 0.4(configurable). - If the model is unreachable: rule hits still block; model-only candidates warn and allow.
Stripe publishable keys (pk_live_..., pk_test_...) are public identifiers and are never flagged.
A base64 token that decodes to a known secret shape (a Kubernetes Secret, an encoded key) is reported as that rule, marked
(base64-encoded).
Findings never print the secret, only a shape-preserving mask such as sk_live_A9a9A9a9.... Every secret on a line is
masked, and so is any other long random-looking token.
The scan does not depend on your git configuration: external diff tools, textconv, diff.noprefix/mnemonicPrefix,
diff.relative and binary/-diff attributes are overridden, so they cannot hide a file from the gate.
Exit codes: 0 allowed (warnings may print), 1 blocked by a finding, 2 tool or configuration error (an unexpected
crash is also 2, with the details on stderr when SMART_COMMIT_GUARD_DEBUG=1).
Commands
| Command | Purpose |
|---|---|
smart-commit-guard scan --staged |
the staged diff (what the hook runs) |
smart-commit-guard scan --diff RANGE |
a revision range, for CI (origin/main...HEAD) |
smart-commit-guard scan --files PATH... |
whole files (--files - reads NUL-separated paths from stdin) |
smart-commit-guard scan --all |
every tracked file (git ls-files) |
smart-commit-guard scan --message FILE |
a commit message (what the commit-msg hook runs); --text - scans stdin the same way |
--messages |
with --diff: also scan the message of every commit in the range |
--format text|json|sarif, --json, --no-model |
output format (--json is --format json); rules only (no model call) |
--config-from REF |
read .secret-guard.toml from a revision such as origin/main, not the working tree |
--baseline FILE |
ignore the findings recorded in a baseline file |
smart-commit-guard baseline create [-o FILE] [--no-model] |
record the current findings (default .secret-guard-baseline.json) |
smart-commit-guard allowlist migrate |
rewrite v1 fingerprints in .secret-guard.toml to v2 |
smart-commit-guard install-hook [--force] |
per-clone hook in the effective hooks directory |
smart-commit-guard install-hook --shared |
committable .githooks/pre-commit and commit-msg plus core.hooksPath |
smart-commit-guard install-hook --chain |
keep an existing hook as pre-commit.local and run it first |
smart-commit-guard doctor |
verify the hooks, the rules, your settings file and the model |
smart-commit-guard config init [--force] / config path |
write a commented template of your settings file / print where it is |
--version |
print the version |
More
| docs/models.md | local and hosted models, the settings file, environment variables, other models, privacy |
| docs/hooks.md | the shared hook, --chain, the pre-commit framework, testing the hook |
| docs/project-config.md | .secret-guard.toml, allowlist, baseline, SKIP_SECRET_GUARD, the skips log |
| docs/ci.md | GitHub Actions, SARIF, commit messages, hosted model in CI, push events |
| specs/secret-scan/SPEC.md | the behaviour contract |
| specs/next-version/MODEL_COMPARISON.md | model comparison report |
Development
uv sync
uv run task setup-hooks # dogfood the shared hook
uv run task test
uv run ruff check . && uv run ty check
python scripts/pin_actions.py # pin GitHub Actions to commit SHAs (needs github.com; --check for CI)
Behavior is specified in specs/secret-scan/SPEC.md.
Limitations
- Scans added lines only, not git history. If a secret was committed, rotate it.
- Not a replacement for server-side scanning such as GitHub push protection; use both.
- PII detection is out of scope for now.
License
MIT
Metadata
Release files for smart-commit-guard 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| smart_commit_guard-0.2.0.tar.gz | 38.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| smart_commit_guard-0.2.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 84.4 kB
Release files / smart_commit_guard-0.2.0.tar.gz
| Download URL | smart_commit_guard-0.2.0.tar.gz |
|---|---|
| Size | 38.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5519007ab7c48fe3b9a9dc8b3c1f8a453437514fd93fb8a9511eff62f64e49fb
|
|
BLAKE2b-256 checksum How to use checksums |
05d93f7147a64fb259eb55dad621e74c2c94a151a6ea66574a15613e09a4bc9f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency logRelease files / smart_commit_guard-0.2.0-py3-none-any.whl
| Download URL | smart_commit_guard-0.2.0-py3-none-any.whl |
|---|---|
| Size | 45.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
2b6af4f06cb38c5088ba07ccbd613d10f4a14929bcaa72f3060a52cc40a88f94
|
|
BLAKE2b-256 checksum How to use checksums |
987b86ac0528ce592a5e987840dffdd5a7d0a900b855a324319aa3cc9aa16d38
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 6, 2026.
Transparency log