v1.0 is an API freeze: what `schema: v1` actually promises.
v1.0 isn't just a number. CLI flag surface, JSON schema v1, and the COMMITBRIEF.md / OUTPUT.md formats are under strict semver from here on. Here's what that buys you, and what it stops me from doing.
For the first eight months CommitBrief existed in public, every release carried an implicit caveat: this might change next week. The CLI surface evolved release-to-release, the JSON output’s shape moved, the OUTPUT.md semantics broke once and quietly fixed themselves. That’s the right posture for a v0.x project — but it’s exactly the wrong posture for a tool you’d wire into a pre-commit hook, a CI gate, or an editor extension.
v1.0 is the line on the floor that ends that posture. From this release on, the things people build on top of CommitBrief are the things I have to defend.
What the freeze actually covers
The frozen surface is everything an external consumer can observe:
- CLI flag surface.
--staged,--unstaged,--json,--markdown,--fail-on,--copy,--cli,--provider,--model,--output,--verbose,--quiet,--color,--lang,--no-cache,--allow-secrets,--no-cost-check,--yes,--file,--dir, and every subcommand verb. Renaming any of these is a breaking change. New flags can land additively in v1.x; existing ones don’t move until v2. - JSON schema v1. The
--jsonoutput —{schema, content, findings, summary, meta}— is locked. Field names, field types, and the severity enum (critical | high | medium | low | info) follow strict semver. Additive fields are fine; renames, removals, or type changes wait forschema: v2. COMMITBRIEF.mdandOUTPUT.mdformats. The system-prompt envelope (the<project_rules>XML wrap, the language directive, the immutability guard) and the local Go template’s data shape (.Findings []Finding{Severity, File, Line, LineEnd, Title, Description, Suggestion, Language, Snippet}plus the four helpersupper,lower,groupBySeverity,countFiles) are part of the contract. Helpers can be added; the slice fields stay.- Public config keys. The dotted-path surface
commitbrief config get/setexposes is stable. Unknown keys error, which means a config file you write today still loads in v1.x without a “deprecated field” warning showing up unannounced.
What’s not frozen: internal package APIs (none are exposed for library use), the rendered terminal output (the cards layout can shift), the embedded COMMITBRIEF.md default content, and the on-disk cache format. The first three are end-user-facing but I can’t promise pixel stability across a year. The cache format is internal — version-bumped when needed, invalidating old entries automatically.
What semver actually means here
People use “semver” as shorthand for “I won’t break your stuff,” but the specifics matter. The version-number ladder I’m committing to is the straightforward read:
- v1.0 → v1.x. Additive only. New flags, new optional JSON fields, new template helpers, new providers. Nothing already in v1.0 changes shape, gets renamed, or starts behaving differently.
- v1.x → v1.x+1 patch. Bug fixes. No new surface; no semantic shifts.
- v1.x → v2.0. Breaking change. Will ship with a migration guide modelled on the v0.x → v1.0 guide currently in the CLI repo’s CHANGELOG, plus a deprecation period where the old surface keeps working with a warning.
The migration guide model is the part I want to underline. The v0.x → v1.0 transition collected every breaking change (scope-flag collapse, --yes scope narrowing, cache.max_size_mb removal, locale narrow, Diff.IsMerge removal) into one section with before/after tables. When v2.0 eventually ships, it’ll be the same shape — one section, every change, table format. No surprises buried in a patch note.
What this buys you
Three concrete things become possible at v1.0 that weren’t safe before:
You can pin a version in CI without dreading the next upgrade. commitbrief --fail-on=critical --json in a GitHub Actions step will produce the same shape of output in v1.0.0 as in v1.4.7. Your jq filter doesn’t need a “which version is this” branch.
You can build tooling on top of --json. Editor extensions that surface findings as inline diagnostics, dashboards that aggregate findings across PRs, custom reporters that pipe to Slack — anything that parses the v1 schema has a guarantee the schema stays parseable. A new optional field might appear; nothing existing disappears.
You can write a COMMITBRIEF.md once and stop maintaining it. The system-prompt envelope isn’t going to change shape; the rules you write today still get applied the same way next year. The anatomy post is now a thing you can hand to a new hire and trust the content not to age out from under them.
What it stops me from doing
I want to be explicit about the cost, because the value of the freeze depends on me actually paying it.
The biggest constraint: clever improvements that would require renaming or restructuring a flag are off the table until v2. If I realize next month that --fail-on should really have been named --exit-on, that’s a v2 change. I have to ship the slightly-worse-named v1 flag and add the better-named one as an alias instead of replacing it.
The same applies to the JSON schema. If I want to restructure meta to nest tokens differently, I can’t — I have to add new fields alongside the existing ones and live with the redundancy. Cleanup happens at v2.
The third constraint is that experimental features have to be opt-in clearly, not bolted into the main surface and quietly stabilised later. If I want to try a new render mode, it ships behind an explicit flag like --experimental-cards-v2, and that flag’s behaviour is explicitly not covered by the semver guarantee.
These are real costs. I think they’re worth paying because the alternative — silent change in a tool that sits in your pre-commit workflow — is exactly the kind of friction that makes a tool stop getting used.
A small note on what changed at v1.0 itself
v1.0 isn’t only the freeze checkpoint; it also stabilises two providers that were experimental in v0.9.x. claude-cli and gemini-cli — the subprocess wrappers that reuse your locally-installed Claude Code or Gemini CLI — are now first-class. The plain-text emit pipeline closed the reliability gaps that kept them in the experimental bucket through v0.9.x. The subscription-backed provider post covers why you’d reach for them and what their trade-offs are.
Everything else that lands at v1.0 is incremental: a gosec security scan in CI, a BENCHMARKS.md baseline, and a handful of small fixes around the cache key’s diff/system-prompt hash fields. The CHANGELOG covers them line by line; none of them shift the surface in a way you need to think about.
What to do today
If you’ve been waiting for the “should I commit to this in CI” moment — this is it. The upgrade path from any v0.9.x is documented in the CHANGELOG migration guide; if you’re starting fresh, brew install CommitBrief/tap/commitbrief and the getting-started doc take you from zero to your first review in three commands.
The next post in this series turns to the safety stack you didn’t ask for but that v1.0 quietly leans on: the three pre-send guards that fire before any token is spent.