diff --git a/.charter/telemetry/events.ndjson b/.charter/telemetry/events.ndjson new file mode 100644 index 0000000..692bc37 --- /dev/null +++ b/.charter/telemetry/events.ndjson @@ -0,0 +1,9 @@ +{"version":1,"timestamp":"2026-03-04T11:38:44.194Z","commandPath":"quickstart","flags":["--version"],"format":"text","ciMode":false,"durationMs":1,"exitCode":0,"success":true} +{"version":1,"timestamp":"2026-03-04T11:38:48.692Z","commandPath":"setup","flags":["--detect-only","--format"],"format":"json","ciMode":false,"durationMs":8,"exitCode":0,"success":true} +{"version":1,"timestamp":"2026-03-04T11:38:52.119Z","commandPath":"setup","flags":["--preset","--yes"],"format":"text","ciMode":false,"durationMs":22,"exitCode":0,"success":true} +{"version":1,"timestamp":"2026-03-04T11:38:56.228Z","commandPath":"doctor","flags":[],"format":"text","ciMode":false,"durationMs":35,"exitCode":0,"success":true} +{"version":1,"timestamp":"2026-03-04T11:39:00.252Z","commandPath":"adf.init","flags":[],"format":"text","ciMode":false,"durationMs":14,"exitCode":0,"success":true} +{"version":1,"timestamp":"2026-03-04T11:39:04.156Z","commandPath":"doctor","flags":[],"format":"text","ciMode":false,"durationMs":49,"exitCode":0,"success":true} +{"version":1,"timestamp":"2026-03-04T11:39:08.702Z","commandPath":"adf.migrate","flags":["--dry-run"],"format":"text","ciMode":false,"durationMs":22,"exitCode":0,"success":true} +{"version":1,"timestamp":"2026-03-04T11:39:50.202Z","commandPath":"adf.migrate","flags":[],"format":"text","ciMode":false,"durationMs":45,"exitCode":0,"success":true} +{"version":1,"timestamp":"2026-03-04T11:39:54.319Z","commandPath":"doctor","flags":[],"format":"text","ciMode":false,"durationMs":54,"exitCode":0,"success":true} diff --git a/ADF_1.png b/ADF_1.png new file mode 100644 index 0000000..83bc7cf Binary files /dev/null and b/ADF_1.png differ diff --git a/src/content/docs/getting-started.md b/src/content/docs/getting-started.md index 6f5ea94..fa377e6 100644 --- a/src/content/docs/getting-started.md +++ b/src/content/docs/getting-started.md @@ -1,108 +1,345 @@ ---- -title: "Getting Started" -description: "Install Charter CLI, configure governance presets, and enforce compliance in your first project in under five minutes." -section: "charter" -order: 1 -color: "#2ea043" -tag: "01" ---- - -# Getting Started - -Charter is a local-first governance toolkit with a built-in AI context compiler. It validates commit governance, detects stack drift, scores risk, and ships **ADF (Attention-Directed Format)** — a modular, AST-backed context system that replaces monolithic `.cursorrules` and `claude.md` files. Everything runs locally and in CI, with no SaaS dependency. - -## Install - -Recommended: local dev dependency per repo. - -```bash -npm install --save-dev @stackbilt/cli -``` - -pnpm workspace root: - -```bash -pnpm add -Dw @stackbilt/cli -``` - -Global (optional, puts `charter` on your PATH): - -```bash -npm install -g @stackbilt/cli -``` - -## Bootstrap a Repo - -```bash -# Preview what charter detects — no files written -npx charter setup --detect-only --format json - -# Write governance baseline + optional CI workflow -npx charter setup --ci github --yes - -# Mixed repos (frontend + backend): choose preset explicitly -npx charter setup --detect-only -npx charter setup --preset fullstack --ci github --yes -``` - -`setup` writes: -- `.charter/config.json` — governance baseline config -- `.charter/patterns/*.json` — blessed-stack pattern definitions -- `.charter/policies/*.md` — human-readable policy summary -- `.github/workflows/charter-governance.yml` — CI workflow (if `--ci github`) - -## Set Up ADF Context - -ADF turns your LLM context into a compiled, modular system. Scaffold the `.ai/` directory: - -```bash -# Scaffold .ai/ with manifest, core, and state modules -npx charter adf init - -# Verify everything parses and syncs -npx charter doctor --format json -``` - -This creates (for default presets): - -```text -.ai/ - manifest.adf # Module registry: default-load vs on-demand with triggers - core.adf # Always-loaded: role, constraints, metric ceilings - state.adf # Session state: current task, decisions, blockers - frontend.adf # Frontend module scaffold (on-demand, triggers: React, CSS, UI) - backend.adf # Backend module scaffold (on-demand, triggers: API, Node, DB) -``` - -For documentation-heavy repos, use `--preset docs` to get `decisions.adf` and `planning.adf` instead of frontend/backend modules. - -Edit `.ai/core.adf` to define your project constraints and LOC ceilings. The `METRICS [load-bearing]` section enforces hard limits that CI can gate on. - -## Verify the Setup - -```bash -npx charter doctor --format json -npx charter -``` - -`charter` with no arguments prints a live governance snapshot: risk score, governed commit ratio, drift status. - -`doctor` validates environment health including ADF readiness: manifest existence, module parse status, and sync lock integrity. - -## Run an Evidence Check - -If you have ADF set up with metric ceilings, run the evidence pipeline: - -```bash -# Validate all metric ceilings and produce a structured report -npx charter adf evidence --auto-measure - -# CI mode: exits 1 if any ceiling is breached -npx charter adf evidence --auto-measure --ci --format json -``` - -## What's Next - -- [CLI Reference](/cli-reference) — full command surface -- [CI Integration](/ci-integration) — GitHub Actions workflow with evidence gating -- [Ecosystem](/ecosystem) — how Charter fits into the StackBilt platform +--- +title: "Getting Started" +description: "Install Charter CLI, configure governance presets, and enforce compliance in your first project in under five minutes." +section: "charter" +order: 1 +color: "#2ea043" +tag: "01" +--- + +# Charter Kit + +## The Problem + +You write a CLAUDE.md. You add a `.cursorrules`. You paste instructions into GEMINI.md. Your AI agent loads all of it into the context window -- 10,000 tokens of flat, unstructured rules competing with the actual work. + +Half get ignored. You don't know which half. + +## The Solution + +Charter is an open-source CLI that replaces monolithic agent config files with **ADF (Attention-Directed Format)** -- a modular context system where agents load only the rules they need for the current task. + +Instead of one big file, you get a manifest. The manifest declares modules, trigger keywords that load them on demand, token budgets, and weighted sections that tell the agent what's load-bearing vs. advisory. + +```bash +npm install --save-dev @stackbilt/cli +npx charter bootstrap --yes # detect stack, scaffold .ai/, migrate existing rules +``` + +## Five-Minute Adoption + +Already have agent config files? Charter migrates them: + +```bash +# See what would happen (dry run) +charter adf migrate --dry-run + +# Migrate: classifies rules by strength, routes to ADF modules, replaces originals with thin pointers +charter adf migrate +``` + +Your `CLAUDE.md` / `.cursorrules` / `GEMINI.md` content gets classified (imperative vs. advisory vs. neutral), routed to the right module (frontend rules to `frontend.adf`, backend rules to `backend.adf`), and your originals become one-line pointers to `.ai/`. No content lost, no rewrite needed. + +## How ADF Works + +Charter manages context through the `.ai/` directory: + +```text +.ai/ + manifest.adf # Module registry: default-load vs on-demand with trigger keywords + core.adf # Always-loaded: role, constraints, output format, metric ceilings + state.adf # Session state: current task, decisions, blockers + frontend.adf # On-demand: loaded when task mentions "react", "css", etc. + backend.adf # On-demand: loaded when task mentions "endpoint", "REST", etc. +``` + +When you run `charter adf bundle --task "Fix the React login component"`, Charter: +1. Reads the manifest +2. Loads `core.adf` and `state.adf` (always loaded) +3. Sees "React" matches a trigger keyword -- loads `frontend.adf` +4. Skips `backend.adf` (no matching triggers) +5. Merges the loaded modules into a single context payload with token budget tracking + +The agent gets exactly the rules it needs. Nothing more. + +### Format Example + +```text +ADF: 0.1 + +TASK: + Build the user dashboard + +CONTEXT: + - React 18 with TypeScript + - TailwindCSS for styling + - REST API at /api/v2 + +CONSTRAINTS [load-bearing]: + - No external state libraries + - Must support SSR + +METRICS [load-bearing]: + entry_loc: 142 / 500 [lines] + handler_loc: 88 / 300 [lines] + +STATE: + CURRENT: Implementing layout grid + NEXT: Add data fetching + BLOCKED: Waiting on API schema +``` + +Sections use emoji decorations for attention signaling, support four content types (text, list, key-value map, and metric with value/ceiling/unit), and follow a canonical ordering the formatter enforces. `[load-bearing]` vs `[advisory]` weight annotations distinguish measurable constraints from preferences. Metric entries (`key: value / ceiling [unit]`) define hard ceilings that the `evidence` command validates automatically. + +## Self-Governance: Charter Enforces Its Own Rules + +This isn't theoretical. Charter uses ADF to govern its own codebase. The `.ai/` directory in this repository contains the same modules and metric ceilings that any adopting repo would use. + +Every commit runs through a pre-commit hook that executes `charter adf evidence --auto-measure`. If a source file exceeds its declared LOC ceiling, the commit is rejected. We can't ship code that violates our own governance rules -- even by accident, even at 2am. + +Here is the actual output from Charter's own evidence check (v0.7.0): + +```text + ADF Evidence Report + =================== + Modules loaded: core.adf, state.adf + Token estimate: ~494 + Token budget: 4000 (12%) + + Auto-measured: + adf_commands_loc: 618 lines (packages/cli/src/commands/adf.ts) + adf_bundle_loc: 175 lines (packages/cli/src/commands/adf-bundle.ts) + adf_sync_loc: 213 lines (packages/cli/src/commands/adf-sync.ts) + adf_evidence_loc: 272 lines (packages/cli/src/commands/adf-evidence.ts) + adf_migrate_loc: 474 lines (packages/cli/src/commands/adf-migrate.ts) + bundler_loc: 125 lines (packages/adf/src/bundler.ts) + parser_loc: 214 lines (packages/adf/src/parser.ts) + cli_entry_loc: 191 lines (packages/cli/src/index.ts) + + Constraints: + [ok] adf_commands_loc: 618 / 650 [lines] -- PASS + [ok] adf_bundle_loc: 175 / 200 [lines] -- PASS + [ok] adf_sync_loc: 213 / 250 [lines] -- PASS + [ok] adf_evidence_loc: 272 / 380 [lines] -- PASS + [ok] adf_migrate_loc: 474 / 500 [lines] -- PASS + [ok] bundler_loc: 125 / 500 [lines] -- PASS + [ok] parser_loc: 214 / 300 [lines] -- PASS + [ok] cli_entry_loc: 191 / 200 [lines] -- PASS + + Verdict: PASS +``` + +What this shows: + +- **Metric ceilings enforce LOC limits on source files.** Each metric in a `.adf` module declares a ceiling. `--auto-measure` counts lines live from the sources referenced in the manifest. +- **Self-correcting architecture.** When `bundler_loc` hit 413/500, Charter's own evidence gate flagged the pressure. The file was split into three focused modules (`manifest.ts`, `merger.ts`, `bundler.ts`) -- now 125/500. The system caught the problem and the system verified the fix. +- **CI gating.** Generated governance workflows run `doctor --adf-only --ci` and `adf evidence --auto-measure --ci` on every PR, blocking merges on ceiling breaches. +- **Available to any repo.** This is the same system you get by running `charter adf init` in your own project. + +## Quick Reference + +```bash +# Scaffold .ai/ with starter modules +charter adf init + +# Reformat to canonical form +charter adf fmt .ai/core.adf --write + +# Apply a typed patch +charter adf patch .ai/state.adf --ops '[{"op":"ADD_BULLET","section":"STATE","value":"Reviewing PR #42"}]' + +# Bundle context for a task (trigger-based module loading) +charter adf bundle --task "Fix the React login component" + +# Migrate existing agent configs into ADF +charter adf migrate --dry-run + +# Verify .adf files haven't drifted from locked hashes +charter adf sync --check + +# Validate metric constraints +charter adf evidence --auto-measure + +# Recalibrate metric ceilings +charter adf metrics recalibrate --headroom 15 --reason "Scope expansion" --dry-run + +# Expose ADF context as an MCP server (for Claude Code / any MCP client) +charter serve +``` + +## Why Charter + +- **Modular AI context** -- trigger-routed `.ai/` modules replace monolithic config files +- **Five-minute migration** -- classify and route existing CLAUDE.md / .cursorrules / GEMINI.md rules automatically +- **MCP server** -- `charter serve` exposes your ADF context as an MCP server; Claude Code can query constraints, architectural decisions, and recent changes without reading raw files +- **Evidence-based governance** -- metric ceilings with auto-measurement, structured pass/fail reports, CI gating +- **Self-regulating** -- pre-commit hooks enforce constraints before code lands +- **Commit governance** -- validate `Governed-By` and `Resolves-Request` trailers, score commit risk +- **Drift detection** -- scan for stack drift against blessed patterns +- **Stable JSON output** -- every command supports `--format json` with `nextActions` hints for agent workflows + +## Install + +```bash +npm install --save-dev @stackbilt/cli +``` + +For pnpm workspaces: `pnpm add -Dw @stackbilt/cli`. For global install: `npm install -g @stackbilt/cli`. + +## Getting Started + +### Human Workflow + +```bash +charter # Repo risk/value snapshot +charter bootstrap --ci github # One-command onboarding +charter doctor # Validate environment/config +charter validate # Check commit governance +charter drift # Scan for stack drift +charter audit # Governance summary +charter adf init # Scaffold .ai/ context directory +``` + +### Claude Code Integration (MCP) + +`charter serve` exposes your `.ai/` modules as an MCP server. Add it to `.claude/settings.json`: + +```json +{ + "mcpServers": { + "charter": { + "command": "charter", + "args": ["serve"] + } + } +} +``` + +Claude Code can then call `getProjectContext`, `getArchitecturalDecisions`, `getProjectState`, and `getRecentChanges` directly — no manual `adf bundle` needed in the conversation. + +### Agent Workflow + +Prefer JSON mode and exit-code handling: + +```bash +charter --format json +charter setup --ci github --yes --format json +charter doctor --format json +charter validate --format json --ci +charter drift --format json --ci +charter audit --format json +charter adf bundle --task "describe the task" --format json +charter adf evidence --auto-measure --format json --ci +charter adf sync --check --format json +``` + +Agent contract: +- Inputs: git repo + optional existing `.charter/` +- Stable machine output: `--format json` with `nextActions` hints where applicable +- Exit codes: `0` success, `1` policy violation, `2` runtime/usage error +- CI behavior: with `--ci`, treat `1` as gating failure and surface actionable remediation +- Evidence: `adf evidence --ci` exits 1 on metric ceiling breaches; warnings (at boundary) don't fail + +
+Trailer Adoption Ramp + +Teams often score lower early due to missing governance trailers. Use this ramp: +- Stage 1: run `charter validate --ci --format json` in PR CI and fail on policy violations. +- Stage 2: add a commit template in the repo that includes `Governed-By` and `Resolves-Request`. +- Stage 3: track audit trend; trailer coverage should rise naturally as PR gating normalizes behavior. + +
+ +## Cross-Platform Support + +Charter works across WSL, PowerShell, CMD, macOS, and Linux. All git operations use a unified invocation layer with cross-platform PATH resolution. Line endings are normalized via `.gitattributes`. + +## Command Reference + +- `charter`: show repo risk/value snapshot and recommended next action +- `charter bootstrap [--ci github] [--preset ] [--yes] [--skip-install] [--skip-doctor]`: one-command onboarding (detect + setup + ADF + migrate + install + doctor) +- `charter setup [--ci github] [--preset ] [--detect-only] [--no-dependency-sync]`: detect stack and scaffold `.charter/` baseline +- `charter init [--preset ]`: scaffold `.charter/` templates only +- `charter doctor [--adf-only]`: validate environment/config state (`--adf-only` runs strict ADF wiring checks) +- `charter validate [--ci] [--range ]`: validate commit governance and citations +- `charter drift [--path ] [--ci]`: run drift scan +- `charter audit [--ci] [--range ]`: produce governance audit summary +- `charter classify `: classify change scope heuristically +- `charter hook install --commit-msg [--force]`: install commit-msg trailer normalization hook +- `charter hook install --pre-commit [--force]`: install pre-commit ADF routing + evidence gate +- `charter adf init [--ai-dir ] [--force]`: scaffold `.ai/` context directory +- `charter adf fmt [--check] [--write]`: parse and reformat ADF files to canonical form +- `charter adf fmt --explain`: show canonical formatter section ordering +- `charter adf patch --ops | --ops-file `: apply typed delta operations +- `charter adf create [--triggers "a,b,c"] [--load default|on-demand]`: create and register a module +- `charter adf bundle --task "" [--ai-dir ]`: resolve manifest and output merged context +- `charter adf sync --check [--ai-dir ]`: verify .adf files match locked hashes +- `charter adf sync --write [--ai-dir ]`: update `.adf.lock` with current hashes +- `charter adf evidence [--task ""] [--ai-dir ] [--auto-measure] [--context '{"k":v}'] [--context-file ]`: validate metric constraints and produce evidence report +- `charter adf metrics recalibrate [--headroom ] [--reason ""|--auto-rationale] [--dry-run]`: recalibrate metric baselines/ceilings +- `charter adf migrate [--dry-run] [--source ] [--no-backup] [--merge-strategy append|dedupe|replace]`: migrate existing agent config files into ADF modules +- `charter serve [--name ] [--ai-dir ]`: start an MCP server (stdio) exposing ADF context as tools and resources for Claude Code and other MCP clients +- `charter telemetry report [--period <30m|24h|7d>]`: summarize local CLI telemetry +- `charter why`: explain adoption rationale and expected payoff + +Global options: `--config `, `--format text|json`, `--ci`, `--yes`. + +## Exit Code Contract + +- `0`: success/pass +- `1`: policy violation in CI mode +- `2`: runtime/config/usage error + +## CI Integration + +- Reusable template: `.github/workflows/governance.yml` +- Generated in target repos by `charter setup --ci github`: `.github/workflows/charter-governance.yml` +- The governance workflow runs `validate`, `drift`, ADF wiring integrity (`doctor --adf-only --ci`), ADF ceiling evidence (`adf evidence --auto-measure --ci`), and `audit` on every PR. + +## Workspace Layout + +```text +packages/ + types/ Shared contracts + core/ Schemas, sanitization, errors + adf/ ADF parser, formatter, patcher, bundler, evidence pipeline + git/ Trailer parsing and risk scoring + classify/ Heuristic classification + validate/ Governance validation + drift/ Pattern drift scanning + cli/ `charter` command + ci/ GitHub Actions integration helpers +``` + +## Development + +- `pnpm run clean` +- `pnpm run typecheck` +- `pnpm run build` +- `pnpm run test` + +## SemVer and Stability Policy + +Charter uses [Semantic Versioning](https://semver.org/) for this repository and for published `@stackbilt/*` packages. + +Until `1.0.0`, Charter may still evolve quickly, but breaking changes should remain exceptional, deliberate, and clearly documented. The goal of `1.0.0` is simple: a connected coding agent or developer can rely on Charter's machine-facing contracts without source archaeology. + +The following surfaces are semver-governed: + +- **Package APIs** -- exported functions, classes, and types from published `@stackbilt/*` packages +- **CLI behavior** -- command names, flags, exit codes, and machine-readable `--format json` output +- **ADF behavior** -- parse, format, patch, bundle, sync, and evidence semantics +- **Generated artifacts** -- thin pointer files, `.ai/manifest.adf`, `.adf.lock`, and related scaffolded outputs +- **Governance schemas** -- evidence, audit, drift, doctor, and scorecard JSON envelopes + +Versioning rules: + +- **PATCH** -- bug fixes, docs, internal refactors, and non-breaking UX improvements +- **MINOR** -- additive commands, flags, fields, modules, templates, and advisory checks that do not break existing consumers +- **MAJOR** -- incompatible changes to CLI contracts, JSON schemas, ADF semantics, generated artifact conventions, or other machine-facing behavior that agents may rely on + +For agent-facing workflows, schema stability is treated as a core product promise, not a nice-to-have. + +## License + +Apache-2.0. diff --git a/src/content/docs/img-forge.md b/src/content/docs/img-forge.md index 54539db..b2e26c9 100644 --- a/src/content/docs/img-forge.md +++ b/src/content/docs/img-forge.md @@ -1,312 +1,312 @@ ---- -title: "img-forge API" -description: "AI image generation API with REST endpoints, MCP tools, and multi-tier quality options. OAuth 2.1 and API key authentication." -section: "platform" -order: 9 -color: "#f472b6" -tag: "09" ---- - -# img-forge API - -img-forge is StackBilt's AI image generation service. Submit a text prompt, get back a generated image. Supports multiple quality tiers (Stable Diffusion XL through Gemini), async job queuing, and content-addressed image storage on R2. - -**Gateway:** `https://imgforge.stackbilt.dev` -**MCP Server:** `https://img-forge-mcp.blue-pine-edf6.workers.dev/mcp` - -## Authentication - -img-forge supports three auth paths, checked in order by the gateway middleware. - -### API Key - -Include your key in the `Authorization` header or `X-API-Key` header: - -```bash -curl -X POST https://imgforge.stackbilt.dev/v2/generate \ - -H "Authorization: Bearer imgf_your_key_here" \ - -H "Content-Type: application/json" \ - -d '{"prompt": "A mountain landscape at sunset"}' -``` - -API keys use the `imgf_` prefix followed by 64 hex characters. You receive the raw key once at creation — store it securely. - -### OAuth 2.1 (MCP Clients) - -The MCP server acts as both Authorization Server and Resource Server using `@cloudflare/workers-oauth-provider`. MCP clients follow the standard OAuth 2.1 + PKCE flow: - -1. Discover endpoints via `/.well-known/oauth-authorization-server` -2. Register dynamically at `/register` (RFC 7591) -3. Redirect to `/authorize` with PKCE challenge -4. User logs in via Better Auth and grants consent -5. Exchange auth code for access token at `/token` - -**Token lifetimes:** Access token 1 hour, refresh token 30 days. -**Scopes:** `generate`, `read` - -First-time users are auto-provisioned with a free-tier tenant and 100 images/month entitlement on consent approval. - -### Anonymous - -No credentials required. Rate-limited to 100 images/month per IP address. - -## REST API - -### Generate an Image - -``` -POST /v2/generate -``` - -Submit a generation request. Returns immediately with a job ID (async) or waits for completion (sync). - -**Request body:** - -| Field | Type | Required | Default | Description | -|-------|------|----------|---------|-------------| -| `prompt` | string | Yes | — | Text description, 1–2000 characters | -| `negative_prompt` | string | No | — | Things to exclude (effective on `draft` tier only) | -| `quality_tier` | string | No | `standard` | `draft`, `standard`, `premium`, `ultra`, `ultra_plus` | -| `sync` | boolean | No | `false` | Wait for completion before responding | -| `idempotency_key` | string | No | — | Deduplication key (24h TTL) | - -**Example (async):** - -```bash -curl -X POST https://imgforge.stackbilt.dev/v2/generate \ - -H "Authorization: Bearer imgf_your_key" \ - -H "Content-Type: application/json" \ - -d '{ - "prompt": "Isometric pixel art of a cloud server room", - "quality_tier": "premium" - }' -``` - -**Response (`202 Accepted`):** - -```json -{ - "job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", - "state": "queued", - "original_prompt": "Isometric pixel art of a cloud server room", - "final_prompt": "...", - "enhancement_logic": "...", - "asset_url": null, - "error": null, - "created_at": "2026-03-04T12:00:00.000Z", - "completed_at": null -} -``` - -When `sync: true`, the response is `201 Created` with `state: "completed"` and `asset_url` populated. - -### Poll Job Status - -``` -GET /v2/jobs/:id -``` - -Check the state of a generation job. Jobs are scoped to the authenticated tenant. - -**Response:** - -```json -{ - "job_id": "a1b2c3d4-...", - "state": "completed", - "original_prompt": "...", - "final_prompt": "...", - "enhancement_logic": "...", - "asset_url": "/v2/assets/sha256hash", - "error": null, - "created_at": "2026-03-04T12:00:00.000Z", - "completed_at": "2026-03-04T12:00:08.000Z" -} -``` - -**Job states:** `queued` → `processing` → `completed` | `failed` - -Jobs that remain in `processing` for more than 60 seconds are automatically marked `failed` with a timeout error. - -### Retrieve an Image - -``` -GET /v2/assets/:id -``` - -Stream the generated image from R2. Images are content-addressed by SHA-256 hash. - -Returns `image/png` with `Cache-Control: public, max-age=3600`. Returns `404` if the asset does not exist. - -### Health Check - -``` -GET /v2/health -``` - -Returns `{ "status": "ok", "version": "0.2.0" }`. - -## Quality Tiers - -| Tier | Provider | Model | Negative Prompt | Default Size | -|------|----------|-------|-----------------|--------------| -| `draft` | Cloudflare AI | Stable Diffusion XL Lightning | Yes | 1024×1024 | -| `standard` | Cloudflare AI | FLUX.2 Klein 4B | No | 1024×768 | -| `premium` | Cloudflare AI | FLUX.2 Dev | No | 1024×768 | -| `ultra` | Gemini | Gemini 2.5 Flash Image | No | 1024×1024 | -| `ultra_plus` | Gemini | Gemini 3.1 Flash Image Preview | No | 1024×1024 | - -## MCP Tools - -Connect MCP-compatible agents to img-forge for programmatic image generation. - -**Endpoint:** `https://img-forge-mcp.blue-pine-edf6.workers.dev/mcp` - -### Claude Code Configuration - -Add to your MCP settings: - -```json -{ - "mcpServers": { - "img-forge": { - "url": "https://img-forge-mcp.blue-pine-edf6.workers.dev/mcp" - } - } -} -``` - -### generate_image - -Generate an image from a text prompt. Requires `generate` scope. - -| Parameter | Type | Required | Default | Description | -|-----------|------|----------|---------|-------------| -| `prompt` | string | Yes | — | Text description, 1–2000 characters | -| `quality_tier` | enum | No | `standard` | `draft`, `standard`, `premium`, `ultra`, `ultra_plus` | -| `negative_prompt` | string | No | — | Exclusions (effective on `draft` tier only) | - -The MCP tool always uses sync mode — it returns the completed image URL directly. - -### list_models - -List all available quality tiers with their providers, models, and default sizes. Requires `read` scope. Takes no parameters. - -### check_job - -Check the status of a generation job. Requires `read` scope. - -| Parameter | Type | Required | Description | -|-----------|------|----------|-------------| -| `job_id` | string (UUID) | Yes | The job ID to check | - -## Rate Limits - -| Auth Method | Quota | Period | Enforcement | -|-------------|-------|--------|-------------| -| Anonymous | 100 images | Calendar month | Per IP, via KV | -| API key (free tier) | 100 images | Calendar month | Per tenant, via D1 entitlements | -| OAuth / MCP (free tier) | 100 images | Calendar month | Per tenant, via D1 entitlements | - -When quota is exceeded, the API returns `429` with error code `QUOTA_EXCEEDED` (authenticated) or `RATE_LIMITED` (anonymous). - -## Tenant Management - -Authenticated users can manage their API keys through tenant endpoints. - -### Create Tenant - -``` -POST /v2/tenants -``` - -Requires a Better Auth session. Returns the raw API key **once** — it cannot be retrieved again. - -```json -{ - "tenant_id": "uuid", - "api_key": "imgf_...", - "api_key_prefix": "imgf_abcd1234", - "scopes": ["generate", "read"], - "tier": "free" -} -``` - -### List Tenants - -``` -GET /v2/tenants -``` - -Returns all tenants for the authenticated user. Does not include raw API keys, only prefixes. - -### Rotate API Key - -``` -POST /v2/tenants/:id/rotate -``` - -Invalidates the current key and returns a new one. - -### Check Usage - -``` -GET /v2/tenants/:id/usage -``` - -Returns active entitlements and total job count: - -```json -{ - "tenant_id": "...", - "tier": "free", - "total_jobs": 12, - "entitlements": [ - { - "type": "standard", - "quota_limit": 100, - "quota_used": 12, - "remaining": 88, - "period_start": "2026-03-01T00:00:00Z", - "period_end": "2026-03-31T23:59:59Z", - "source": "img-forge-free" - } - ] -} -``` - -## TypeScript Example - -```typescript -const GATEWAY = "https://imgforge.stackbilt.dev"; -const API_KEY = "imgf_your_key_here"; - -// Generate (async) -const genRes = await fetch(`${GATEWAY}/v2/generate`, { - method: "POST", - headers: { - "Authorization": `Bearer ${API_KEY}`, - "Content-Type": "application/json", - }, - body: JSON.stringify({ - prompt: "A neon-lit cyberpunk alleyway", - quality_tier: "premium", - }), -}); -const job = await genRes.json(); -console.log("Job ID:", job.job_id); - -// Poll until complete -let result = job; -while (result.state !== "completed" && result.state !== "failed") { - await new Promise((r) => setTimeout(r, 2000)); - const pollRes = await fetch(`${GATEWAY}/v2/jobs/${job.job_id}`, { - headers: { "Authorization": `Bearer ${API_KEY}` }, - }); - result = await pollRes.json(); -} - -if (result.state === "completed") { - console.log("Image:", `${GATEWAY}${result.asset_url}`); -} -``` +--- +title: "img-forge API" +description: "AI image generation API with REST endpoints, MCP tools, and multi-tier quality options. OAuth 2.1 and API key authentication." +section: "platform" +order: 9 +color: "#f472b6" +tag: "09" +--- + +# img-forge API + +img-forge is StackBilt's AI image generation service. Submit a text prompt, get back a generated image. Supports multiple quality tiers (Stable Diffusion XL through Gemini), async job queuing, and content-addressed image storage on R2. + +**Gateway:** `https://imgforge.stackbilt.dev` +**MCP Server:** `https://img-forge-mcp.blue-pine-edf6.workers.dev/mcp` + +## Authentication + +img-forge supports three auth paths, checked in order by the gateway middleware. + +### API Key + +Include your key in the `Authorization` header or `X-API-Key` header: + +```bash +curl -X POST https://imgforge.stackbilt.dev/v2/generate \ + -H "Authorization: Bearer imgf_your_key_here" \ + -H "Content-Type: application/json" \ + -d '{"prompt": "A mountain landscape at sunset"}' +``` + +API keys use the `imgf_` prefix followed by 64 hex characters. You receive the raw key once at creation — store it securely. + +### OAuth 2.1 (MCP Clients) + +The MCP server acts as both Authorization Server and Resource Server using `@cloudflare/workers-oauth-provider`. MCP clients follow the standard OAuth 2.1 + PKCE flow: + +1. Discover endpoints via `/.well-known/oauth-authorization-server` +2. Register dynamically at `/register` (RFC 7591) +3. Redirect to `/authorize` with PKCE challenge +4. User logs in via Better Auth and grants consent +5. Exchange auth code for access token at `/token` + +**Token lifetimes:** Access token 1 hour, refresh token 30 days. +**Scopes:** `generate`, `read` + +First-time users are auto-provisioned with a free-tier tenant and 100 images/month entitlement on consent approval. + +### Anonymous + +No credentials required. Rate-limited to 100 images/month per IP address. + +## REST API + +### Generate an Image + +``` +POST /v2/generate +``` + +Submit a generation request. Returns immediately with a job ID (async) or waits for completion (sync). + +**Request body:** + +| Field | Type | Required | Default | Description | +|-------|------|----------|---------|-------------| +| `prompt` | string | Yes | — | Text description, 1–2000 characters | +| `negative_prompt` | string | No | — | Things to exclude (effective on `draft` tier only) | +| `quality_tier` | string | No | `standard` | `draft`, `standard`, `premium`, `ultra`, `ultra_plus` | +| `sync` | boolean | No | `false` | Wait for completion before responding | +| `idempotency_key` | string | No | — | Deduplication key (24h TTL) | + +**Example (async):** + +```bash +curl -X POST https://imgforge.stackbilt.dev/v2/generate \ + -H "Authorization: Bearer imgf_your_key" \ + -H "Content-Type: application/json" \ + -d '{ + "prompt": "Isometric pixel art of a cloud server room", + "quality_tier": "premium" + }' +``` + +**Response (`202 Accepted`):** + +```json +{ + "job_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", + "state": "queued", + "original_prompt": "Isometric pixel art of a cloud server room", + "final_prompt": "...", + "enhancement_logic": "...", + "asset_url": null, + "error": null, + "created_at": "2026-03-04T12:00:00.000Z", + "completed_at": null +} +``` + +When `sync: true`, the response is `201 Created` with `state: "completed"` and `asset_url` populated. + +### Poll Job Status + +``` +GET /v2/jobs/:id +``` + +Check the state of a generation job. Jobs are scoped to the authenticated tenant. + +**Response:** + +```json +{ + "job_id": "a1b2c3d4-...", + "state": "completed", + "original_prompt": "...", + "final_prompt": "...", + "enhancement_logic": "...", + "asset_url": "/v2/assets/sha256hash", + "error": null, + "created_at": "2026-03-04T12:00:00.000Z", + "completed_at": "2026-03-04T12:00:08.000Z" +} +``` + +**Job states:** `queued` → `processing` → `completed` | `failed` + +Jobs that remain in `processing` for more than 60 seconds are automatically marked `failed` with a timeout error. + +### Retrieve an Image + +``` +GET /v2/assets/:id +``` + +Stream the generated image from R2. Images are content-addressed by SHA-256 hash. + +Returns `image/png` with `Cache-Control: public, max-age=3600`. Returns `404` if the asset does not exist. + +### Health Check + +``` +GET /v2/health +``` + +Returns `{ "status": "ok", "version": "0.2.0" }`. + +## Quality Tiers + +| Tier | Provider | Model | Negative Prompt | Default Size | +|------|----------|-------|-----------------|--------------| +| `draft` | Cloudflare AI | Stable Diffusion XL Lightning | Yes | 1024×1024 | +| `standard` | Cloudflare AI | FLUX.2 Klein 4B | No | 1024×768 | +| `premium` | Cloudflare AI | FLUX.2 Dev | No | 1024×768 | +| `ultra` | Gemini | Gemini 2.5 Flash Image | No | 1024×1024 | +| `ultra_plus` | Gemini | Gemini 3.1 Flash Image Preview | No | 1024×1024 | + +## MCP Tools + +Connect MCP-compatible agents to img-forge for programmatic image generation. + +**Endpoint:** `https://img-forge-mcp.blue-pine-edf6.workers.dev/mcp` + +### Claude Code Configuration + +Add to your MCP settings: + +```json +{ + "mcpServers": { + "img-forge": { + "url": "https://img-forge-mcp.blue-pine-edf6.workers.dev/mcp" + } + } +} +``` + +### generate_image + +Generate an image from a text prompt. Requires `generate` scope. + +| Parameter | Type | Required | Default | Description | +|-----------|------|----------|---------|-------------| +| `prompt` | string | Yes | — | Text description, 1–2000 characters | +| `quality_tier` | enum | No | `standard` | `draft`, `standard`, `premium`, `ultra`, `ultra_plus` | +| `negative_prompt` | string | No | — | Exclusions (effective on `draft` tier only) | + +The MCP tool always uses sync mode — it returns the completed image URL directly. + +### list_models + +List all available quality tiers with their providers, models, and default sizes. Requires `read` scope. Takes no parameters. + +### check_job + +Check the status of a generation job. Requires `read` scope. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `job_id` | string (UUID) | Yes | The job ID to check | + +## Rate Limits + +| Auth Method | Quota | Period | Enforcement | +|-------------|-------|--------|-------------| +| Anonymous | 100 images | Calendar month | Per IP, via KV | +| API key (free tier) | 100 images | Calendar month | Per tenant, via D1 entitlements | +| OAuth / MCP (free tier) | 100 images | Calendar month | Per tenant, via D1 entitlements | + +When quota is exceeded, the API returns `429` with error code `QUOTA_EXCEEDED` (authenticated) or `RATE_LIMITED` (anonymous). + +## Tenant Management + +Authenticated users can manage their API keys through tenant endpoints. + +### Create Tenant + +``` +POST /v2/tenants +``` + +Requires a Better Auth session. Returns the raw API key **once** — it cannot be retrieved again. + +```json +{ + "tenant_id": "uuid", + "api_key": "imgf_...", + "api_key_prefix": "imgf_abcd1234", + "scopes": ["generate", "read"], + "tier": "free" +} +``` + +### List Tenants + +``` +GET /v2/tenants +``` + +Returns all tenants for the authenticated user. Does not include raw API keys, only prefixes. + +### Rotate API Key + +``` +POST /v2/tenants/:id/rotate +``` + +Invalidates the current key and returns a new one. + +### Check Usage + +``` +GET /v2/tenants/:id/usage +``` + +Returns active entitlements and total job count: + +```json +{ + "tenant_id": "...", + "tier": "free", + "total_jobs": 12, + "entitlements": [ + { + "type": "standard", + "quota_limit": 100, + "quota_used": 12, + "remaining": 88, + "period_start": "2026-03-01T00:00:00Z", + "period_end": "2026-03-31T23:59:59Z", + "source": "img-forge-free" + } + ] +} +``` + +## TypeScript Example + +```typescript +const GATEWAY = "https://imgforge.stackbilt.dev"; +const API_KEY = "imgf_your_key_here"; + +// Generate (async) +const genRes = await fetch(`${GATEWAY}/v2/generate`, { + method: "POST", + headers: { + "Authorization": `Bearer ${API_KEY}`, + "Content-Type": "application/json", + }, + body: JSON.stringify({ + prompt: "A neon-lit cyberpunk alleyway", + quality_tier: "premium", + }), +}); +const job = await genRes.json(); +console.log("Job ID:", job.job_id); + +// Poll until complete +let result = job; +while (result.state !== "completed" && result.state !== "failed") { + await new Promise((r) => setTimeout(r, 2000)); + const pollRes = await fetch(`${GATEWAY}/v2/jobs/${job.job_id}`, { + headers: { "Authorization": `Bearer ${API_KEY}` }, + }); + result = await pollRes.json(); +} + +if (result.state === "completed") { + console.log("Image:", `${GATEWAY}${result.asset_url}`); +} +```