# Forge Deploy Alpha builder guide

This guide is for repository administrators and application builders. It
explains how to configure and operate an application in the current Alpha. For
the product boundary, release model, and operator-facing contracts, see the
[Forge Deploy overview](README.md).

Forge Deploy turns an exact SmolForge Git commit into a public application at
`{project}.sites.smol.ai`. The current Alpha supports immutable static
assets, an HTTP Worker, Forge-managed durable state, and bounded realtime
without asking an application author to provision Cloudflare resources.

The Alpha is available to eligible public repositories whose administrator has
accepted the current Forge Deploy Terms and whose account and project have
Alpha access. It is a real hosted service, but `sites.smol.ai` is a
pre-production domain and the runtime contract may change before general
availability. A claimed hostname remains reserved to its original project and
is not reassigned, while Forge may suspend serving or revoke retained Alpha
content.

## Why Forge instead of deploying directly to Cloudflare?

Cloudflare provides the runtime, storage, networking, and state primitives that
make Forge possible. Forge Deploy adds a Git-native release control plane above
them:

| Deployment concern | Direct provider deployment | Forge Deploy |
| --- | --- | --- |
| Source identity | The command publishes whatever code and generated assets are present in the invoking checkout. | Forge reads one exact pushed Git SHA and freezes its configuration, application code, and assets into one deployment. |
| Before production | A deploy command may update the live Worker and bundled frontend together. | Every successful build receives an immutable preview. Provider publication, preview readiness, and production activation remain separate states. |
| Stale releases | Preventing an older checkout from becoming production depends on release procedure. | Automatic activation rechecks that the exact SHA is still the configured branch head and that protection policy and required checks still pass. |
| Partial provider success | If the provider changes traffic but the client loses the final receipt, operators must determine which side committed. | Forge retains the activation intent. A retry recognizes the exact target already active, records the provider receipt, and completes the Forge pointer without switching traffic again. A different active version fails closed. |
| Rollback and evidence | Operators correlate Git, build output, provider versions, and traffic changes themselves. | Forge records source, configuration, build, provider, preview, and activation evidence together. Rollback moves the production pointer to a prior ready deployment without rebuilding or rewinding durable state. |

Forge does not replace Cloudflare's platform. It removes common deployment
footguns by withholding provider credentials from repository builds, publishing
immutable candidates before traffic changes, and making deliberate promotion or
rollback explicit and auditable. Connected Cloudflare applications can retain
their existing bindings and production domain while adopting this release
workflow.

## Forge deploys Forge

Forge's API and web application are the first platform dogfood target for this
release model. Their checked-in `forgeBuild.ts` imports the API Worker's
Wrangler configuration as inert data, builds one exact Forge commit, and
publishes an immutable connected Worker Version without changing traffic.

A platform administrator verifies that candidate through its Forge preview
before promoting it. Production activation:

- is serialized per connected Worker;
- requires the provider's current version to match the version recorded when
  the candidate was built;
- moves exactly one immutable version to 100 percent traffic;
- records the Cloudflare deployment receipt beside the Forge deployment; and
- remains idempotent when an already-active target is retried.

If Cloudflare commits the traffic change but the final receipt read fails, the
same promotion is safe to retry. Forge recognizes the exact target already
active, records the provider receipt, and completes its own production pointer
without changing traffic again. If a different version became active, the
expected-current fence fails closed instead.

Forge requires Cloudflare's standalone per-version Preview URL before a
connected release becomes ready. It enables Preview URLs on the approved
Worker, preserves the existing `workers.dev` setting, and never stages preview
candidates into the production deployment. Because Cloudflare does not
generate those URLs for Workers that implement Durable Objects, Forge keeps one
bounded 0%-traffic candidate addressable through a version override while
production remains at 100%. Publishing another such candidate replaces the
preview slot, so historical Durable Object previews are not immutable archives.
Keep the Durable Object behind a separately connected service when retained
previews matter.

`forge.smol.ai` remains attached directly to the API Worker. It is not served
through the user-content Sites edge, so a Sites routing failure cannot hide the
control plane. Wrangler administrator access remains an independent
provider-level recovery path. Forge owns the normal exact-SHA release and audit
workflow; Cloudflare remains the runtime and the final break-glass authority.

This split is deliberate. Self-deployment should prove Forge's release contract
against its own application without making the application its only means of
recovery.

## Configure a repository

Install the public authoring package for editor types and local validation:

```bash
npm install --save-dev @smolai/forge
```

Add `forgeBuild.ts` at the repository root:

