{"slug": "show-hn-commonforge-let-clients-ai-agents-work-in-your-codebase-safely", "title": "Show HN: CommonForge – Let clients' AI agents work in your codebase safely", "summary": "CommonForge launched as a self-hosted workspace that lets agencies and their clients run coding agents on client websites, with every agent change isolated, checked, previewed on staging, and approved before production. The tool runs entirely on Cloudflare Workers and Cloudflare Artifacts, deploys into a user's own Cloudflare account via one script, and agents operate through a small CLI called cforge that installs, signs in with a one-time code, checks out the task's folders, and finishes with cforge submit. Access is controlled per folder by the owner through Settings → Access, with Can change, Read only, or No access options, and clients see only the projects they are given.", "body_md": "CommonForge is a self-hosted workspace where an agency, its clients and their coding agents change a client's website together. Clients ask for changes as tasks. Agents work on each task in an isolated copy of the code. Every change is checked, previewed on a staging site and approved before it reaches production, and every accepted version can be restored.\n\nFor developers: it runs entirely on **Cloudflare Workers** and **Cloudflare Artifacts**. You\ndeploy it into your own Cloudflare account with one script, and agents work through a small CLI,\n`cforge`.\n\n**▶ Watch the 8-minute demo on YouTube**\n\n| **Getting started** walks a new owner from an empty organization to the first client task live. | **Tasks** (staging mode): client tasks move from Working to In staging, Waiting for approval and Live. | \n| **Give to agent** copies one prompt that a coding agent runs from start to finish: install, sign in, check out, submit. | **The Change storyboard** : what was asked, what changed, what was verified, and the next decision. | \n| **Versions** : every accepted version, the one production runs, and restore. |  | \n\nThe screenshots come from the local stack (below), not from fixture data. To regenerate them, run\n`pnpm --filter @commonforge-org/web run screenshots`\n([apps/web/e2e/readme-screenshots.spec.ts](https://github.com/CommonForge-org/commonforge/blob/main/apps/web/e2e/readme-screenshots.spec.ts)).\n\nThe path from a new deployment to a client's change in production:\n\n1. **Owner signs in.** Sign-in is by emailed magic link. Only the addresses in the deployment's\nadmin list (`COMMONFORGE_ADMIN_EMAILS` ) may create an organization.\n2. **Organization and project.** One organization per client; a project is one client site. The\nproject's Overview shows a**Getting started** checklist that reads its progress from the real\nproject state.\n3. **Import the code.*** Files → Add* imports a public Git repository as the project's first version.\n4. **Release target and first publish.** The project's*Settings → Policy* gets a Release section\n(a ready example is offered), which says how to build the site and which Cloudflare Worker runs\nproduction. Then*Versions → Publish this version* : prepare, approve publishing, publish.\n5. **Staging.** A Staging section in the Policy turns on always-on staging. Staging starts from what\nproduction runs, so the first publish comes before it.\n6. **Invite the client.*** Members → Invite* , role Client, with access to the project. Clients see\nonly the projects they are given. Then choose, under*Settings → Access* , what they can do with\neach folder:**Can change** (their agent changes it, and the change goes to staging for review),**Read only** , or**No access** . A new client reads only until you choose.\n7. **The client asks for a change.** The client creates a task on the**Tasks** board: a title and\nwhat they want, nothing else. Which folders the agent may change, only read, or never see comes\nfrom the access the owner set in step 6, not from the client.\n8. **An agent does it.*** Give to agent* has one button,**Copy prompt for your agent** . The\nperson pastes the prompt into a coding agent that can run commands (the Code tab in Claude\nDesktop, Codex, Claude Code, Cursor, …). The agent installs`cforge` if it is missing, signs in\nwith a one-time code that the button puts in the prompt, checks the task out into its own copy\nof the task's folders, does the work and finishes with`cforge submit` . The same steps, to run\nby hand, are folded away under the button.\n9. **Staging and review.** The submitted change goes to the shared staging site by itself and moves\nto*In staging* . The client tries it there.\n10. **Production.** The client who asked for it (or a developer) promotes it from the board. It\nreaches production once it is approved and published; publishing is a separate, explicit step\n(owners by default).\n\nWithout staging, the same work goes through **Changes** instead: *New task*, *Give to agent*,\nthen *Make proposal* once the agent submits. The proposal opens as a Change storyboard: validation\nruns the project's checks, then approve, accept as a new version, and publish are three separate\nrecords. Clients of such a project edit a filtered **edition** copy and send it back as a proposal.\n\nUnderneath:\n\n- Every task works in its own isolated Artifacts repository, with short-lived credentials scoped to that repository. Clients' editions have no access to the production repository.\n- A SQLite Durable Object ledger decides, atomically, what becomes the accepted version. Stale proposals are refused, approvals are bound to the exact proposal hash, and restore is a new forward version.\n- An integration runner in a Cloudflare Sandbox container does the git merge, the checks, the\npreview build and the push. The Artifacts API cannot write, so every write is a `git push` from\nthe runner.\n\nThe repository also hosts the reusable versioned-workspace engine (`@commonforge-org/*`: core,\nledger, providers, runner protocol, conformance suites) that other products can adopt.\n\n```\n web app / cforge CLI / agents\n            │  HTTPS (session cookie or bearer)\n            ▼\n ┌─────────────────────────────┐   signed jobs (Queue)   ┌──────────────────────────────┐\n │ commonforge-worker          │ ──────────────────────▶ │ commonforge-runner           │\n │ Hono API, auth, broker      │ ◀────────────────────── │ Sandbox container per job:   │\n │ OrgLedger DO (SQLite)       │   results, credentials  │ git merge/check/push, builds │\n │ D1 directory, outbox, cron  │   (service binding)     └──────────────┬───────────────┘\n └──────┬───────────────┬──────┘                                        │ git push\n        │ REST/binding  │                                               ▼\n        ▼               ▼                               ┌──────────────────────────────┐\n  R2 (assets,      Artifacts: <prefix>-<org>-canonical │ -tasks │ -editions repos      │\n  manifests,       └────────────────────────────────────────────────────────────────────┘\n  exports)         commonforge-preview: token-gated previews from R2 + a container per preview\n```\n\nThe Worker names are the demo instance's; a bootstrap deployment calls them `<name>-worker`,\n`<name>-runner` and `<name>-preview`. The HTTP API, deploy prerequisites and known deviations are\nin [apps/worker/API.md](https://github.com/CommonForge-org/commonforge/blob/main/apps/worker/API.md).\n\nCode comments and docs sometimes refer to \"plan §…\", \"PRD §…\", \"AT-NN\" (acceptance tests) or \"Task N\". These point to internal planning documents that are not published; the code, the tests and the docs in this repository are the source of truth.\n\n| Path | Package | What | \n|---|---|---|\n| `packages/core` | `@commonforge-org/core` | Identities, schemas, hashing, path policy, provider contracts | \n| `packages/ledger` | `@commonforge-org/ledger` | Acceptance invariants (pure `planCommit` ) over a`LedgerStore` port | \n| `packages/provider-cloudflare` | `@commonforge-org/provider-cloudflare` | Artifacts and R2 providers | \n| `packages/provider-local-git` | `@commonforge-org/provider-local-git` | Local bare-git provider (tests, offline, exit path) | \n| `packages/runner-protocol` | `@commonforge-org/runner-protocol` | Signed runner jobs, materialization plans | \n| `packages/conformance` | `@commonforge-org/conformance` | Provider and ledger conformance suites | \n| `apps/worker` | `@commonforge-org/worker` | Control-plane Worker + `OrgLedger` /`OpsGate` Durable Objects; also the preview and runner Workers (`src/preview` ,`src/sandbox` ) | \n| `apps/runner` | `@commonforge-org/runner` | Integration runner (Sandbox container image, or a Node process) | \n| `apps/web` | `@commonforge-org/web` | Web UI (React + Vite), served by the control-plane Worker | \n| `apps/cli` | `@commonforge-org/cli` | Developer CLI, binary `cforge` | \n| `apps/demo-agents` | `@commonforge-org/demo-agents` | Orchestrates three real agent sessions working concurrently | \n| `fixtures/` |  | The demo client project (\"Customer Portal\") | \n| `scripts/` |  | Bootstrap, teardown, deploy, the live CI harness, demo helpers | \n\nRequires Node.js 22 or newer, pnpm (the version pinned in `package.json`; `corepack enable`) and git.\nRun the whole product on your machine without a Cloudflare account:\n\n```\npnpm install\nscripts/dev-local.sh          # or: pnpm dev:local; PORT=8813 scripts/dev-local.sh for another port\n```\n\nOpen [http://127.0.0.1:8799](http://127.0.0.1:8799) and sign in as `owner@agency.e2e.test` (the only address allowed to\ncreate an organization; set `ADMIN_EMAIL=you@example.test` to change it). No email is sent: the\nsign-in link is printed in the terminal as\n`[commonforge dev] magic link for <email>: <link>` (and kept in\n`apps/worker/.wrangler/dev-local.log`). Open it in the same browser. To use the CLI against it:\n\n```\npnpm exec turbo run build --filter=@commonforge-org/cli      # bundles apps/cli/dist/index.js\nnode apps/cli/dist/index.js login --api-url http://127.0.0.1:8799 --email owner@agency.e2e.test\n```\n\nThe CLI's sign-in link (`…/auth/cli?code=…`) is printed in the server's terminal too; paste it\nwhen `cforge` asks, or run `cforge login --code <code>`.\n\nThis is the stack the local-stack e2e suite runs: the real control-plane Worker under\n`wrangler dev -c apps/worker/wrangler.e2e.jsonc`, with local D1, Durable Objects, R2 and queues,\nserving the real web app. Cloudflare Artifacts, the integration runner and the Cloudflare API are\nin-memory fakes, so git pushes, merges, checks and deploys are simulated, previews do not run, and\neverything starts empty on each run. `apps/worker/.dev.vars` is never read.\n\n`scripts/bootstrap.sh` deploys a complete CommonForge into your own Cloudflare account. It is\nidempotent: rerun it to update.\n\nYou need Workers Paid, Cloudflare Artifacts and Containers (Sandbox) on the account, Docker on your machine (the runner and preview images are built locally), Node.js 22+, pnpm and an API token. The token needs Workers Scripts, Workers R2 Storage, D1, Queues, Workers KV Storage, Containers and Artifacts: Edit, and Account Settings: Read. The Worker gets its own Artifacts-only token.\n\n```\nexport CLOUDFLARE_API_TOKEN=… CLOUDFLARE_ACCOUNT_ID=…   # wrangler + account API (never echoed)\nexport CF_API_TOKEN=…                                   # the Worker's Artifacts token (Artifacts: Edit)\nexport COMMONFORGE_DEPLOY_API_TOKEN=…                   # optional: release deploys (Workers Scripts + KV: Edit)\n\nscripts/bootstrap.sh --name acme --email-mode log --admin-emails you@acme.com --smoke   # a test deployment\nscripts/bootstrap.sh --name acme --admin-emails you@acme.com,@acme.com \\\n  --email-from login@acme.com --app-domain forge.acme.com --preview-domain preview.acme.net\nscripts/teardown.sh  --name acme                         # list what it created\nscripts/teardown.sh  --name acme --yes                   # delete it and verify nothing is left\n```\n\nCustom domains and the email sender's domain must be zones on the same Cloudflare account as the deployment. The app and preview domains must differ: previews run site code and never share the app's origin. Onboarding the sending domain to Cloudflare Email Service is a manual step that the script prints.\n\nPrerequisites, every flag, the token scopes, state and ownership rules, and teardown are in\n**[docs/SELF-HOSTING.md](https://github.com/CommonForge-org/commonforge/blob/main/docs/SELF-HOSTING.md)**. It also covers local development against real\nCloudflare resources, and the maintainers' scripts for the project's own demo and CI instances\n(`scripts/deploy-live.sh`, `scripts/deploy-ci.sh`, `scripts/ci-live/`).\n\n```\nnpm install -g @commonforge-org/cli\n```\n\nIt needs Node.js 22+ and Git. To run a CLI you changed yourself, build it from the source instead (Node.js 22+, Git and pnpm):\n\n```\ngit clone https://github.com/CommonForge-org/commonforge.git\ncd commonforge\npnpm install\npnpm --filter \"@commonforge-org/cli...\" build\nnpm install -g ./apps/cli\n```\n\nThen `cforge login --api-url <your app URL> --email <you>`. *Give to agent* in the app shows the\nrest, filled in for the task, and its **Copy prompt for your agent** lets the agent do all of this\nby itself. (The app's hand-off panel shows the same commands; a self-hosted copy that changes the\nCLI without publishing it can set `CLI_PUBLISHED` to `false` in\n[apps/web/src/lib/handoff.ts](https://github.com/CommonForge-org/commonforge/blob/main/apps/web/src/lib/handoff.ts) to show the source build instead.)\n\n`cforge mcp` gives an AI app tools to sign in, list projects and tasks, create a task, check it\nout and submit it. The app's **Account** page shows the setup for each app and makes the one-time\nsign-in code:\n\n- **Claude Desktop:** the`commonforge.mcpb` extension from the latest release. Open the file and click Install.\n- **Claude Code:**`/plugin install commonforge --marketplace CommonForge-org/commonforge`\n- **Codex:** a`[mcp_servers.commonforge]` entry in`~/.codex/config.toml` (see[apps/cli/README.md](https://github.com/CommonForge-org/commonforge/blob/main/apps/cli/README.md#use-it-from-an-ai-app-mcp) ).\n\nThe plugin and the Codex entry start the server with `npx -y @commonforge-org/cli mcp`, so they\nneed Node.js 22+ but no separate install.\n\nThe tools can do only what the signed-in person can; see [docs/LIMITATIONS.md](https://github.com/CommonForge-org/commonforge/blob/main/docs/LIMITATIONS.md)\nfor what is tested.\n\n```\npnpm install\npnpm build          # turbo: every package, the web app, the Worker bundles\npnpm typecheck\npnpm test           # unit and integration tests (miniflare, real git, fakes for Artifacts/runner)\n\npnpm --filter @commonforge-org/web exec playwright install chromium   # once\npnpm test:e2e        # Playwright: fixture-mode UI + the local stack (no credentials)\npnpm test:fault      # fault injection via COMMONFORGE_CHAOS flags + provider fault conformance\npnpm test:security   # the security acceptance tests across worker, runner, core, runner-protocol, conformance\npnpm test:live       # live-provider tests; need CF_API_TOKEN (CI runs them only when the secret is set)\n```\n\n[docs/LIMITATIONS.md §8](https://github.com/CommonForge-org/commonforge/blob/main/docs/LIMITATIONS.md#8-what-the-test-suites-fake-and-what-only-a-live-run-proves)\nlists, per suite, what is real and what is faked. [CONTRIBUTING.md](https://github.com/CommonForge-org/commonforge/blob/main/CONTRIBUTING.md) has the rest.\n\n**[Watch the demo on YouTube](https://youtu.be/m1paaT6kocQ)** (8:28, with chapters and captions):\na client's agents and the agency's agents build one feature in parallel, a conflict is caught\nbefore it ships, the change goes through staging to production, and then a fresh deployment is set\nup from this repository and a client hands a task to Claude Code.\n\nThe project runs its own demo instance of CommonForge on its Cloudflare account. The original\nscript, beat by beat, is [docs/DEMO-SCRIPT.md](https://github.com/CommonForge-org/commonforge/blob/main/docs/DEMO-SCRIPT.md).\n\nBefore anything depended on Artifacts and Sandbox behavior, each assumption the design rests on\nwas measured on a live Cloudflare account (evidence in `spikes/*/RESULTS.md`).\n\n|  | Assumption | Verdict | Consequence | \n|---|---|---|---|\n| A1 | Stale pushes are refused | PARTIAL: the server accepts `--force` , but never silently last-writer-wins | Every runner push uses `--force-with-lease` against the ledger's sha, one ref per push (`--atomic` is now refused) | \n| A2 | Forks are fast and survive parent deletion | PARTIAL: they survive; 2.5 s at 1 MB, ~50 s at 500 MB | Forks and creates run in queue steps. Forks cannot cross namespaces, so task repos are fresh repos seeded by the runner | \n| A3 | `git` runs in a Sandbox container and pushes to Artifacts | VERIFIED | Runner = Sandbox container, token injected on egress, internet off | \n| A4 | Token revocation stops in-flight pushes | VERIFIED: effective on the next request (~170 ms) | Candidate freeze = token revocation | \n| A5 | Custom refs and notes work | PARTIAL: over git yes; REST cannot resolve full ref names | The ledger stores shas; ref listing happens in the runner | \n| A6 | `pushed` events arrive within ~5 s | VERIFIED (p95 1.1 s); `repo.forked` /`imported` never arrive | Events are wakeups only, with a periodic sweep as the backstop | \n| A7 | Per-candidate preview hostnames | PARTIAL: needs a zone with wildcard DNS | Path-based, token-gated, expiring previews on one dedicated origin | \n| A8 | Wrangler ≥ 4.145 with a remote Artifacts binding | VERIFIED | `wrangler dev` always uses real credentials | \n| A9 | Rate-limit headroom for 100 task lifecycles | VERIFIED: 0 × 429 over 700 lifecycles | Cap of 25 concurrent fork/token operations per namespace | \n\n**Nothing in the core path is simulated** on a Cloudflare deployment (yours, or the demo\ninstance): real Artifacts repositories, real `git push` from a real Sandbox container, the real\nDurable Object ledger, R2, Queues, Email Service and real `wrangler deploy` releases. The local\nquickstart is the exception: it fakes Artifacts, the runner and the Cloudflare API, and says so.\n\nAlso labelled as not live:\n\n- The web app's **fixture mode** (`VITE_COMMONFORGE_FIXTURE=1` ) runs the UI on in-memory sample\ndata, always under a \"Fixture mode\" banner. Only the fixture-mode e2e suite uses it.\n- The e2e, fault and security suites replace Artifacts, the runner and the Cloudflare API with test doubles, and they say so.\n\nThe main shortcuts of this build:\n\n- Previews share one origin, the preview Worker's (a path per preview, token-gated, expiring).\n- There is one ledger Durable Object per organization.\n- Stale bases are refused, with no automatic rebase.\n- Sign-in is by magic link only.\n- No ArtifactFS: export is plain git bundles plus asset manifests.\n- No private Git import. A confirmed ZIP intake creates its resources empty: copying the archive in needs a runner step that does not exist yet.\n\nThe full, honest list is in [docs/LIMITATIONS.md](https://github.com/CommonForge-org/commonforge/blob/main/docs/LIMITATIONS.md).\n\nContributing: [CONTRIBUTING.md](https://github.com/CommonForge-org/commonforge/blob/main/CONTRIBUTING.md) and the [code of conduct](https://github.com/CommonForge-org/commonforge/blob/main/CODE_OF_CONDUCT.md).\nReporting a vulnerability: [SECURITY.md](https://github.com/CommonForge-org/commonforge/blob/main/SECURITY.md) (not a public issue).\n\nThe code is [MIT](https://github.com/CommonForge-org/commonforge/blob/main/LICENSE) © 2026 CommonForge contributors. Third-party licences:\n[THIRD_PARTY_NOTICES.md](https://github.com/CommonForge-org/commonforge/blob/main/THIRD_PARTY_NOTICES.md).\n\nThe CommonForge name and the logos in `brand/` are trademarks and are not covered by the MIT\nlicence; see [brand/README.md](https://github.com/CommonForge-org/commonforge/blob/main/brand/README.md).", "url": "https://wpnews.pro/news/show-hn-commonforge-let-clients-ai-agents-work-in-your-codebase-safely", "canonical_source": "https://github.com/CommonForge-org/commonforge", "published_at": "2026-10-15 15:11:09+00:00", "updated_at": "2026-10-15 15:23:30.708117+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "developer-tools", "ai-products"], "entities": ["CommonForge", "Cloudflare Workers", "Cloudflare Artifacts", "cforge", "Claude Desktop", "Codex", "Claude Code", "Cursor"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-commonforge-let-clients-ai-agents-work-in-your-codebase-safely", "markdown": "https://wpnews.pro/news/show-hn-commonforge-let-clients-ai-agents-work-in-your-codebase-safely.md", "text": "https://wpnews.pro/news/show-hn-commonforge-let-clients-ai-agents-work-in-your-codebase-safely.txt", "jsonld": "https://wpnews.pro/news/show-hn-commonforge-let-clients-ai-agents-work-in-your-codebase-safely.jsonld"}}