Turn a working tree into well-formed Conventional Commits — group changes, review, commit. AI-assisted.
Project description
ncomm
One command, well-formed commits. The natural sibling of nlsh: nlsh proposes a command, ncomm proposes your commits.
ncomm reads your working tree, asks an LLM (DeepSeek) to split the changes into one or more Conventional Commits, shows you each proposed commit, and commits the ones you approve.
$ ncomm
working tree on feature/x
st file ±
M src/auth/oauth.py +142 -4
A src/auth/__init__.py +3
?? tests/test_oauth.py new
M pyproject.toml +1 -1
Proposed 2 commit(s).
commit 1/2 feat(auth): add OAuth2 login flow
Wires the OAuth2 device-code grant into the login view.
files: src/auth/oauth.py, src/auth/__init__.py, tests/test_oauth.py
Commit this? (y)es (n)o (e)dit (d)iff (r)egroup (q)uit (y): y
✓ a1b2c3d feat(auth): add OAuth2 login flow
At each commit you can press y to accept, n to skip, e to edit the
message in $EDITOR, d to show the actual diff for that group, r to ask
the model to regroup (optionally with a one-line hint like "split tests out"),
or q to stop.
Why
A real working tree is rarely one logical change — it's a feature, a bugfix, and
a dependency bump tangled together. Stuffing them into one commit makes
git bisect, revert, and review harder. ncomm groups them for you, then
commits each group with only its explicit file list.
Install
ncomm ships a uv.lock and a pinned requirements.txt, so you can install
with either uv or pip — whichever your environment prefers.
Option A — uv (recommended)
git clone https://github.com/decajoin/ncomm
cd ncomm
uv sync # creates .venv, installs pinned runtime deps from uv.lock
uv run ncomm --version
Or install it as a global tool:
uv tool install ncomm
Option B — pip
Runtime dependencies are pinned in requirements.txt (runtime only — no
pytest/ruff), so a plain pip install is reproducible without uv:
git clone https://github.com/decajoin/ncomm
cd ncomm
python -m venv .venv && source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -r requirements.txt # pinned runtime deps
pip install -e . # install ncomm itself (editable)
ncomm --version
Or from PyPI:
pip install ncomm
Regenerating the lockfile / requirements
Both files are kept in sync. If you change pyproject.toml:
uv lock # refresh uv.lock
uv export --format requirements-txt --no-hashes --no-emit-project --no-dev \
-o requirements.txt # refresh runtime-only requirements.txt
First-time setup
ncomm config set-key # paste your DeepSeek API key (stored mode 0600)
ncomm config show
Or via env: export DEEPSEEK_API_KEY=sk-...
Usage
ncomm # group, review each commit, commit approved ones
ncomm -y # commit all proposed groups without prompting
ncomm -n # dry run: show proposed commits, commit nothing
ncomm --no-group # force a single commit covering all changes
ncomm --staged # one commit for what you've already `git add`-ed
ncomm --pro # use the stronger model for this run
ncomm -m <model> # override the model id
ncomm --lang en # messages in English (default: en; use zh for Chinese)
ncomm --no-scan # skip the secret/debug pre-commit scan
ncomm --allow-secrets # don't let a secret finding block --yes
# Path filtering (fnmatch globs, repeatable) — leave WIP out of the commit:
ncomm --only 'src/auth/**' --only 'tests/test_auth*' # only this slice
ncomm --exclude '*.lock' --exclude 'tmp/*' # everything but these
--only / --exclude filter the changed set before grouping, so excluded
files stay untouched in your working tree and never need to be committed.
--staged makes ncomm write a single commit from the index exactly as you
staged it (it never re-stages, so a git add -p selection is preserved) — use
it when you've already curated the commit yourself and just want the message.
Pre-commit guardrails
Before anything is committed (or sent to the model), ncomm scans the added lines of your diff — locally, no network — for:
- secrets: AWS / GitHub / Slack / Google keys, private-key blocks, JWTs,
password = "…"-style assignments, plus a Shannon-entropy check for random custom tokens. High-confidence (structural) hits are shown in red; a group touching one defaults its prompt to no, and--yesrefuses to commit it unless you pass--allow-secrets. Entropy hits are yellow "maybe" advisories. - debug leftovers:
breakpoint()/pdb,console.log,debugger,binding.pry,dbg!— shown in yellow.
If a secret is found in interactive mode, ncomm also asks before sending the diff to the model, so a leaked credential can be pulled before it leaves the box.
ncomm also notices untracked junk (caches, build dirs, logs, .env, compiled
files) and offers to add it to .gitignore. The obvious cases are matched by
rules; project-specific artifacts (model checkpoints, data dumps) are spotted by
asking the model about the filenames (never their contents). You confirm
before anything is written, and source files / committed configs are never
suggested.
Safety contract
ncomm only ever runs three things on your behalf:
git add <explicit paths>— nevergit add -A/git add .git commit -m <message>— hooks are never bypassed- (future)
git commit --amend— gated behind a typedyes
It never pushes, force-pushes, resets, or rebases. After committing, review
with git log and push when you're ready. The only other file it may write is
.gitignore — and only the patterns you approve at the prompt.
If the model's file assignment doesn't cover every changed file exactly, ncomm
aborts rather than commit a wrong grouping — re-run, or use --no-group.
How it works
git diff HEAD+ untracked file contents are gathered into one diff bundle, with per-file patches truncated (head + tail) so a generated/lockfile doesn't blow the token budget.- The bundle goes to DeepSeek with a Conventional Commits system prompt; the
model returns
{"groups": [...]}. - ncomm validates that the union of group files == the set of changed files.
- For each approved group:
git add <its files>thengit commit -m <msg>.
Configuration
~/.config/ncomm/config.toml (or $NCOMM_CONFIG):
api_key = "sk-..."
base_url = "https://api.deepseek.com"
model = "deepseek-v4-flash"
learn_style = true # show recent commits to the model to match repo style
With learn_style on (the default), ncomm passes your last few commit subjects
to the model so generated messages follow the repo's existing conventions
(type/scope habits, language, casing). Disable per run with --no-style.
Env overrides: DEEPSEEK_API_KEY / NCOMM_API_KEY, DEEPSEEK_BASE_URL,
NCOMM_MODEL, NCOMM_LANG, NCOMM_LEARN_STYLE.
License
MIT
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 ncomm-0.2.0.tar.gz.
File metadata
- Download URL: ncomm-0.2.0.tar.gz
- Upload date:
- Size: 48.6 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ee0636b95f9cddcebed65d601c54b99a79d325f7cb91418037822159642ecec8
|
|
| MD5 |
a988be4fca966e224d5bdd7b3104fd2f
|
|
| BLAKE2b-256 |
85f5fd725edd07dc0d878967f779438b2e72eafeb2c06f2c6c567f8ae8c86f24
|
File details
Details for the file ncomm-0.2.0-py3-none-any.whl.
File metadata
- Download URL: ncomm-0.2.0-py3-none-any.whl
- Upload date:
- Size: 29.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: uv/0.11.23 {"installer":{"name":"uv","version":"0.11.23","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5b78aead8e15f469e28b1bb2118a79cb2fe8f724926474ff41ea255da9699ce0
|
|
| MD5 |
d5ba66697f813d655bd7eaf0663c5785
|
|
| BLAKE2b-256 |
1a8339f6c6c5bb4df7a326c0a469794b24f8218031eb4422c4fbe31adcfcb269
|