Forge AI is Forge-owned, profile-scoped model routing for deployed applications. Applications declare what an AI use case may do; Forge supplies the private runtime capability, provider credential, budget enforcement, and metadata-only usage receipt.
Forge AI is not a raw OpenAI proxy. Application code cannot choose provider URLs, credentials, arbitrary model IDs, gateway headers, or another tenant's billing identity.
Forge AI is one service in the Forge Sites application-services
stack. Site owners can discover it from the
repository's Sites page, then configure it beside Build and Identity in
forgeBuild.ts. The future Forge Agent is a separate roadmap capability; Forge
AI does not grant an end user agent or repository authority.
| Capability | Current Alpha contract |
|---|---|
| Logical model route | forge/text-fast@1 |
| Funding | Host funded only |
| Runtime | Server-side, non-streaming text messages |
| Native Forge JS | env.forge.ai.responses.create(...) |
| Connected Cloudflare Worker | env.FORGE_AI.responsesCreate(...) |
| Structured output | JSON mode and JSON parsing; the application must validate the object |
| Privacy | Prompt and completion content is not retained in Forge logs or usage rows |
| Production provider for connected Workers | Workers AI, selected by Forge |
BYOK, browser-direct invocation, streaming, tools, images, audio, embeddings, arbitrary models, caller-defined provider headers, and public HTTPS inference are not available. Forge has internal OpenAI-compatible adapters for OpenAI, Gemini, and Featherless, but applications cannot select them and connected Workers currently always use Workers AI.
Add the policy to app.ai.profiles in the project's forgeBuild.ts. Profile
names are the application-facing API; provider and model details stay behind
the logical Forge route.
import { defineForge, importWrangler } from '@smolai/forge/config';
export default defineForge({
version: 1,
name: 'overgrid',
build: { command: 'pnpm run build', workingDirectory: '.' },
app: {
entrypoint: 'dist/server/index.js',
assets: { directory: 'dist/client' },
ai: {
profiles: {
gameCommentary: {
model: 'forge/text-fast@1',
audience: 'server',
funding: ['host'],
maxInputTokens: 2_500,
maxOutputTokens: 180,
response: {
type: 'json_schema',
name: 'game_commentary',
schema: {
type: 'object',
additionalProperties: false,
required: ['line', 'factIds'],
properties: {
line: { type: 'string', maxLength: 320 },
factIds: {
type: 'array',
minItems: 1,
maxItems: 12,
items: { type: 'string' },
},
},
},
},
limits: {
requestsPerMinute: 10,
hostCostMicrosPerDay: 1_000_000,
previewHostCostMicrosPerDay: 50_000,
},
privacy: { contentLogging: 'off' },
},
},
},
},
routes: [
{ pattern: '/assets/*', to: 'app.assets' },
{ pattern: '/*', to: 'app.http' },
],
provider: {
cloudflare: {
wrangler: importWrangler('wrangler.toml', {
shareProductionResources: true,
}),
},
},
});Use audience: 'server' for connected Workers. Although the manifest parser
reserves signed_in and anonymous, connected RPC does not carry visitor
identity and there is no browser-direct capability in this release.
Changing or adding a profile changes the immutable deployment policy. Commit
the forgeBuild.ts update and publish a new Forge release before calling the
new profile.
Forge publishes one private, Forge-managed service binding into the connected Worker Version:
interface ForgeAiBinding {
responsesCreate(input: {
profile: string;
input: Array<{
role: 'system' | 'user' | 'assistant';
content: string;
}>;
billing?: { source: 'host' };
idempotencyKey: string;
}): Promise<ForgeAiResult>;
}
interface Env {
FORGE_AI?: ForgeAiBinding;
}
const result = await env.FORGE_AI.responsesCreate({
profile: 'gameCommentary',
input: [
{
role: 'system',
content: 'Use only the supplied approved public facts.',
},
{
role: 'user',
content: JSON.stringify({ facts: approvedPublicFacts }),
},
],
billing: { source: 'host' },
idempotencyKey: `commentary:${eventDigest}`,
});Do not declare FORGE_AI in wrangler.toml. Forge owns that binding and
rejects repository-authored or inherited conflicts. The binding targets the
private ConnectedForgeAi RPC entrypoint; there is no public inference URL.
Forge seals the capability to one account, project, release, provider-target generation, manifest digest, and profiles digest. Those values are revalidated against mutable account, entitlement, project, target, and production-pointer state on each call. Application code never supplies them.
Native Forge JS receives the same normalized service through the trusted runtime facade:
const result = await env.forge.ai.responses.create({
profile: 'gameCommentary',
input: [{ role: 'user', content: JSON.stringify(approvedPublicFacts) }],
billing: { source: 'host' },
idempotencyKey: `commentary:${eventDigest}`,
});interface ForgeAiResult {
id: string;
outputText: string;
outputJson?: unknown;
route: 'forge/text-fast@1';
usage: {
inputTokens: number;
outputTokens: number;
estimatedCostMicros: number;
billedTo: 'host';
cached: false;
};
receipt: {
policyDigest: string;
pricingVersion: string;
limitResetAt?: string;
};
}response.type: 'json_schema' requests JSON output and causes Forge to parse it
into outputJson. In this Alpha, Forge does not validate the generated object
against the supplied JSON Schema. Validate the shape, length, allowed fact IDs,
and product-specific invariants in application code before displaying it.
Use an application timeout and retain deterministic behavior:
const fallback = deterministicCommentary(approvedPublicFacts);
if (!env.FORGE_AI) return fallback;
try {
const result = await withTimeout(
env.FORGE_AI.responsesCreate(request),
5_000,
);
return validateCommentary(result.outputJson) ?? fallback;
} catch {
return fallback;
}Forge AI should normally explain or transform an authoritative application result. It should not become the source of truth for game moves, permissions, prices, scoring, or other deterministic product behavior.
[A-Za-z][A-Za-z0-9_-]{0,63}.system, user, or assistant and each message is bounded to
100,000 characters.idempotencyKey is required and contains 8–128 characters.maxInputTokens defaults to 2,500 and may be 1–32,000.maxOutputTokens defaults to 256 and may be 1–4,096.estimatedCostMicros is the current maximum-output reservation estimate, not a
reconciled provider invoice. cached is currently always false.
Derive the key from the immutable logical event and normalized input. Reusing a
key with different input returns idempotency_conflict and never starts a
second provider call. Reusing the same key and input prevents a second charge,
but this Alpha does not replay the previous output; callers currently receive a
provider-unavailable failure instead. Keep a successful result in application
state when needed and use the deterministic fallback after an ambiguous retry.
Forge normalizes failures to these codes:
ai_disabledprofile_not_foundidentity_requiredbyok_consent_requiredbudget_exhaustedrate_limitedinput_too_largeoutput_invalidprovider_unavailableidempotency_conflictNative runtime failures expose the code on the returned error. Connected RPC callers should catch defensively; the capability may be absent in local development, disabled by entitlement or project state, rate limited, or unable to complete provider work.
Browser code must call a narrow application-owned server route. The application
route remains responsible for request-body validation, authentication or
Turnstile, per-user abuse controls, response validation, and a bounded timeout.
audience: 'server' protects the Forge capability; it does not automatically
protect a public application endpoint from abuse.
/.forge/ai is reserved but provides no browser or cross-account capability in
this release. A future signed HTTPS transport is needed only for Workers in a
different Cloudflare account or applications outside Cloudflare.
OverGrid currently has two deployed profiles:
gameCommentary: short structured { line, factIds } output with 2,500
input tokens and 180 output tokens.trainingCoach: structured { answer, factIds } output with 4,000 input
tokens and 300 output tokens.Both are host-funded, server-only, limited to 10 requests per minute, use a five-second application timeout, validate model output against approved fact IDs, and fall back to deterministic explanations. Commentary receives only the public tactical receipt after the authoritative game engine commits a move. The training coach also uses an application session, Turnstile, and rate limiters.
For local tests, mock FORGE_AI.responsesCreate. Forge injects the real binding
only into published connected Worker Versions.
Tell an application coding agent to:
forgeBuild.ts and publish a
new Forge release before using a new profile.outputJson.FORGE_AI binding, raw model IDs,
browser-direct calls, streaming, tools, or arbitrary upstream URLs.