Local validation
FORGE only works behind CORE, so validating it locally needs a stand-in for CORE’s proxy. The two affordances on this page are for local validation only. No deployment uses either of them.
forge dev proxy
forge dev proxy --email <addr> [--listen 127.0.0.1:8081] [--upstream http://127.0.0.1:8080] [--connections <dir>]It impersonates CORE. The proxy:
- serves
/forge/…and strips the prefix before proxying to--upstream. It also redirects/to/forge/; - drops any inbound
X-Core-Identityand signs a fresh assertion for--emailon every request, usingCORE_FORGE_IDENTITY_KEY; - flushes every write immediately, so gRPC-web server streams (such as
ApproveChat) arrive live.
It grants nothing new to whoever runs it, because holding the key already lets them sign
any address by hand. But anyone who can reach it is signed in as --email. So it
defaults to loopback, and on any other address it logs:
WARNING: forge dev proxy listens on <addr>, not loopback: anyone who can reach it is signed in to FORGE as <email>--connections <dir>: stand in for CORE’s connections
The lane connection picker reads CORE’s connections registry, by name only, from CORE’s own
gRPC-web at the page origin. With --connections <dir>, the proxy serves
runink.ui.datasources.v1.ConnectionsService read-only over a local registry in <dir>,
sealed with CORE_ENVELOPE_KEK. Every write is refused. Seed the registry by hand as
<dir>/connections.json, with non-secret fields only:
{"version":1,"connections":[{"id":"erp-orders","name":"ERP orders","type":"postgres"}]}Without the flag, a call to any of CORE’s own services answers UNIMPLEMENTED, and the
picker says the list could not be read.
FORGE_GITHUB_TOKEN
When this is set, FORGE uses the given personal GitHub token for every call instead of
minting a platform App installation token. It also stops reading CORE_GH_APP_*, and logs
DEV: acting as a personal GitHub token, not the platform App. Everything FORGE then does
is that person’s action, with that person’s permissions, including creating real
repositories and issues in the organisation.
Run it
Generate throwaway keys
export CORE_FORGE_IDENTITY_KEY=$(head -c32 /dev/urandom | base64) \
CORE_ENVELOPE_KEK=$(head -c32 /dev/urandom | base64) \
FORGE_GITHUB_TOKEN=$(gh auth token)The server and the proxy must share the same CORE_FORGE_IDENTITY_KEY.
Build the bundle with the /forge/ base href
cd flutter && flutter build web --base-href /forge/ && cd ..Start the server
cd grpc && FORGE_WEB_DIR=../flutter/build/web go run . serve --port 8080 &By hand, the server listens on 127.0.0.1.
Start the stand-in for CORE
go run . dev proxy --email you@example.orgOpen the studio
Open http://127.0.0.1:8081/forge/ in a browser.
To try the planner as well, set INFERENCE_URL and INFERENCE_MODEL to an
OpenAI-compatible endpoint you run yourself. Without them, free-form text answers
the planner is not connected to the platform's own model — INFERENCE_URL / INFERENCE_MODEL unset on this deployment. Typed commands still work.
What to expect
- The local appfs root is
~/.local/state/forge/appfsunlessFORGE_APPFS_DIRis set. It is sealed underCORE_ENVELOPE_KEK, so keep the same key between runs that share a root. - An approval creates a real private repository in
FORGE_GITHUB_ORG(defaultorg-runink) and files real issues. To keep a test out of that organisation, pointFORGE_GITHUB_ORGat a GitHub organisation you control. - Verification stages show “No verification yet” unless CORE’s sweep reaches the repo.
Sources
grpc/cmd/dev.go; grpc/cmd/dev_connections.go; grpc/internal/ghforge/ghforge.go
(FromEnv); CLAUDE.md (“Local validation (dev-only affordances)”).