Goodcommit is a plugin-first CLI for generating structured, consistent commit messages.
It runs a configurable plugin pipeline across commit phases (collect, enrich, finalize, etc.), then composes the final message and executes git commit.
- Install:
go install github.com/rolasotelo/goodcommit/cmd/goodcommit@latest- Bootstrap config in your repository:
goodcommit initThis scaffolds:
configs/goodcommit.plugins.jsonconfigs/commit-types.jsongoodcommit.plugins.lock(unless--lock=false)
- Run interactively:
goodcommit- Dry run (no commit):
goodcommit -mIf config already exists and you only want to refresh lock/build artifacts:
goodcommit plugin lock \
--plugins-config ./configs/goodcommit.plugins.json \
--plugins-bin-dir gobin \
--plugins-lockfile ./goodcommit.plugins.lockVerify:
goodcommit plugin verify \
--plugins-config ./configs/goodcommit.plugins.json \
--plugins-lockfile ./goodcommit.plugins.lockCurrent default stack (from configs/goodcommit.plugins.json):
builtin/logobuiltin/typesbuiltin/scopesbuiltin/descriptionbuiltin/whybuiltin/bodybuiltin/breakingbuiltin/breakingmsgbuiltin/coauthorsbuiltin/conventional-titlebuiltin/signedoffby
Notes:
logoandtypesshare one grouped page (ui_group: "intro").- Grouped UI is compact by default.
- Use
--detailed-ui(orGOODCOMMIT_DETAILED_UI=true) to show verbose grouped section headings/instructions.
You can provide answers via --plugin-answer:
goodcommit \
--plugin-answer commit_type=feat \
--plugin-answer commit_description="add plugin lock verification" \
-mTo inspect required/optional answers for automation/agents:
goodcommit plugin context \
--plugins-config ./configs/goodcommit.plugins.json \
--plugins-lockfile ./goodcommit.plugins.lock- Main plugin config:
configs/goodcommit.plugins.json - Example config:
configs/plugins-config.example.json - Default logo file:
configs/logo.ascii.txt - Scope options file:
configs/commit-scopes.json - Co-author options file:
configs/commit-coauthors.json
Built-in plugins can omit explicit manifest/source in config; runtime resolves them from embedded built-in definitions.
You can force specific plugin answer keys to be mandatory via required_answers on that plugin config entry. Example:
{
"id": "builtin/body",
"required_answers": ["commit_body"]
}This affects both:
goodcommit plugin contextoutput (commit_bodywill move torequired_answers)- Runtime execution (plugin invocation fails if required answers are still missing/empty, even when that plugin uses
fail_open)
goodcommit init [flags]--plugins-configpath to scaffold plugins config (default./configs/goodcommit.plugins.json)--types-configpath to scaffold commit types config (default./configs/commit-types.json)--plugins-lockfilelockfile output path (defaultgoodcommit.plugins.lock)--plugins-bin-direxecutable output directory (defaultgobin, which resolves toGOBIN/Go bin dir)--lockbuild+write lockfile after scaffolding (defaulttrue)--forceoverwrite scaffold files if they already exist
MIT. See LICENSE.