Repository navigation
v0.3.0
0.3.0 (2026-09-21)
First public release. The project is now ForgeGraph: the compiler ships as
the forgec binary from the forgegraph-cli crate, and the runtime packages
are published on npm under the @forgegraph scope. Everything is Apache-2.0
and developed in the open at https://github.com/gmackie/forgec.
Breaking
- The CLI binary is
forgec, notforge. Every command, flag and output
format is unchanged; only the name moved.forgeis taken on crates.io and
by Foundry, and the old name could not be published. - npm packages moved from
@forge/*to@forgegraph/*. Update imports; no
API changed with the move. - The library crates are
forgegraph-syntax,forgegraph-semantic,
forgegraph-plannerandforgegraph-codegen(Rust paths
forgegraph_syntaxand so on).forge-codegenwas already taken on
crates.io by an unrelated project, and it is the fourth of five in publish
order — a release would have discovered that only after permanently
publishing the three before it. The other three names were free, butforge-
is contested enough (Atlassian, Foundry, Aptos) that consistency is worth
more than the names. Compiler output is unaffected: the generated bundle and
its build hash are byte-identical across the rename. createNodeHostnow refuses to start without anAuthHost. It
previously fell back to development header auth, which meant a Node
deployment that forgot to configure authentication trusted
x-forge-tenant/x-forge-actorfrom the caller. Passauth, or set
FORGE_AUTH=dev-headersto opt into the development behaviour by name. The
Cloudflare and AWS hosts already failed closed; all three now log a loud
warning whenever development auth is active.
Added
- Published artifacts: five crates on crates.io, nine packages on npm with
build provenance, prebuiltforgecbinaries for macOS and Linux on both
architectures, and a Homebrew formula atgmackorg/tap/forgec. The tap
pulls the formula from each release rather than being pushed to, so this
repository holds no credential for it — seedocs/releasing.md. docs/stability.md: a per-package stability tier, also recorded in each
package.jsonunderforgegraph.stability.docs/releasing.md: the release process, the required secrets, and how to
bootstrap the shared Homebrew tap.- CI (
.github/workflows/ci.yml): compiler on stable and 1.97, runtime on
Node 22 and 24 against PostgreSQL 17, a stale-fixture check, the
cross-profile differential, a packaging dry-run, and supply-chain audits. - Release automation (
.github/workflows/release.yml) and a Forgejo mirror. scripts/check-crate-names.mjs, run by CI and again before a release starts:
every workspace crate name must be free or already ours. crates.io names are
permanent and publishing is ordered, so a name discovered to be taken partway
through leaves everything before it published forever.- The
LICENSEfile is now the full Apache-2.0 text. It was a 15-line notice
pointing at the licence rather than a copy of it, while every crate and
package declaredApache-2.0and shipped that file as their licence —
Apache-2.0 requires the copy. It is also now inside each crate's own
directory: cargo pulls the workspace README into a tarball but not the
workspace LICENSE, so the crates would have published with none at all.
scripts/check-packaging.mjsnow checks the crate tarballs too, and fails if
one carries no LICENSE, no README or no license field. scripts/check-workflows.mjs, run by CI: workflow files must parse, and an
unquoted${{ }}inside awith: { }flow mapping is rejected by name. YAML
reads the expression's{as opening a map, which invalidates the entire
file — GitHub reports that as a run named after the file path, failing before
any job starts, with no log to read.
Changed
-
@forgegraph/temporal: Temporal WorkflowDriver + worker; profile
self-hosted-fullcertified on a single-node Temporal dev server. -
@forgegraph/adapters/sqlite: embedded libsql executor certified through the
D1 adapter. -
OtlpSinkandtelemetryFormat: "otlp"on the Node host. -
Live deployment identifiers in
examples/acmeare placeholders. The
certification evidence inconformance/certification/latest.jsonkeeps every
result and withholds only the private hostnames, marked as withheld. -
Re-certified live against build
cfc8286aafter the rename: Cloudflare
(Workers + D1 + R2 + Queues + Workflows + Durable Objects + Cron Triggers)
and AWS (HTTP API + Lambda + DynamoDB + S3 + SQS + Step Functions +
EventBridge + API Gateway WebSocket), 15 scenarios / 221 steps each, realtime
and provider switching in both directions, plus the differential across
memory / sqlite-node / PostgreSQL with 0 unexplained differences. All five
required profiles are certified against this build. -
examples/acme/deploy/cloudflare/resolve-config.mjs: the committed
wrangler.jsonckeeps placeholders, and thecf:*scripts resolve a
gitignored copy fromFORGE_D1_DATABASE_ID. A public repository should not
name someone else's database, and an editable placeholder is a placeholder
waiting to be committed by accident. -
Re-pinned the adapter capability manifest digests in
examples/acme, whose
IDs moved to the@forgegraphscope. -
cargo clippy -D warningsandcargo fmt --checknow pass workspace-wide
and are enforced in CI.
Fixed
Two concurrency defects, both found by CI on a clean machine after they had
hidden behind warm local state. Both were real: the first diagnosis of the
workflow one — "a flaky test, not a flaky runtime" — was wrong, and the poll
budget it widened was treating a symptom.
-
A workflow activity could run twice and report the wrong outcome. The
idempotency key for a workflow step embedded the instance version. That
version moves whenever anything else touches the instance — a delivered
signal, a competing driver — which is exactly what makes a step's save
conflict and forces a retry. So the retry presented a key the idempotency
store had never seen, the already-committed activity ran a second time, and
it failed withVersionConflictagainst the record the first attempt had
itself just moved. The workflow then reportedVersionConflictinstead of
its real result: in the reference application, an order that should have
failed withShortPaymentand been cancelled. Reproduced at roughly 1 run in
6 under load. The key is nowwf:<instance>:<step>:<pass>, stable across
retries and distinct per loop iteration (stepIdempotencyKey, exported and
unit-tested). -
Independent concurrent writes failed on PostgreSQL. Every commit writes
_forge_assertand may writeforge_outbox, so underSERIALIZABLEwriters
that share no business state still collide on predicate locks. A
serialization failure there is the expected outcome and the documented remedy
is to retry, butPostgresStorageinherited D1's retry budget — 3 attempts
inside 75ms, tuned for a single-writer store where conflicts are rare. 64
concurrent creates of distinct customers produced 10TransientConflict
503s. The retry budget and backoff are now overridable per adapter, and
PostgreSQL uses 10 attempts with exponential backoff and jitter (~2s). Calls
that succeed on D1 and DynamoDB now succeed on PostgreSQL, which is the whole
point. -
pnpm differentialno longer dies withENOENTon the report file when the
suite fails before writing one. It reported a missing file instead of the
failure that was printed directly above it. -
The workflow-failure assertion in
conformance/scenarios/workflows.jsonnow
gets the same 30s poll budget as the workflow-completion assertion beside it
— consistency between two assertions of the same kind, not a fix.
Install the compiler:
brew install gmackorg/tap/forgec # macOS and Linux
cargo install forgegraph-cli # from source
Runtime packages are on npm under @forgegraph/* with build provenance.
Certified profiles and their evidence: RELEASE_MANIFEST.json.