Skip to main content

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 --yes refuses 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> — never git add -A / git add .
  • git commit -m <message> — hooks are never bypassed
  • (future) git commit --amend — gated behind a typed yes

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

  1. 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.
  2. The bundle goes to DeepSeek with a Conventional Commits system prompt; the model returns {"groups": [...]}.
  3. ncomm validates that the union of group files == the set of changed files.
  4. For each approved group: git add <its files> then git 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ncomm-0.2.0.tar.gz (48.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ncomm-0.2.0-py3-none-any.whl (29.6 kB view details)

Uploaded Python 3

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

Hashes for ncomm-0.2.0.tar.gz
Algorithm Hash digest
SHA256 ee0636b95f9cddcebed65d601c54b99a79d325f7cb91418037822159642ecec8
MD5 a988be4fca966e224d5bdd7b3104fd2f
BLAKE2b-256 85f5fd725edd07dc0d878967f779438b2e72eafeb2c06f2c6c567f8ae8c86f24

See more details on using hashes here.

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

Hashes for ncomm-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5b78aead8e15f469e28b1bb2118a79cb2fe8f724926474ff41ea255da9699ce0
MD5 d5ba66697f813d655bd7eaf0663c5785
BLAKE2b-256 1a8339f6c6c5bb4df7a326c0a469794b24f8218031eb4422c4fbe31adcfcb269

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page