Skip to content

Releases: prabhuakshay/forge

v0.11.1

Choose a tag to compare

@prabhuakshay prabhuakshay released this 29 Jun 07:51

Changed

  • /forge:release commit message now follows the conventional-commit form chore(release): release vX.Y.Z instead of Release vX.Y.Z, and the command now has an explicit commit step.
  • Changelog guidance for /forge:release now records only the net user-visible change in a release, not intra-release churn: something added and then removed within the same release is listed nowhere, and something added and then fixed within the same release is listed only as the final working feature.

Fixed

  • README layout table brought back in sync with the tree: the agents/, lib/, and references/ listings now include the security-auditor agent, the security/versions modules, and the fastapi/library/pytest references added in 0.11.0.

v0.11.0

Choose a tag to compare

@prabhuakshay prabhuakshay released this 27 Jun 06:37

Added

  • Version-agreement check in /forge:audit. The mechanical audit now refuses
    to pass when a project declares its version in more than one place that
    disagree — pyproject.toml [project], a package __version__, and every
    .claude-plugin/*.json manifest (top-level and nested plugin entries). This
    caught a real drift: pyproject.toml was 0.10.0 while the plugin/marketplace
    manifests were still 0.9.1. (lib/versions.py)
  • Security scanning in /forge:audit. Optional pip-audit (dependency CVEs,
    blocking) and bandit (risky code patterns, advisory — or blocking under
    FORGE_SECURITY_STRICT=1) scans. Both degrade to a hint when the tool isn't
    installed, so forge never forces the dependency. (lib/security.py)
  • python-security-auditor agent for logic-level security review of changed
    code in /forge:review, complementing the mechanical scanners.
  • Override hygiene. /forge:override list prints the consumed-bypass trail and
    /forge:override prune [keep] compacts it; /forge:status now warns when the
    trail piles up (a signal a gate may be mis-calibrated).
  • FORGE_COVERAGE_FLOOR env var to override the default coverage floor (80),
    mirroring FORGE_GATE_TIMEOUT. A project's own fail_under still wins.
  • Three new style references: fastapi, pytest, and library (packaging /
    library-authoring conventions), installable via /forge:reference add.

v0.10.0

Choose a tag to compare

@prabhuakshay prabhuakshay released this 25 Jun 15:39

Added

  • Dual Docker setup for all projects: Dockerfile (production, multi-stage optimized) and Dockerfile.dev (development with watchfiles hot reload). Includes .dockerignore for efficient builds.
  • Docker Compose files: docker-compose.yml (production with health checks and restart policy) and docker-compose.dev.yml (development with volume mounts for live code changes).
  • Django-specific Docker: Dockerfile.django and Dockerfile.django.dev with proper Django setup (gunicorn, migrations, collectstatic). Includes docker-compose.django.yml and docker-compose.django.dev.yml.
  • Django health check integration: Management command template (healthcheck.py) automatically created for Django projects. Docker health checks integrated by default via python manage.py healthcheck (checks database connectivity).

v0.9.1

Choose a tag to compare

@prabhuakshay prabhuakshay released this 25 Jun 08:13

A correctness-and-clarity patch.

Fixed

  • Concurrent /forge:decide runs can no longer collide on an ADR number. Number allocation was the one state mutation that ran without the .forge lock, so two racing decisions could both claim 0004 — duplicate ADRs and an ambiguous directive back-reference. Allocation and the ADR/directive/index writes now run together under state.locked via a new decisions.record_decision, and the ADR is written atomically (temp + os.replace) and first, so a crash mid-write can at worst orphan an ADR — never leave a directive pointing at a number that was never written.
  • The coverage-floor check no longer trips on a comment. Detection of whether a project sets its own floor is now section-scoped: fail_under only counts in [tool.coverage.report], --cov-fail-under only in [tool.pytest.ini_options], comments ignored.
  • The commit-time gate now measures coverage like the rest. forge's prek pytest hook ran without --cov; it now runs pytest -q --cov, matching the dev command and the in-session gate.

Changed

  • Clearer command guidance. /forge:build states the two --no-docs skip conditions as independent; /forge:init lists concrete type-detection markers instead of "from any existing files"; and the scaffolded CLAUDE.md now documents the scripts/check_env_sync.py guard that was already wired into pre-commit.

Full changelog: v0.9.0...v0.9.1

v0.9.0

Choose a tag to compare

@prabhuakshay prabhuakshay released this 25 Jun 05:29

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 makes code_fingerprint skip 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 of state.json
    could let one os.replace silently drop the other's change — a lost dirty_py
    entry, or worse a dropped overrides audit record. Every mutation now runs
    under an exclusive POSIX advisory lock (.forge/.state.lock).
  • code_fingerprint only re-reads what changed, via a git-ignored
    .forge/fpcache.json cache, 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; state re-exports it, so callers are unchanged.

Documentation

  • forge now states its requirements plainly: Python projects only, and
    Linux/macOS only — the hooks invoke python3 and the state relies on POSIX
    file locking (fcntl), so Windows is unsupported. The manifests carry the same
    constraint.
  • docs/state-schema.md documents the two new local-only sidecar files.

Internal

  • A meta-test asserts the prompt layer stays wired up: every bin/*.py a command
    invokes, every agent it names, and every hooks.json script must resolve to a
    real file — so a rename or typo there can't ship undetected.

Full changelog: v0.8.0...v0.9.0

v0.8.0

Choose a tag to compare

@prabhuakshay prabhuakshay released this 25 Jun 04:48

forge v0.8.0 tightens the env-drift gate, sharpens the docs, and removes dead code — a correctness-and-honesty release.

Changed

  • env_scan detects the env reads it was silently missing. The drift scan now recognises os.environ.pop(...) and os.environ.setdefault(...) (both read the variable, just like .get()), and captures variable names in any case rather than UPPER_CASE only. Environment variables are case-sensitive on POSIX, so a read like os.getenv("debug_mode") is real config that onboarding must document — matching only [A-Z…] quietly dropped every lower/mixed-case read on the floor. The drift check compares names verbatim, the way the OS resolves them (pydantic-settings stays case-folded, since it resolves env vars case-insensitively). This makes the /forge:audit env check and the Stop gate's drift check catch undocumented configuration they previously let through.

Removed

  • lib/state.clear_dirty — dead code with no caller (record_pass clears the dirty set inline). No command, hook, or documented behaviour referenced it.

Documentation

  • README now states plainly that only two agents are evidence-bounddoc-sync-auditor and reference-auditor must cite a file:line for every finding — while python-quality-auditor, doc-gap-scanner, and python-test-author are advisory/generative.
  • README's Stop gate description now says when it fires (turn-end), what it runs (format/lint whole-tree, mypy scoped to changed files and skipped when nothing is dirty, env drift — never the test suite), and that failures are fed back rather than walling off.
  • docs/state-schema.md documents that dirty_py clears only on a green check, so it intentionally accumulates past audit/review passes.
  • /forge:docs report header no longer looks like a subcommand; /forge:release gives the concrete command for listing commits since the last tag; the lib/ layout list now includes status (caught by the doc-sync auditor during this release).

Internal

  • Closed branch-coverage gaps in lib/cmdscan (91%→98%) and lib/state (89%→96%); suite total 94%→96%, 272 tests.

Full changelog: v0.7.0...v0.8.0

v0.7.0

Choose a tag to compare

@prabhuakshay prabhuakshay released this 25 Jun 04:05

This release hardens the enforcement layer and closes a consistency gap in how the review gate was documented. It's backward-compatible — no command contract or .forge/ layout changed.

Robustness

  • State is now persisted atomically. lib/state.save writes a temp file and os.replaces it into place. A torn write was previously read back as corrupt JSON and silently reset to the empty skeleton — dropping recorded passes and the overrides audit trail — and two concurrent tool calls could lose each other's writes. The audit trail is the whole point of the override mechanism, so it must never vanish silently.
  • Gates check freshness before consuming an override. require_check, require_review, require_audit, and require_plan now confirm the gate is actually unsatisfied before taking a one-shot override — so a green/satisfied action never burns (or falsely logs) a bypass that wasn't needed.
  • require_plan only treats a plan with unchecked items as active. A completed plan (every item ticked) or an empty file no longer holds the gate open, so finishing a plan correctly re-demands a new one before more source is written.
  • auto_format is scoped to forge-enabled projects, like every other hook — no more silent ruff runs on .py edits in unrelated repos.
  • require_review decodes git's C-quoted paths (octal-escaped non-ASCII / special filenames) before matching them against reference globs, so the reference half of the gate no longer misses a governed file with such a name.

Added

  • bin/plan.py active <path> (backed by lib/state.set_active_plan) — /forge:plan records the active plan through a helper instead of hand-editing state.json, where a malformed write would corrupt workflow state. This was the last state mutation without a dedicated entrypoint.

Documentation

  • Propagated the review gate into every place it had drifted from: /forge:status, the scaffolded CLAUDE.md template, /forge:init's loop string, and the README loop diagram — and qualified the README's auto-format claim to match its new forge-scoped behaviour.
  • doc-gap-scanner no longer assumes the plugin's own layout; src/** is the universal case and plugin-only kinds are optional.

Quality

Coverage of lib/ rises to 94% (gate runner 90% → 99%): added unit tests for the subprocess timeout and full/fast gate aggregation, atomic-write failure cleanup, the override-not-consumed-when-satisfied path across all four gates, git C-path unquoting, and the completed-plan case. 258 tests, green across Python 3.10–3.13.

Full changelog: v0.6.0...v0.7.0

v0.6.0

Choose a tag to compare

@prabhuakshay prabhuakshay released this 25 Jun 01:52

Added

  • Review gate (require_review)git commit is now blocked until
    /forge:review is green for the current tree, closing the gap where binding
    directives and blocking style references were enforced only by an optional
    command. It binds only where there's something to enforce (option B): a
    recorded directive, or an installed reference governing a file in the change
    set — projects with neither are unaffected. Like the other gates it works on a
    fingerprinted pass (last_review, recorded by /forge:review via
    bin/mark.py review), is invalidated by any .py edit, and honours a one-shot
    logged override (/forge:override review "<why>"). /forge:status surfaces the
    review gate when it applies.
  • lib/decisions.binding_directive_count / has_binding_directives — distinguish
    a project that has actually recorded a directive from one that only carries the
    scaffolded template prose (the signal the review gate keys on). /forge:status
    now uses this for its directive count.

Changed

  • references.for_file breaks an equal-specificity tie deterministically:
    blocking references outrank advisory ones (then name), and the
    reference-auditor documents the rule.
  • /forge:init pins the default Python version (3.13) instead of "a current
    stable, e.g. 3.12"; /forge:build documents that it is resumable (works only
    unchecked items).

v0.5.0

Choose a tag to compare

@prabhuakshay prabhuakshay released this 24 Jun 16:27

forge v0.5.0 adds two utility commands and makes the type-check step adapt to projects that don't use mypy.

Added

  • /forge:status — a one-screen snapshot of where a project stands: phase and active plan, each gate (check / audit) as green-for-the-current-tree / stale / never-run, the dirty set, installed style references, the binding-directive count, plus any armed one-shot override (about to fire) and recent override history. Pure read; the report builder lives in lib/status.py.
  • /forge:override <gate> "<reason>" — an ergonomic, logged front door to the one-shot bypass the hooks already honour (gates: check, audit, stop, plan, uv). It arms .forge/override-<gate> with the reason baked in; the next matching gated action consumes it and records the bypass. Writing the sentinel by hand still works. The hook deny messages and docs/state-schema.md now point at the command.

Changed

  • The type-check step is now opt-in by configuration. mypy runs only when the project configures it ([tool.mypy], mypy.ini/.mypy.ini, or a [mypy] section in setup.cfg); otherwise the step is skipped, not failed. Previously uv run mypy on a project that never installed mypy would fail the gate for a tool it deliberately doesn't use. forge-scaffolded projects ship [tool.mypy], so they keep type-checking unchanged.

Full changelog: https://github.com/prabhuakshay/forge/blob/main/CHANGELOG.md

v0.4.0

Choose a tag to compare

@prabhuakshay prabhuakshay released this 24 Jun 11:16

Added

  • uv-only dependency enforcement. A new require_uv PreToolUse hook blocks
    non-uv dependency commands (pip install, uv pip install, poetry/pipenv,
    conda, pip-compile, easy_install, …) in forge-enabled projects, steering
    all dependency changes through uv add/uv remove so pyproject.toml and
    uv.lock stay the single source of truth. Read-only commands (pip list,
    uv pip freeze) are untouched, and .forge/override-uv is the logged one-shot
    escape hatch. The policy is also stated as a binding rule in the python-base
    reference and the scaffolded CLAUDE.md.
  • cmdscan.dep_install_command() — parses a Bash line and names the first
    non-uv dependency invocation it finds (reusing the tokenizer behind the
    commit/push guards).