Releases: azrtydxb/procoder
Release list
v1.3.0
The decisions Procoder used to make on your behalf are yours to make,
and it says which ones you changed.
Added — a repository chooses its own tools, thresholds and templates.
(#123,
#124,
#125) [tools] js = "biome" picks the formatter for a language. [security] sast_blocks_at
sets the severity that stops a commit, where the code had ERROR as a
literal. .procoder/templates/<name>.md replaces any of the nine
templates that drive the quality chain — spec, plan, ADR, todo,
milestone, epic, story, sprint, bug — which were embedded constants with
no way in. And .procoder/lint/RULES.md gains the ## checks list the
docs and security domains already had, replacing Procoder's curated
clang-tidy families.
A repository names a tool; it does not name a binary and an argv.
Procoder owns the invocation, which is what keeps the print-don't-write
contract a guarantee rather than a hope — a tool reaches the menu by
being able to emit formatted source on stdout, tested for each candidate
rather than assumed. Laravel Pint, phpcbf and php-cs-fixer are absent for
that reason and no other.
Added — procoder config says what is in force and where it came
from. (#123) Every
effective setting, its value, and its source — default, or the file and
line. A setting weaker than its default is marked. Configurability
without visibility is worse than none: a person reading an unfamiliar
repository has to be able to ask which of Procoder's defaults still
apply.
Changed — a setting that weakens a default prints on every gate
run. (#123) Naming
what was relaxed and what it costs. Strengthening prints nothing. This is
the rule the gate already lives by, applied to configuration: a green
verdict must not be able to mean "the config was loosened" without saying
so.
Fixed — a setting Procoder cannot apply no longer passes in silence.
(#123) The loader fell
through for any key it did not recognise, so polcy = "block" was
accepted, did nothing, and said nothing — the writer believed their
policy was set. Unknown keys, malformed lines and values of the wrong
kind are each reported with their line number, and they block.
Fixed — an emptied Markdown file blocks.
(#120) procoder format
prints one header line for a file that is already formatted, so a
pipeline that strips the header and writes the rest empties it on the
success path. That destroyed a 551-line documentation page in this
repository, and nothing noticed: the documentation obligation asks
whether a doc CHANGED, and emptying one is a change, so the destruction
satisfied the check meant to prevent it.
Upgrade in place: procoder self-upgrade — it asks first, and installs
only after the download matches the SHA256SUMS published below.
Or download the binary for your platform below and check it against
SHA256SUMS before running it.
Every commit in this release:
v1.2.0...v1.3.0
v1.2.0
A green gate now means the code was checked rather than that the machine
was empty, and PHP is a language Procoder speaks.
Changed — a check that could not run stops the commit.
(#114) A missing linter
used to print NOT checked as information and let the gate exit 0, so an
empty machine was indistinguishable from clean code. Domain 1 had always
blocked on a missing gitleaks; every domain does now — lint, formatting,
infrastructure, docs, workflows. A formatter that wants a config it cannot
find is unchecked rather than out of scope, because out of scope passes.
This will fail repositories that were passing on a toolchain that was
never there. That is the point, and every refusal names the tool and the
command that installs it: procoder init installs what procoder doctor
lists. A file type Procoder does not claim — a text file, an image — is
still out of scope, still silent, still green.
[lint] policy is unchanged: it governs whether a linter's findings block
a commit. Whether the linter ran at all was never a matter of policy.
Added — PHP.
(#112) .php files are
formatted through prettier's PHP plugin, linted by whichever of phpstan
and phpcs the project configured, and phpunit is detected and run by
procoder test with its counts and --name filtering. A project that
configured no linter gets Procoder's phpstan baseline rather than a
syntax check; a project that configured one keeps it. Coverage reports
NOT measured rather than a number nobody measured.
Added — Procoder brings a linter when the project brought none.
(#113) TypeScript with
no eslint config is linted against typescript-eslint's recommended set,
where it used to be declared out of scope because a parser would have had
to be installed — the most common TypeScript setup there is got no
linting and a green gate. C and C++ reach clang-tidy, and clang-format no
longer needs a project style file to format anything. Every baseline is
written to a temp file or named on the command line; nothing is written
into your repository, and a project config always wins.
Fixed — an emptied documentation file no longer passes the gate.
(#120) procoder format
prints one header line for a file that is already formatted and nothing
after it, so a pipeline that strips the header and writes the rest empties
the file on the success path. That destroyed docs/commands.md during
this release's own development, and nothing noticed: the documentation
obligation asks whether a doc CHANGED, and emptying one is a change, so
the destruction satisfied the check meant to prevent it. An emptied
Markdown file is a blocking finding now, naming the command that restores
it. PHP also reached the language list in the README, where it was
missing.
Fixed — five file types were formatted and never linted.
(#114) .mts and .cts
went unlinted while .mjs and .cjs were checked, and .pyi was
formatted and never read by ruff. C# and Dart have no linter yet and now
say so rather than passing quietly.
Upgrade in place: procoder self-upgrade — it asks first, and installs
only after the download matches the SHA256SUMS published below.
Or download the binary for your platform below and check it against
SHA256SUMS before running it.
Every commit in this release:
v1.1.1...v1.2.0
v1.1.1
procoder ask puts the open questions to a human instead of letting
the coder guess. A spec's undecided questions and the gate's own
findings are collected into .procoder/ask/QA.md, answered in
answers.md, and an answered question stops blocking the spec
controller. A flagged secret's value never travels — not into a
question, not into the terminal, not into a hook payload.
pi could not install procoder at all. The pi extension was a
CommonJS module and pi validates the export shape at install time, so
omp plugin install failed outright while the portability docs listed
pi as supported. Nothing local caught it: Node hands a CommonJS export
back as default on import, so every load test passed. The adapter is
an ES module now, and the check reads adapter source rather than
importing it. Reported by @striderZA, who supplied the diagnosis and
the fix.
Generated ids no longer weld words together. Dropping a dot left
answers.md filed as "answersmd" — a story unfindable by the name of
the file it is about — and collapsed v1.2.3 and v12.3 onto one id,
which surfaced as a refusal with no visible cause. Punctuation
separates now, accented letters fold to their letters (café → cafe)
rather than vanishing, and two criteria that still land on the same id
get two stories instead of one written over the other. Names already on
disk are untouched.
v1.1.0
procoder now knows when it is out of date, and verifies what it
installs. procoder version --check asks GitHub what the newest
release is; procoder self-upgrade installs it, but only after an
explicit yes on a terminal, only after the download matches the
SHA256SUMS the release publishes, and never over a binary a package
manager owns — that one is refused with the manager's own upgrade
command. A check that could not run reports NOT known and exits 2,
because an unanswered check has never meant "you are current". At a
session start the check runs alongside the payload, capped at one
second, so a slow network cannot hold a session open.
Windows works. Claude Code runs hooks through Git Bash, where
uname -s answers MINGW64_NT-…; the launcher recognised only Darwin
and Linux and exited 1, so every hook and every slash command failed on
a fresh install while procoder.exe sat there unreachable. Fixed by
this project's first outside contributor, and now exercised on a real
Windows runner in CI.
procoder copilot-leak collects what GitHub Copilot's auto-review
found, strips every trace of your code from it, and — only if you say
yes — files it as issues and records it as unlearned until somebody
writes the adaptation that closes the class.
The backlog stops overstating itself. The board names the branch it
read and counts the open stories the default branch holds that this
checkout cannot see. A spec's fingerprint tracks its acceptance
criteria rather than its prose, so rewrapping a paragraph no longer
reads as drift. A spec with undecided questions is no longer reported
COMPLETE whatever those questions are called, and the dead-code tier
separates surface referenced only by its own tests from live code.
The gate is faster and no longer drifts. Every tool it installs is
pinned in .github/tool-versions.env and cached, and the three that
publish binaries are downloaded rather than compiled: 5m47s to 3m06s.
Tool versions can no longer change the gate's verdict between two runs
of the same commit, and the Go toolchain is pinned for the same reason.
dist/ is reproducible. scripts/build-dist.sh records the
procedure that used to live in a shell history, stamps the version from
the manifest, and builds with -buildvcs=false so two builds of one
tree produce identical bytes. CI rebuilds the committed binaries and
compares digests, so a stale dist/ fails before a tag rather than
after one.
v1.0.2
Kilo Code is a first-class host, and the gate goes with it. Kilo's
CLI is an OpenCode fork and its plugin API is the same one, so the JS
shim that already served OpenCode now serves both, byte for byte. It
gained the piece that matters: the commit gate runs at the tool
boundary and refuses a commit with blocking findings — in Kilo that
covers the VS Code extension, not only a terminal, which makes it the
first editor where "done" has to survive the gate. OpenCode gets the
same enforcement in the same change. Every host reaches one
implementation, so there is one verdict wherever you work, and a
machine without the binary is told the gate did NOT run rather than
having its commits blocked.
Three more tiers came with it: Kilo's current rules path, a command
set, and skills/procoder/SKILL.md — the contract under the Agent
Skills envelope, read by Kilo and by any host that scans a skills
directory.
A correct link stopped reading as a broken one. The reference
check reproduced mkdocs' slugify everywhere, including repositories
whose Markdown is only ever read on github.com, which does not collapse
runs of hyphens. Every heading containing an ampersand, an em dash, or
a colon had a working anchor the gate called broken — blocking, with no
way out but rewording public headings. A heading is now credited with
the anchor each renderer generates. Underscores inside code spans
survive too, so a heading naming a snake_case symbol is reachable.
The documentation acknowledgment works from wherever git reads the
message. docs: none — <reason> only cleared its obligation when the
message arrived through -m. With -F <file>, a heredoc, or an editor
commit the line was invisible, so the finding told you to write exactly
the line it then ignored. All the forms the gate can see are read now,
and where no message can reach the check it says so instead of naming a
remedy that cannot work.
The documentation obligation asks about your branch, not your
uncommitted slice. Writing the doc in one commit and the code in the
next demanded an acknowledgment for work that was already documented.
The question now spans the commits your branch carries. The public
surface is also compared like with like — the previous revision read by
the same parser as the current one — so a capitalised local constant in
JavaScript no longer reports itself removed on every run.
An epic that was never seeded says so. A Spec: line carrying
anything a fingerprint could not produce read as spec drift forever,
pointing at a comparison that had never happened.
v1.0.1
A tag is the release now. Twenty-seven tags were pushed while exactly
one GitHub Release was ever created by hand, so everything that reads
"latest release" — the documentation site's own header among them — sat
on a version from weeks earlier while the site body reported the current
one.
CI publishes the Release when a v* tag is pushed, with the changelog
entry as the notes and the five platform binaries attached, so the
manual install no longer means cloning the repository for one file. It
runs only after the suite and the gate pass on the tagged tree: the
Release is what people download, so it ships on the same evidence as
everything else.
A missing changelog entry fails the job rather than publishing empty
notes. procoder release already refuses to tag without one, so its
absence at this point means something went wrong upstream, and a release
that looks finished but says nothing is worse than a red job.
1.0.0 — the interface is a promise now
Procoder is 1.0. Not because anything new landed today, but because what
is here has been used long enough to be worth promising.
What 1.0 means. These are the public interface, and breaking any of
them takes a major version: command and subcommand names; exit codes (0
clean, 1 findings or refusal, 2 usage); what blocks versus what informs,
so a new blocking check cannot fail a build that passed yesterday; the
.procoder/ formats a repository commits — config keys, the
spec/plan/todo/backlog/adr shapes, the epic Spec: fingerprint, the
rules files' machine-read sections; and the hook payloads and envelopes,
per host.
Deliberately not covered, because pinning them would freeze the product:
the wording of report lines (verdicts are for people; exit codes are the
contract), the default rules content every repository is meant to
override, the internal/ Go packages, and the gitignored index format.
.procoder/adr/0003-what-1-0-promises.md carries the reasoning and the
alternatives that lost.
What it is. One Go binary, no runtime dependencies, cross-compiled
for five platforms and committed with the plugin — no npm, no network at
hook time, air-gapped installs included. Ten domains behind one gate.
The quality chain from spec to release, every link refusing rather than
advising. A universal agent layer serving twenty-odd hosts from one
AGENTS.md. A code index instead of grep. A lessons ledger where an
escape is not closed until the layer that missed it has been adapted.
Where it stands. 73.2% statement coverage from a mutation-driven
sweep; the whole-tree audit reports zero blocking findings; the deep
security scan reports zero findings; 25 lessons recorded with zero
unlearned; three debt markers, each with the condition that will bring
it back.
One judgment reviewed for this release. The spec fingerprint and the
tool-cache directory name both use SHA-1. Both are change detection
rather than signatures, and the fingerprint is persisted on every seeded
epic, so switching the digest would flag drift on work that has not
changed. Kept deliberately, marked at both call sites with the reason,
and now covered by the compatibility promise.
v0.22.1
The CLI help (procoder with no arguments) now lists every command alphabetically instead of grouped by workflow, so a command is found by name at a glance. Descriptions are unchanged.
Full changelog: https://github.com/azrtydxb/procoder/blob/main/CHANGELOG.md