v0.9.0
forge v0.9.0 hardens the core that the whole enforcement model rests on — the
workflow state and the green-gate fingerprint — and pins down the supported
platform.
Fixed
- The green-gate fingerprint no longer misses a same-second edit. A new
stat-keyed digest cache makescode_fingerprintskip files it can prove are
unchanged, but a naive(mtime, size)cache would wrongly trust a same-size
edit landing in the same clock-granularity tick as the last hash — the classic
"racy clean" problem, and not theoretical (fast/tmpfs writes hit it). The cache
now applies git's rule: an entry is trusted only when the file's mtime is in a
strictly earlier whole second than the recorded cache build time. A
same-second change is always re-hashed; the content-addressed guarantee holds.
Changed
- Workflow state is now concurrency-safe. Claude Code can run tools (and
hooks) at once; two updaters racing on a read-modify-write ofstate.json
could let oneos.replacesilently drop the other's change — a lostdirty_py
entry, or worse a droppedoverridesaudit record. Every mutation now runs
under an exclusive POSIX advisory lock (.forge/.state.lock). code_fingerprintonly re-reads what changed, via a git-ignored
.forge/fpcache.jsoncache, so the per-commit hash stays proportional to the
edit rather than to repo size. The logic moved into a new dependency-free
lib/fingerprint.py;statere-exports it, so callers are unchanged.
Documentation
- forge now states its requirements plainly: Python projects only, and
Linux/macOS only — the hooks invokepython3and the state relies on POSIX
file locking (fcntl), so Windows is unsupported. The manifests carry the same
constraint. docs/state-schema.mddocuments the two new local-only sidecar files.
Internal
- A meta-test asserts the prompt layer stays wired up: every
bin/*.pya command
invokes, every agent it names, and everyhooks.jsonscript must resolve to a
real file — so a rename or typo there can't ship undetected.
Full changelog: v0.8.0...v0.9.0