Status: proposed behavior for review.
This document describes what repository administrators, contributors, agents, and operators experience. It intentionally separates requested configuration, successful build output, provider readiness, preview availability, and production publication.
A repository administrator may enable the default Deploy project when all of the following are true:
sites.smol.ai Alpha period, the owning account and project have
Alpha access;Enablement records the actor, repository, project, terms version, configuration digest, policy-check results, feature entitlements, quotas, and timestamp.
The first UI exposes one default Deploy project per repository. The underlying model supports additional projects later without changing deployment identity. Self-service is limited to Alpha accounts until hosted content moves to a separate registrable domain.
The claimed hostname remains reserved to its original project through disablement, suspension, repository deletion, or Alpha revocation. Reservation does not guarantee continued serving or content retention: Forge may suspend the hostname and remove retained Alpha artifacts.
The current repository-level Sites area evolves into Deploy while retaining a Sites label for the static compatibility path.
The project overview shows:
Provider IDs may appear in an advanced diagnostic view. They do not replace Forge status or become part of stable product URLs.
Configuration is split deliberately:
forgeBuild.ts defines what the application needs:
The forward resource contract uses stable, repository-chosen logical names and behavioral requirements rather than provider product names. It permits multiple resources of the same semantic kind. This is a design goal rather than current v1 syntax: the shipped v1 contract still exposes one application with built-in managed state and realtime.
Provider-specific configuration is allowed only under an explicit
provider.<name> namespace. The Deploy UI and deployment receipt identify the
affected capabilities as non-portable, show the selected provider resources in
advanced evidence, and never imply that a provider extension can be migrated
without semantic or data-movement work.
The Forge control plane defines what the application is allowed to do:
The effective plan is the intersection of repository intent and trusted policy. A commit cannot grant itself broader egress, public preview access, production authority, higher quotas, provider credentials, or resource deletion rights.
Each production environment has one policy:
| Policy | Behavior |
|---|---|
auto |
Publish an eligible ready deployment automatically. This is the default only when the production branch satisfies the protection and check baseline. |
owner_review |
Require an authorized repository administrator to promote. |
environment_review |
Require an actor named by the protected environment policy. |
Even auto requires:
An agent has no separate production authority. An agent may push an authorized task branch and open or update a pull request. Production follows the normal merge, check, and environment policy.
For an auto environment, anyone authorized to merge or directly update the
protected production branch is deliberately a production deployer. If the
branch or check baseline does not meet this contract, Forge changes the
effective policy to owner_review; it does not silently retain auto.
Because application code can mutate retained production state and emit to
connected realtime clients, the project UI must make this delegated production
authority explicit when auto is selected. Rollback changes code and routes;
it does not restore durable state or already delivered events.
On sites.smol.ai, auto may replace the active deployment for an enrolled
project after exact-SHA, build, ingest, runtime, eligibility, and
compare-and-set checks pass. Removing the project or account from the trial
stops all of its routes.
Initial triggers are:
A source, manifest, release-compiler, build input, or artifact-policy identity change creates an environment-neutral release and builds its artifacts once. An environment-policy, plan-compiler, or provider-adapter change creates a new deployment from an existing ready release when its artifacts remain compatible; it does not rebuild merely to refresh provider state.
Forge applies each eligible ready release as an immutable preview deployment. Publication creates or reuses a distinct production deployment from the same release artifacts and binds the stable production state scope.
Automatic branch and pull-request previews should use the same durable ref-change event path as Git receive, API-created commits, merges, and future imports. They are added only after that unified event and outbox boundary exists. Agents can still create previews through ordinary authorized pushes and manual exact-SHA deployment during the initial dynamic release.
The UI presents one pipeline while preserving four separate state machines.
| State | Meaning |
|---|---|
queued |
Exact SHA accepted and waiting for compilation or capacity. |
planning |
Repository intent and the build graph are being normalized. |
building |
Immutable environment-neutral artifacts are being produced. |
ready |
All required release artifacts passed trusted ingest. |
failed |
Compilation, build, or ingest failed. |
cancelled |
An authorized cancellation reached a terminal state. |
A ready release remains ready. Activation and rollback do not mutate release readiness.
| State | Meaning |
|---|---|
queued |
A ready release is waiting to apply to an environment. |
applying |
Trusted adapters are provisioning the application's provider components. |
verifying |
Every applicable application component and shared gateway path is undergoing readiness checks. |
ready |
The release is usable in this environment and may be previewed or activated. |
failed |
A required application component or policy gate failed. |
cancelled |
The environment application was cancelled. |
expired |
A preview deployment and its unpinned endpoint reached retention. |
All applicable application components are required in the initial version. Assets-only sites do not wait for HTTP, state, or realtime. Realtime-disabled sites verify the denial policy instead of provisioning a transport.
An environment activation is requested, applying, active, failed, or
compensated. awaiting_promotion, live, and superseded are UI
projections from publication policy and activation history rather than
deployment states.
An endpoint is pending, active, revoked, retired, or expired.
Endpoint expiry does not delete release artifacts or provider versions pinned
by active or rollback-eligible production deployments.
The UI exposes release, application-component, resource-instance, operation, activation, and endpoint evidence. Provider components remain an advanced diagnostic. A failure shows which actions completed, whether cleanup is pending, and whether durable state changed.
Each ready preview deployment receives a preview such as:
https://preview-{128-bit-random}.sites.smol.ai
Preview access is snapshotted per deployment:
| Mode | Behavior |
|---|---|
public_unlisted |
No authentication; high-entropy URL, no public enumeration, and noindex. |
repository |
Only authorized repository members. |
share_token |
Anyone with a scoped, revocable share link. |
During the trial, public_unlisted is the default. The other modes remain
reserved until their edge authentication and revocation paths are implemented.
An unlisted URL is never described or treated as authenticated.
Repository access means any current actor with repository read permission. Membership removal, repository visibility changes, token revocation, or suspension increments an access epoch checked by the edge on every request.
Repository-authenticated previews use an edge-owned flow:
/.forge/access/bootstrap#code=...; the code remains in the fragment and is
not sent in an HTTP request or referrer./.forge/access/exchange. The
exchange is consumed before any repository code runs and all code fields are
redacted from logs.Secure, HttpOnly, host-only
__Host-forge-access cookie with Path=/ and redirects to a clean return
URL.Exact /.forge and the /.forge/* namespace are reserved and cannot be
claimed by application routes. Forge bearer tokens and control-plane
credentials are never sent to preview origins.
Share links use the same edge-owned bootstrap boundary:
/.forge/access/bootstrap#share=..../.forge/access/exchange before repository code runs.Secure,
HttpOnly, host-only __Host-forge-access cookie with Path=/; the raw
secret and credential are excluded from request and platform logs.Share secrets are scoped to one deployment and hostname, replaceable without rebuilding, and never placed in an ordinary query string or path.
Visibility changes, token revocation, repository visibility changes, deletion, disablement, and suspension must take effect without waiting for an immutable asset cache lifetime.
Production initially resolves:
https://{project}.sites.smol.ai
Production points to one ready application deployment. Promotion applies an existing ready release to the stable production environment; rollback selects or reapplies a previous release. Neither action rebuilds artifacts.
Rollback:
The UI must distinguish an immediate pointer rollback from a provider re-activation that is still reconciling.
Rollback changes application code, assets, and routes only. Durable state does not roll back. Activation and rollback increment a realtime generation, stop new connections to the old generation, allow a short drain, and then close remaining sessions so clients reconnect and fetch a fresh snapshot. Stateful projects require an explicit acknowledgment, and Forge blocks any rollback that violates a declared application compatibility rule.
Repository authors deploy one application. They are not asked to choose between a Worker, Durable Object, key-value store, or companion realtime service. Forge exposes one portable runtime and compiles it into provider components.
Every application entrypoint may use env.forge.state. State storage is
retained only after a successful mutation, so an application that never
writes provisions no per-project data. An assets-only application creates no
state usage.
The initial adapter uses Forge-owned SQLite-backed Durable Objects behind a trusted gateway; repository code receives neither a raw namespace nor a custom object class. Each project uses a fixed 16-shard production pool and each preview uses four shards; a trusted hash maps caller-selected scopes into that bounded pool.
Operations are strictly serializable within one caller-selected scope. There are no cross-scope transactions. A mutation may atomically commit state changes plus a versioned realtime event intent, which makes common reservation, counter, room, and coordination workflows safe without additional infrastructure. Live delivery remains best effort.
Production state belongs to the stable production environment and persists across deployments. Every immutable preview receives deployment-isolated state with a retention TTL. Preview data is never promoted into production, and rollback never rewinds production data. Destruction is a separate authorized operation with an impact summary and retention policy.
Every application entrypoint may use env.forge.realtime; the provider path
materializes only when a state mutation emits an event or a client subscribes.
The browser SDK subscribes through a reserved Forge endpoint. Repository code
does not handle raw socket upgrades, connection lifecycle, or provider
identifiers. Application code authorizes an ordinary HTTP request and directly
returns an opaque subscription grant scoped to one state scope and topic. Only
the trusted wrapper can turn that grant into ticket bytes, and the browser
cannot choose a different scope after authorization.
Realtime is a convenience view over authoritative durable state:
(scope, topic) and carry a
state version;Connections, fan-out, bytes, topics, and lifetimes have conservative default ceilings. A repository may lower its limits. Raising them is an audited plan or feature-entitlement change, not a manifest request that silently increases spend. Realtime quota exhaustion stops realtime first and preserves normal HTTP, assets, and durable-state operations. A state mutation still commits when its event is suppressed; the sequence advances and affected clients are forced to resynchronize.
Activation, rollback, preview expiry, disablement, access revocation, and suspension invalidate affected sessions. Re-enable or unsuspend starts new authenticated sessions; it never restores old sockets or tickets. Suspension wakes the fixed shard pool, makes sessions inert through a fail-closed state/event gate, and then closes hibernating sockets.
Custom Durable Object classes, alarms, raw WebSocket handlers, client
publishing, durable replay, and user-directed networking from managed state or
realtime components remain deferred. Cloudflare Outbound Workers do not
intercept Durable Object fetch() calls, so Forge does not run repository code
inside those components.
Each Deploy project receives one conservative application profile. A repository administrator can configure, per site:
These settings describe outcomes and budgets, not provider products. The UI
does not ask whether to create a Worker, Durable Object, namespace, or
companion service. Repository limits may lower the trusted project settings.
Only an audited entitlement or plan change can raise them.
Build and runtime egress have separate policies.
The default runtime mode is a per-project allowlist. The requested destinations are versioned with the deployment plan, while the trusted control plane applies the final ceiling.
A project may receive a broad_public_egress feature flag. This means
"arbitrary public Internet destinations through Forge's controlled outbound
layer," not raw unrestricted networking. The outbound layer still blocks
private and platform infrastructure, validates DNS and redirects, applies
ports and size limits, meters usage, records bounded audit evidence, and
supports immediate revocation.
All user-authored external requests originate in the application HTTP runtime and pass through the provider outbound policy. Forge-managed state and realtime components do not make user-directed external requests. Runtime code cannot modify its own egress entitlement.
The existing restricted runner remains the build foundation:
Before dynamic artifacts are accepted, trusted ingest additionally requires file-identity and link-count checks, digest verification after the sandbox is quiescent, and tests for hard links and same-size mutation.
Every build network path applies the same private, loopback, link-local, metadata, internal-service, unsafe-port, DNS-at-connect, redirect, DNS-rebinding, credential, size, duration, and quota protections as runtime egress. The permitted public dependency registries form a separate build allowlist; the project's runtime egress setting never widens it.
Dynamic build output may include one Forge application bundle. Repository deployment commands and provider CLI credentials remain prohibited.
Users can inspect:
Large logs and artifacts live in object storage. Control-plane records hold bounded summaries, indexes, digests, and references.
Logs must be attributable to tenant, project, environment, deployment, application component, operation, and source SHA. Provider secrets, preview tokens, realtime tickets, bearer tokens, request credentials, and configured sensitive values are redacted before storage or display. Realtime message bodies are not logged by default.
At minimum, meter and enforce:
Every billable or externally mutating operation carries a tenant, project, deployment or resource target, idempotency key, and audit attribution.
Account and global circuit breakers must stop denial-of-wallet conditions even when an individual project remains within nominal quotas.
Repository administrators may disable a project immediately. Platform operators may suspend a repository, project, deployment, hostname, preview, runtime, account, or organization.
Serving checks current repository, project, deployment, access epoch, realtime generation, and suspension state before routing. Artifacts and provider endpoints are never exposed as an unguarded storage bypass.
A private, unlisted, deleted, or suspended source repository disables its public Deploy project immediately. Historical deployment and hostname records remain for audit and takeover prevention.
Suspension takes precedence over publication, rollback, feature flags, cached previews, and repository-admin actions.
State transitions are explicit:
| Event | Routing and triggers | Retained state | Resume |
|---|---|---|---|
| Repository admin disables project | Stop routing and new triggers; increment desired, access, and realtime generations; drain active sessions; fence in-flight operations. | Active pointer, releases, deployments, hostname claims, and durable state remain. | Admin re-enables after fresh eligibility checks and explicitly confirms the prior active deployment. |
| Source becomes private or unlisted | Apply a source-visibility eligibility block immediately; stop routing and triggers. | Project state, pointer, history, hostname claims, and resources remain. | Returning public removes only the source block; an admin must revalidate before serving resumes. |
| Source is deleted | Stop routing and triggers; tombstone repository and hostnames. | Audit history and hostname tombstones remain; resource retention policy begins. | No automatic resume. Repository restoration and operator review are required. |
| Platform suspension | Stop routing, previews, triggers, promotion, rollback, and provider mutations except containment; revoke tickets and close active realtime sessions. | Evidence and quarantined resources remain under operator policy. | Only an authorized operator may lift suspension. |
| Billing or quota block | Stop new builds and mutations; serving behavior follows plan policy and global safety limits. | Existing releases and resources remain. | Reconcile eligibility before queued work or serving resumes. |
Disablement and every blocking transition invalidate provider-operation leases. Public restoration, payment, or flag changes never resurrect a stale operation.
The operator surface supports:
The target suspension propagation SLO must be published and verified before production graduation.
Initial flags should be explicit control-plane entitlements:
deploy_application;broad_public_egress;realtime_extended_limits;explicit_provider_placement;railway_service;modal_job;runtime_secrets.Durable state is part of deploy_application and has no separate provider
feature flag. Managed realtime works within its conservative default limits;
realtime_extended_limits authorizes only reviewed higher ceilings. Feature
flags cap requested behavior. They are never passed to user code as provider
credentials or management authority.
Before constrained dynamic Deploy is enabled: