A fully-realized GitHub clone built entirely on Cloudflare infrastructure. Push code, browse files, manage issues, create pull requests — all backed by Workers, D1, R2, and Durable Objects.
Live: forge.smol.ai · Engineering blog: forge.smol.ai/blog · RSS: feed.xml
SmolForge implements the core GitHub experience from scratch: user auth, repository CRUD, independent repository forks, the Git Smart HTTP protocol (push/clone/fetch with a real git CLI), file browsing, branch management, issues, pull requests, collaborators, and an organization/team permission system. Forge also provides a versioned SKIT registry for distributable skill bundles.
Forge is now a routed Cloudflare system rather than a single Worker. Thirteen independently released Workers separate the public edge, identity, content control, repository data plane, deployment control plane, notifications, build runner, hosted-site edge, deployed-application runtime, wiki, content delivery, AI routing, and Slack agents. They share explicit contracts and are built, tested, and released according to project impact.
Forge began in a single session using Claude in Cowork mode, with early scaffolding help from ralph-claude-code for autonomous development loops. The system has since grown into the component architecture below.
forge.smol.ai
|
+-------v-------+
| public edge |
| web/blog/docs |
+-------+-------+
|
+------------+------------+------------------+
| | | |
+------v------+ +---v--------+ +--v----------+ +-----v--------+
| identity | | content | | repository | | deploy-control|
| auth/account| | gists/cards| | Git + repos | | projects/releases |
+-------------+ +------------+ +------+------+ +------+-------+
| |
+--------v--------+ +--------v--------+
| runner / wiki / | | deploy-runtime / |
| notifications | | sites-edge / AI |
+-----------------+ +-----------------+
control D1 + domain D1s · R2 Git/artifacts · Durable ObjectsThe component graph is declared in config/forge-components.json. Identity, repository, Deploy control, and notifications have independent workspace entrypoints and Wrangler contracts; packages/api is their internal implementation kernel while feature code is moved to its final owner. Changes are routed to affected validation suites and runtime components, with a fail-closed full gate when ownership cannot be established.
Cloudflare D1 stores relational state behind explicit domain ownership. The
current product/control-plane source is cloudforge-next; an executable
inventory in config/forge-database-domains.json
maps every canonical table to its future database and reports cross-domain
foreign-key blockers. Domain databases are additive shadow targets until
schema, row-count, and content-digest parity pass and the owning runtime has no
cross-domain transaction. The AI router already owns its reservation and
immutable invocation ledger in cloudforge-ai-usage.
Cloudflare R2 stores Git objects, packfiles, release artifacts, and other immutable blobs. Git objects are keyed by repository and object SHA.
Durable Objects provide repository coordination and one small publication lane per production Worker. Each lane stores only serialization, a monotonic fence, and the current in-flight deployment; Cloudflare's active deployment remains runtime truth.
Hono remains the Workers-native HTTP framework for the API components.
| Layer | Technology | Why |
|---|---|---|
| Runtime | Cloudflare Workers | Edge compute, zero cold starts, global deployment |
| Database | Cloudflare D1 (SQLite) | Serverless relational DB at the edge |
| Object Storage | Cloudflare R2 | S3-compatible, no egress fees, stores git objects |
| Concurrency | Durable Objects | Repo locks plus fenced production release authority |
| API Framework | Hono | Lightweight, Workers-native, great DX |
| Auth | JWT (HMAC-SHA256) + PBKDF2 | Stateless auth via Web Crypto API |
| Frontend | React 19 + React Router SSR + Vite + TailwindCSS | Edge-rendered public routes and hydrated product UI |
| Build/Deploy | Forge main generations + Wrangler | Complete PR previews, exact-main immutable versions, per-Worker fenced publication |
| Testing | Vitest | Fast, TypeScript-native test runner |
| Monorepo | npm workspaces | Simple, no extra tooling needed |
The most interesting part. SmolForge implements the Git Smart HTTP Protocol from scratch:
Endpoints:
GET /:owner/:repo.git/info/refs?service=git-upload-pack — Reference discovery (clone/fetch)GET /:owner/:repo.git/info/refs?service=git-receive-pack — Reference discovery (push)POST /:owner/:repo.git/git-receive-pack — Receive pushed objectsPOST /:owner/:repo.git/git-upload-pack — Send objects for clone/fetchWhat's implemented:
git clone (collects all reachable objects)multi_ack_detailed, no-done, and
immediate ACK <sha> ready pack streaming for incremental pullsThe packfile parser (packages/api/src/git/packfile.ts) includes a hand-written deflate stream scanner that traverses the block structure (stored, fixed Huffman, dynamic Huffman) to find object boundaries without decompressing — needed because packfile entries are concatenated zlib streams with no length prefixes.
The landing page intentionally keeps implementation details light. This section is the deeper technical reference for how the product surface is built.
public, unlisted, and private visibility. Unlisted repositories are readable by direct URL but excluded from public profiles and discovery.LICENSE, including for a repository's initial commit.cache: auto, cache: npm for download/tool caches, and cache: npm-exact for dependency snapshots. Generated Deploy builds choose auto; every cache identity includes the normalized project root so monorepo projects warm independently, and cache failures fall back to a clean install.needs, with real-time logs, cache timing telemetry, and cancel/rerun controls.Forge Deploy hosts authorized public or private repository applications at *.sites.smol.ai with
immutable assets, an HTTP Worker, Forge-managed durable state, bounded realtime,
exact-SHA previews, automatic or manual publication, and pointer-based
rollback. Applications describe their provider-neutral shape in a typed,
statically evaluated forgeBuild.ts.
Monorepos may also add a static root .forge/config.json to map project roots,
shared defaults, and reviewed Cloudflare binding proposals. It never replaces
the per-project forgeBuild.ts or grants builds DNS authority; inspect/import
and provider Apply remain separate administrator actions. See the
repository configuration contract.
Cloudflare remains the runtime provider; Forge adds the Git-native release control plane. It binds application code and assets to one exact commit, creates an immutable preview before production, blocks automatic activation when the branch has advanced, records the complete release receipt, and rolls back by moving a production pointer instead of rebuilding an old checkout.
Start with the public Forge Deploy preview guide,
the live forgeBuild.ts v1 specification,
or the three conformance fixtures.
Large public binaries can remain standard Git LFS pointers backed by Forge
Assets: OpenNext plans their exact provider identity from verified digests and
streams only provider-requested bytes instead of buffering a release in memory.
commit_sha uploads and AI-Session git trailers.sf add skit, sf skit install, skit add, and skit install use one
preservation-first implementation. Claude Code is the Stage 1 writable
target; other agent roots remain inventory-only until their compatibility
gates pass.content.snippet preservation sink during the verified semantic cutover.See SKIT Registry Stage 1 for the current contract.
The database spans users, repositories (including visibility, fork ancestry, and SPDX license metadata), refs, issues, comments, labels, pull requests, collaborators, organizations, teams, team members, stars, SKIT drafts/releases/skills, the minimal snippet migration sink, workflow configs, workflow runs, jobs, steps, logs, artifacts, secrets, transcripts, secret masks, webhooks, content blocklists, and content reports. Large SKIT and snippet bodies remain in content-addressed R2 objects.
forge/
+-- config/
| +-- forge-components.json # Component ownership and dependency graph
| +-- forge-releases/ # Per-component runtime contracts
+-- packages/
| +-- edge/ # Public routing, web assets, blog, RSS, social cards
| +-- content/ # Public content and blog metadata
| +-- web/ # React product UI
| +-- identity/ # Identity Worker entrypoint and provider contract
| +-- repository/ # Git/repository Worker entrypoint and provider contract
| +-- content-control/ # Gists, skins, and product social metadata
| +-- deploy-control/ # Deploy control Worker entrypoint and provider contract
| +-- notifications/ # Notification Worker entrypoint and provider contract
| +-- api/ # Internal implementation kernel during domain source extraction
| | +-- src/components/ # Component composition modules
| | +-- src/git/ # Git protocol and storage internals
| | +-- src/features/ # Domain implementations
| +-- runner/ # Trusted CI/build orchestration and provider adapter
| +-- deploy-runtime/ # Hosted application runtime
| +-- sites-worker/ # Hosted-site edge routing
| +-- wiki-worker/ # Wiki execution boundary
| +-- ai-router/ # Model routing + owned AI usage D1 ledger
| +-- slack-agent/ # Slack agent boundary
| +-- cli/ # `sf` / `smolforge` CLI
| +-- shared/ # Versioned cross-component contracts
+-- migrations/ # Canonical control schema plus generated domain schemas
+-- scripts/ # Validation, impact, contracts, and recovery tooling
+-- docs/ # Public guides plus excluded operational material
+-- examples/forge-deploy/ # Deploy conformance fixturesForge began as a single-Worker project built in one extended session. This is the origin story; the current component architecture is described above.
Scaffolding — Used ralph-claude-code to bootstrap the monorepo structure, set up Hono, and generate initial route stubs.
Git Protocol (the hard part) — Implemented the Smart HTTP protocol from scratch: packfile parsing with a custom deflate stream scanner, delta resolution (OFS_DELTA + REF_DELTA), pkt-line encoding, and object graph walking. This required reading RFC 1951 (DEFLATE), RFC 1950 (zlib), and the git pack format spec.
API Routes — Built out all CRUD endpoints: repos, issues (with auto-increment numbering and comments), pull requests, branches, commits, file browsing, and collaborators.
Frontend — 18-page React SPA with TailwindCSS: login/register, dashboard, repo view with file browser, issue tracker, PR management, branch list, commit history, and settings.
Deployment — Deployed the Worker to Cloudflare. Hit several issues:
/memberships endpoint failed with API tokens → switched to Cloudflare REST API for D1/R2 creationgit clone returned "bad line length character: PACK" → fixed sideband-64k encoding, then simplified to raw pack data without sidebandgit clone returned "bad object" → the want line parser wasn't stripping capabilities from the SHA[vars] binding conflicting with secret → removed from vars, set via wrangler secret put[assets] in wrangler.toml, eliminating CORS issuesTesting — 119 unit tests (pkt-line, objects, delta, packfile) + 20 API E2E tests + 32 privacy E2E tests, all passing.
Privacy Fixes — Found and fixed private repo info leaking via issues endpoint (returned data instead of 404 for unauthorized access).
Organization/Team System — Designed and implemented org-based auth: organizations, teams, team-repo mappings, role hierarchy (owner > admin > member), and permission levels (read < write < admin). See the organizations and teams design for the full design.
llms.txt)#SmolForge ships a comprehensive llms.txt file designed for AI coding agents (Claude Code, Codex, etc.) to consume programmatically. It includes:
The recommended setup is CLI-managed:
sf hooks install alice/demo --agent all --git post-commit,pre-push
sf hooks status alice/demoThis creates a repo-local upload script, installs native lifecycle hooks where available, and installs Git hook backstops for Codex and other agents. Codex is supported through the Git hook path and ~/.codex/sessions JSONL discovery. Git has no native post-push hook, so SmolForge uses pre-push for the final missed-upload check.
See llms.txt for the full guide.
SmolForge also ships an installable CLI package, @smolai/forge, with two equivalent binaries: smolforge and sf.
For new JavaScript and TypeScript repositories, Forge strongly recommends pnpm as the default package manager. Bun is the high-speed alternative when project compatibility allows. npm and Yarn repositories remain fully supported; Forge's UI and CLI provide advisory guidance and never silently migrate a project.
# npm
npm install -g @smolai/forge
# Homebrew, once the tap is published
brew install smol-ai/tap/smolforge
# Local formula from this repo
brew install --HEAD ./Formula/smolforge.rbBasic usage:
sf auth login --username alice
sf repo create demo --description "Edge-hosted git repo"
git remote add origin $(sf clone-url alice/demo)
sf auth git-credential alice/demo
sf auth status alice/demo
git push origin main
# Install transcript capture before agents start writing code
sf hooks install alice/demo --agent all --git post-commit,pre-push
sf hooks status alice/demo
# Upload Codex, Claude Code, Cowork, Cursor, Factory Droid, or other JSONL agent transcripts
sf transcript upload alice/demo --file ~/.codex/sessions/2026/03/29/session.jsonl
# Work with Actions and the live machine-readable API guide
sf actions list alice/demo --branch main --limit 5
sf llms --save llms.txtThe CLI defaults to https://forge.smol.ai and can be pointed at another deployment with --base-url or SMOLFORGE_BASE_URL.
The API login and repository Git credential are intentionally separate;
sf auth status owner/repo reports both states and gives the exact remediation
without printing a bearer. Repository credentials last seven days. On a trusted
durable machine, the CLI also guides users to the explicit broader mode:
sf auth login --git-scope global --expires never --yesThat mode creates a non-expiring repo:read,repo:write credential for every
accessible Forge repository, stores it only in protected OS storage, never
prints it, and makes sf auth logout revoke it. It is deliberately never the
silent login default.
Normal production releases validate an immutable pull-request SHA against the
workflow registered from base main, serialize the merge, then let one trusted
post-merge authority build and deploy the exact merged SHA under one production
lease and fence.
SHA="$(git rev-parse HEAD)"
sf release enqueue "$SHA" \
--ref codex/my-feature \
--repo swyx/forge \
--pr 123 \
--yes \
--json
sf release status merge_request_uuid --repo swyx/forge --json
sf release watch merge_request_uuid --repo swyx/forge --jsonEnqueue records durable merge state; it does not activate a provider inline.
After merge, the ProductionDeployer reloads workflow/config from merged main,
uploads affected immutable provider versions, performs observed-prior CAS,
verifies public health, and writes one compact append-only receipt. Retry uses
the same SHA with a new attempt and workflow run. The canonical observation
commands are sf release status/watch. See the
trusted release contract
and production runbook.
Queue validation reuses a successful trusted exact-SHA run for the same production base. Provider versions activate in dependency-safe waves. Each Worker owns its health binding list beside its runtime entrypoint, so adding a component does not edit one global binding registry or select every existing Worker.
This repository predates Forge's pnpm-first recommendation and intentionally retains its committed npm lockfile until a measured migration is performed.
# Install dependencies
npm install
# Start the API (with D1/R2 local emulation)
cd packages/api
npx wrangler dev
# In another terminal, start the frontend
cd packages/web
npm run devnpm run typecheck
npm test # Local-only unit and integration tests
npm run test:migrations # Clean schema plus data-preserving 0015 -> current-head upgrade
npm run test:smoke # Real Worker: push, clone, pull, issue, PR, and mergeRemote E2E tests are opt-in, require E2E_BASE_URL to name a disposable
staging deployment, and refuse known production hosts:
E2E_BASE_URL=https://staging.example.test npm run test:e2e:remote:api
E2E_BASE_URL=https://staging.example.test npm run test:e2e:remote:webProduction changes enter the protected merge queue with sf release enqueue.
After trusted affected CI passes, the queue advances main and hands the exact
merge SHA to ProductionDeployer. A release is complete only when
its canonical status is terminal, required components and bindings are healthy,
and the public verification receipt is recorded. A Git push or successful build
alone is not deployment evidence.
See production deployment for break-glass recovery, rollback, and smoke checks.
The archive/ralph/ directory contains files from the ralph-claude-code autonomous development loop that was used during initial scaffolding. These are preserved for historical interest — they show the prompts, fix plans, and session logs from the automated build process.