```ts
import { defineForge } from '@smolai/forge/config';

export default defineForge({
  version: 1,
  name: 'my-app',
  app: {
    entrypoint: 'src/server.ts',
    assets: {
      directory: 'dist',
      fallback: 'index.html',
    },
  },
  routes: [
    { pattern: '/api/*', to: 'app.http' },
    { pattern: '/*', to: 'app.assets' },
  ],
});
```

The manifest is the checked-in build contract, not an activation switch. After
committing it, open the repository's **Sites** page, create the corresponding
Deploy project, accept the current Deploy Terms, and enable the project.
`npx smolforge deploy check` validates the file locally and cannot confirm those
account- and repository-level steps.

Check the configuration locally, then push normally:

```bash
npx smolforge deploy check
git push origin main
```

Forge reads and statically evaluates `forgeBuild.ts` from the exact pushed
commit before scheduling repository code. The evaluator accepts a deliberately
small data-only TypeScript subset; it never imports or executes the repository
file. See the complete [`forgeBuild.ts` v1 specification](manifest-v1.md) and
the versioned, structural
[JSON Schema](https://forge.smol.ai/spec/deploy/v1/schema.json). The schema is
useful for tooling; `smolforge deploy check` remains the authoritative local
syntax and semantic check.

Monorepos keep one `forgeBuild.ts` in every configured project root. They may
also add a static root `.forge/config.json` to list project roots, defaults,
and reviewed Cloudflare binding proposals without executing repository code.
Inspecting and importing that file does not enable a project or apply provider
state. See [Repository configuration](repository-config.md) and its
[JSON Schema](https://forge.smol.ai/spec/deploy/v1/repository-config.schema.json).

`forge.yml` and `forge.yaml` are no longer accepted for new deployments. Existing live
deployments remain online until they are replaced, rolled back, disabled, or
suspended.

## What applications receive

- **Assets:** immutable, content-addressed files with safe MIME types, hardened
  response headers, directory indexes, and optional SPA fallback.
- **HTTP:** one isolated application handler behind Forge-owned routing.
- **Durable state:** scoped reads, snapshots, lists, and atomic mutations,
  including compare-and-set-style assertions.
- **Realtime:** state-bound events, hibernating WebSockets, authoritative
  snapshot recovery, and bounded polling fallback after technical failure.
- **Deployments:** immutable previews, automatic or manual publication,
  promotion, rollback by pointer, disablement, logs, and exact-SHA receipts.

Forge owns the provider topology. Application code uses `env.forge` rather than
choosing Workers, Durable Objects, namespaces, or provider credentials.

## Write an HTTP and state handler

An entrypoint exports one object with an asynchronous `fetch` method:

```js
export default {
  async fetch(request, env) {
    const url = new URL(request.url);
    const counter = env.forge.state.scope('counter/main');

    if (request.method === 'GET' && url.pathname === '/api/counter') {
      const snapshot = await counter.snapshot({
        topic: 'value',
        prefix: 'counter/',
      });
      const value = snapshot.entries
        .find(({ key }) => key === 'counter/value')?.value ?? 0;
      return env.forge.realtime.snapshotResponse(request, {
        type: 'forge-snapshot',
        data: { value },
        cursor: snapshot.realtimeCursor,
      });
    }

    if (request.method === 'POST' && url.pathname === '/api/increment') {
      return Response.json(await counter.mutate([
        { increment: { key: 'counter/value', delta: 1 } },
        { emit: { topic: 'value', event: { type: 'incremented' } } },
      ]));
    }

    if (request.method === 'GET' && url.pathname === '/api/subscribe') {
      return env.forge.realtime.authorize(request, {
        scope: 'counter/main',
        topic: 'value',
      });
    }

    return Response.json({ error: 'Not found' }, { status: 404 });
  },
};
```

`scope(name)` provides `get`, `list`, `snapshot`, and atomic `mutate`.
Mutations support `assertAbsent`, `assertVersion`, `put`, `delete`,
`increment`, and state-bound `emit`. All operations in one mutation either
commit together or fail together. Production state is stable across code
deployments and rollbacks; preview state is isolated by deployment.

Browser pages load the versioned `/.forge/client.js` SDK and subscribe using an
application authorization endpoint plus an authoritative snapshot endpoint.
The SDK connects and buffers before fetching the snapshot, detects gaps, and
resynchronizes automatically. See the complete
[application runtime contract](application-runtime-v1.md) and the
[realtime fixture source](https://forge.smol.ai/swyx/deploy-realtime-fixture).

## Fast deployments

Buildless repositories can use Forge's trusted fast path. Forge reads
`forgeBuild.ts`, committed assets, and a self-contained JavaScript entrypoint
directly from its Git object store, then reuses content-addressed artifacts.
Repositories with build commands, TypeScript compilation, imports, or generated
assets continue through the restricted exact-SHA sandbox.

The three conformance fixtures improved from 12.7–15.2 seconds to 2.6–2.7
seconds from deployment creation to live publication:

| Fixture | Before | Current | Improvement |
| --- | ---: | ---: | ---: |
| Static SPA | 12.747 s | 2.674 s | 4.8× |
| Durable reservations | 15.210 s | 2.558 s | 5.9× |
| Durable realtime | 14.779 s | 2.719 s | 5.4× |

Try the live fixtures:

- [Static assets and SPA fallback](https://deploy-static-fixture.sites.smol.ai)
- [Atomic durable reservations](https://deploy-reservations-fixture.sites.smol.ai)
- [Durable state and realtime](https://deploy-realtime-fixture.sites.smol.ai)

Each fixture explains the behavior it proves and links to its own SmolForge
source repository.

## Overrides and publication

The repository file is authoritative by default. A repository administrator
may explicitly override the build command, asset directory, or SPA fallback in
Forge. The Deploy page shows both source and effective values and records who
configured each override.

Saving an override never silently deploys. The administrator chooses **Save
only** or **Save and deploy current branch head** for every edit.

Production publication defaults to automatic after a successful eligible push.
Manual publication, redeploy, promotion, rollback, and immediate disablement
remain available.

Automatic production publication is additionally gated by Forge's protected
branch baseline: the exact source SHA must still be the configured branch head,
required Forge checks must pass, and the project's protection policy must allow
automatic activation. A successful build still receives an immutable preview
when production activation is blocked.

Rolling back moves the active code and asset pointer without rebuilding. It
increments the runtime generation, invalidates old subscription tickets, and
drains affected realtime connections. Production durable state is deliberately
not rewound.

## Enrollment and lifecycle

An eligible repository administrator completes the controlled-trial flow in
the repository's Deploy page:

1. confirm that the source repository is public and active;
2. review and accept the current versioned Forge Deploy Terms;
3. pass the account and project Alpha-access checks; and
4. enable the site and choose automatic or manual publication.

Making an enabled source private, unlisted, deleted, or suspended immediately
stops production and preview serving, tickets, state mutations, and realtime
connections. Making it public again does not silently re-enable the site; an
administrator must explicitly enable it.

Every preview has a seven-day retention deadline. Forge retains the two newest
successful rollback candidates for each site, then deletes expired immutable
assets, Forge-managed runtime scripts, and Forge-published connected-account
Worker Versions in retryable batches while preserving deployment, provider
receipt, and cleanup history. Connected version retirement shares the
per-Worker activation fence, rechecks current provider deployment membership
immediately before deletion, removes the exact version from a zero-percent
preview slot when necessary, and treats an already-absent version as successful
reconciliation. The 100-percent production version is never a cleanup target.
Forge never deletes the Worker, routes, domains, schedules, or
bound KV, D1, R2, and Durable Object data. Running deployments, the active
deployment, and the two newest successful rollback candidates are never
selected for cleanup.

## Preview security and current limits

Preview URLs use 128 bits of randomness, are unauthenticated, unlisted, and
served with `noindex`. This provides discovery resistance, not confidentiality.
Do not put secrets or private data in a preview.

The current release intentionally excludes private-source builds, runtime
secrets, custom domains, arbitrary Workers or Durable Object classes,
repository-controlled provider bindings, and unrestricted outbound networking.
Runtime egress is denied by default. Resource, connection, event, recipient,
session, and byte ceilings are enforced by Forge rather than by application
cooperation. Access and quota denials are terminal: the browser SDK does not
turn an authorization or cost refusal into repeated WebSocket or polling
traffic.

The trial records configuration, exact SHA, build phases, provider versions,
activation/rollback, access changes, runtime invalidation, usage, and retention
operations. These receipts let an operator distinguish a successful build
from provider publication, preview readiness, production activation, and live
hostname verification.

## Shipped conformance evidence

The 2026-07-24 Phase 0–2 release gate proved:

- ten concurrent claims for one new booth produced one `201` and nine `409`
  responses;
- production reservations remained byte-for-byte present across a rollback to
  earlier code and restoration to current code, while the preview state was
  empty;
- two realtime clients received the same state-bound event, the first 20
  preview connections succeeded, and the 21st received terminal `429`
  `realtime_quota`;
- an expired synthetic preview artifact was removed from R2 while its
  deployment and cleanup history remained queryable; and
- a static rollback remained selected through the reconciliation soak and did
  not create a duplicate build for the current branch head.

For deeper implementation and security details, see the
[Deploy documentation index](README.md).
