OffByOne is an agent-native website factory for turning prompts into validated, handoff-ready full-stack web projects.
It combines a Node.js CLI, MCP runtime, mock-safe automation, quality gates, and delivery packaging into one workflow — less “vibe-coded mystery box,” more reproducible product assembly line for AI-assisted builders.
OffByOne v4 is now a complete deliverable website factory, and v5 adds the first Business Digital Organism layer. It supports:
- staged prompt-template workflow with persisted
.agent/state/artifacts - mock LLM mode for offline regression testing
- OpenAI-compatible
/chat/completionsHTTP mode with provider presets - Vite React frontend, Express + SQLite backend, and Expo starter scaffold output
- deterministic API bindings for generated pages and live product/metric/lead surfaces
- prompt-relevant visual assets and design-profile guidance so generated sites avoid text-only/template-only output
- validation, build, API, preview, visual, and unified acceptance checks
- deployment handoff assets, offline deploy readiness scoring, and aggregate release gate reports
- client-ready delivery bundle export with checksums and optional
.tar.gzarchive - Product Genome / Organism Bundle artifacts and a Quality Contract that refreshes from local acceptance/readiness evidence
- Workbench Project Center visibility for organism status and Quality Contract publish decisions
- Node.js 18+
- No npm dependencies are required for the current version.
npm install
npm run checknpm install is optional today because the project has no third-party dependencies, but it is safe to run.
node src/cli.js init --output ./generated/my-project
node src/cli.js run --prompt "Build a premium SaaS dashboard with product cards, analytics metrics, and lead capture" --output ./generated/my-project --mock --force --max-pages 2 --scaffold
node src/cli.js project-doctor --output ./generated/my-project --install --backend-port 57840 --frontend-port 57841 --visual-backend-port 57842 --visual-frontend-port 57843 --save-baseline --project-name "My Site" --frontend-url https://frontend.example --backend-url https://backend.example
node src/cli.js delivery-bundle --output ./generated/my-project --project-name "My Site"
node src/cli.js status --output ./generated/my-project
node src/cli.js validate --output ./generated/my-project
node src/cli.js supervise --output ./generated/my-project
node src/cli.js runtime mock-task --output ./generated/runtime-demo --prompt "Build a one-page product site" --json
node src/cli.js runtime job/status --output ./generated/runtime-demo --job-id runtime-cli-mock-task --summary --json
node src/cli.js check
node src/cli.js providersYou can also use the package bin after linking/installing:
auto-fullstack-agent run --prompt "Build a BTC market dashboard" --output ./generated/btc-dashboard --mock --force --max-pages 1The runtime layer is the local/mock-safe seam for agent-facing OffByOne automation. It is designed for CLI, Workbench, and MCP clients that need artifact summaries, durable job records, and deterministic mock builds without enabling real model calls.
Runtime outputs are restricted to the local workspace generated/ and outputs/ roots by default. Job records are written under <output>/.agent/jobs/<jobId>/job.json; JSONL events are written to <output>/.agent/jobs/<jobId>/events.jsonl.
node src/cli.js runtime help
node src/cli.js runtime artifacts --output ./generated/runtime-demo --skip-validation --json
node src/cli.js runtime mock-task --output ./generated/runtime-demo --prompt "Build a one-page product site" --job-id runtime-demo --json
node src/cli.js runtime job/status --output ./generated/runtime-demo --job-id runtime-demo --summary --json
node src/cli.js runtime job/events --output ./generated/runtime-demo --job-id runtime-demo --limit 20 --json
node src/cli.js runtime job/cancel --output ./generated/runtime-demo --job-id runtime-demo --reason "Stop requested" --force-cancel --jsonThe stdio MCP server is a thin JSON-RPC adapter over the same safe handlers:
node src/mcp/server.jsCopyable agent-facing JSON-RPC examples are documented in docs/OFFBYONE_MCP_AGENT_EXAMPLE_CALLS.md.
The canonical MCP tool contract is generated from src/mcp/tools.js:listTools():
docs/OFFBYONE_MCP_TOOLS_SCHEMA.mddocs/OFFBYONE_MCP_TOOLS_SCHEMA.json
After changing MCP descriptors or handlers, run npm run mcp-tools-docs and keep npm run mcp-stability-smoke green before broader runtime checks.
Supported MCP methods are initialize, ping, tools/list, and tools/call. Current safe tools are:
offbyone_artifactsoffbyone_generate_mockoffbyone_validateoffbyone_statusoffbyone_job_statusoffbyone_job_events
offbyone_generate_real is intentionally absent. Runtime/MCP real-model execution remains blocked until a separate approval, provider preflight, quota/budget, and audit path is designed.
Recommended local verification:
npm run mcp-stability-smoke
npm run runtime-cli-smoke
npm run runtime-job-smoke
npm run mcp-tools-smoke
npm run mcp-server-smoke
npm run checkFor the active repo 100% local readiness gate, run:
npm run offbyone-readiness-smokeExternal-agent setup and JSON-RPC usage are documented in:
docs/OFFBYONE_EXTERNAL_AGENT_QUICKSTART.mddocs/OFFBYONE_MCP_CLIENT_REGISTRATION.mddocs/OFFBYONE_MCP_AGENT_EXAMPLE_CALLS.md
Prompt Oracle is a deterministic, offline pre-flight brief generator. It turns a raw user idea into .agent/oracle/oracle-brief.json, .agent/oracle/oracle-brief.md, and a OffByOne-ready enhanced prompt file.
OffByOne v4.4 modularizes the Prompt Oracle core under src/oracle/ so it can evolve as an independent pre-generation subsystem. src/agent/promptOracle.js remains only as a compatibility re-export for older first-party or external imports.
OffByOne v4.5 upgrades Prompt Oracle from a basic brief generator into a product reasoning chain. The generated brief now includes system understanding, reasoning, confidence, uncertainties, product logic, section purposes, generation strategy, and editable-field metadata while preserving the old intent, contentStrategy, visualDirection, and offbyonePrompt fields.
node src/cli.js oracle --prompt "我要做一个高端iPhone手机壳品牌官网" --output ./generated/oracle-site --force
node src/cli.js run --prompt-file ./generated/oracle-site/.agent/oracle/offbyone-prompt.txt --output ./generated/oracle-site --mock --force --max-pages 1 --scaffoldUse --prompt-file on run to feed the Oracle-enhanced prompt directly into the existing workflow. If both --prompt and --prompt-file are provided, the file content is used.
OffByOne v4.5 upgrades Prompt Oracle from a basic brief generator into a deterministic product-logic reasoning layer. The Oracle brief now preserves all old compatibility fields while also exposing understanding, productLogic, contentPlan.sections, generationStrategy, and editableFields.
It remains fully offline and deterministic: no model call is made during Oracle analysis, no new dependencies are introduced, and the main workflow/scaffold/parsers stay unchanged. The implementation stays inside the modular src/oracle/ boundary, with src/agent/promptOracle.js continuing as a compatibility re-export.
The UI now presents the v4.5 产品推理链 as five layers: system understanding, product logic, page structure, generation strategy, and the final OffByOne prompt.
OffByOne v4.6 adds an independent post-generation Product Design Supervisor. It reviews a generated website as a product artifact and writes deterministic/offline QA artifacts under .agent/supervisor/:
product-review.jsonproduct-review.mdrevision-plan.jsonrevision-prompt.txt
Run it after generation/scaffold:
node src/cli.js supervise --output ./generated/siteThe v4.6 supervisor checks product narrative, hero clarity, section order, conversion path, content completeness, and source-level design professionalism risk. It does not mutate generated source files; it only produces review and revision-planning artifacts for a future revision pass.
OffByOne v4.7 adds a guarded post-generation revision pass. It consumes the v4.6 supervisor artifacts and writes deterministic revision handoff files under .agent/revision/:
revision-brief.jsonrevision-brief.mdrevision-patch-plan.jsonrevision-instructions.txtmock-revision-notes.mdwhen--mockis used
Run it after supervise:
node src/cli.js revise --output ./generated/site --mock --forceDefault mode is artifact-only and does not mutate generated app source. --force only overwrites .agent/revision/ artifacts. If you explicitly want a visible low-risk source artifact, add --apply-notes:
node src/cli.js revise --output ./generated/site --mock --force --apply-notes--apply-notes only writes src/components/OffByOneRevisionNotes.jsx; it does not edit existing generated pages, layouts, scaffold files, or supervisor artifacts.
Recommended v4.7 loop:
oracle -> run --mock --scaffold -> supervise -> revise --mock -> validate -> supervise
For a browser-based local experience, start the lightweight v4 UI:
node src/cli.js uiThen open http://127.0.0.1:45845. The UI is intentionally a thin v4 experience shell, not the original v5 platform plan. It lets you enter a website prompt, review an optional Prompt Oracle product brief, set max pages/output slug, start a real job, poll progress, and open generated previews.
OffByOne v4.3 adds Prompt Oracle as a visible pre-generation UI step:
node src/cli.js ui
# Open http://127.0.0.1:45845
# Enter a raw idea, click “生成产品 Brief / 提示词先知分析”, review the brief, then start generation.Oracle runs locally and deterministically through POST /api/oracle. If you skip it, direct generation still uses the raw prompt. If you accept the brief without editing the raw prompt, the UI submits brief.offbyonePrompt to the existing job flow and preserves the original prompt plus compact Oracle metadata in the job input.
OffByOne v4.7.1 exposes the post-generation loop directly in the v4 Experience UI. Start the UI and open the local browser page:
node src/cli.js ui --host 127.0.0.1 --port 45845
# Open http://127.0.0.1:45845After at least one generated/ui-* project exists, use the new 产品监督与修订 / Product Supervisor & Revision panel:
- Select a recent
ui-*project, or click a recent-project quick action. - Click
运行产品设计监督to run the v4.6 Product Design Supervisor. - Review score, grade, status, dimension chips, top issues, and
.agent/supervisor/artifact paths. - Click
生成修订方案to run the v4.7 Revision Pass in mock/force mode. - Review action count, mutation policy, patch-plan action cards, and
.agent/revision/artifact paths.
The browser default is safe artifact-only revision. It does not mutate generated source files. The server API accepts applyNotes:true only when explicitly posted to /api/projects/:project/revise; the UI does not enable that by default.
Related local APIs:
POST /api/projects/:project/supervise
POST /api/projects/:project/revise
GET /api/projects/:project/supervision
GET /api/projects/:project/revision
The UI runs the existing v4 chain:
run --scaffold -> project-doctor -> delivery-bundle
Outputs are written under generated/ui-<slug>-<timestamp>/. API keys are never shown in the browser; Real mode still reads keys from the local environment/provider configuration.
OffByOne v5 starts turning generated websites into inspectable product organisms instead of one-off pages. The workflow now writes an organism/ bundle with Product Genome, experiment plan, revision brief, quality report, and Quality Contract artifacts.
v5.3 closes the local evidence loop: after project-doctor writes acceptance/deploy/readiness reports, organism/quality_contract.json is refreshed from those local artifacts. A passing local gate can promote the contract to publish-candidate; missing evidence stays revise-before-publish; explicit failures stay non-publish with blockers. Workbench Project Center cards show the compact Quality Contract decision, score, readiness/acceptance signals, and blocker/warning counts.
Key artifacts:
organism/genome.json
organism/quality_contract.json
organism/experiment_plan.json
organism/revision_brief.md
.agent/project-doctor/report.json
.agent/acceptance/report.json
.agent/deploy-check/report.json
Recommended v5.3 local gate:
node src/cli.js run --prompt "Build a B2B SaaS platform landing page for workflow automation with dashboards, CRM integrations, analytics, and request demo CTA." --output ./generated/ui-v53-quality-contract-smoke --mock --force --max-pages 1 --scaffold
node src/cli.js validate --output ./generated/ui-v53-quality-contract-smoke
node src/cli.js build-check --output ./generated/ui-v53-quality-contract-smoke --install
node src/cli.js project-doctor --output ./generated/ui-v53-quality-contract-smoke --install --backend-port 58640 --frontend-port 58641 --visual-backend-port 58642 --visual-frontend-port 58643 --save-baseline --project-name "OffByOne v5.3 Quality Contract Smoke" --frontend-url https://frontend.example --backend-url https://backend.exampleSee outputs/kurtty_v53_quality_contract_closeout_20260519.md for the v5.3 closeout and real-smoke checklist.
Use --mock to test the complete workflow without an API key:
node src/cli.js run --prompt "Build a BTC market dashboard" --output ./generated/btc-dashboard --mock --force --max-pages 1Mock mode returns deterministic plan, layout, and page-generation responses that exercise the parsers and file writer.
Use these options to keep real provider runs short and targeted:
--max-pages Nlimits the parsed plan before the page-generation loop. Example:--max-pages 1generates only the first planned page.--only-pages Home,Craftfilters parsed pages after--max-pages. It matches component names case-insensitively and also accepts file names likeHome.jsx.--stages listruns only selected comma-separated stages. Valid values arechat,analysis,db,plan,layout,pages,backend,app. Example:--stages chat,analysis,db,plan,layout,pagesskips backend/app stubs. If you includepages, includeplanandlayout; with--resume, priorstep-plan.md/step-layout.mdstate can satisfy those dependencies.--resumereusesOUTPUT/.agent/state/<stage>.md(includingstep-page-<PageName>.md) instead of calling the LLM when state exists, then parses the reused state and continues downstream. Logs include messages likeReusing step-plan from state.--skip-existingleaves existing generated files untouched. For pages, if the page state exists and all files parsed from that state already exist, the page LLM call is skipped.--forcestill overwrites generated files and takes precedence over skip behavior.--timeout-ms Nsets the per-request LLM fetch timeout. The default is180000(3 minutes).--retries Nsets LLM retry count for network errors, timeouts, 429s, and 5xx responses. The default is2orLLM_RETRIES.--retry-delay-ms Nsets delay between retry attempts. The default is1500orLLM_RETRY_DELAY_MS.--scaffoldwrites a Vite React project skeleton at the output root after plan/layout/page generation. It also createsbackend/andapp/starter projects.
Quick real-run shape:
node src/cli.js run --prompt "Build a BTC market dashboard" --output ./generated/btc-real-smoke --force --max-pages 1 --stages chat,analysis,db,plan,layout,pages --timeout-ms 180000 --retries 1Recommended production-like real-run workflow:
# 1) Build shared context and layout first.
node src/cli.js run --prompt "我要做一个高端iPhone手机壳品牌官网" --output ./generated/brand-real --force --stages chat,analysis,db,plan,layout --timeout-ms 180000 --retries 1
# 2) Inspect what state and pages are available.
node src/cli.js status --output ./generated/brand-real
# 3) Generate pages one by one, reusing previous state.
node src/cli.js run --prompt "我要做一个高端iPhone手机壳品牌官网" --output ./generated/brand-real --only-pages Home --resume --skip-existing --stages pages --timeout-ms 180000 --retries 1
node src/cli.js run --prompt "我要做一个高端iPhone手机壳品牌官网" --output ./generated/brand-real --only-pages Craft --resume --skip-existing --stages pages --timeout-ms 180000 --retries 1
# 4) Validate generated files and imports.
node src/cli.js validate --output ./generated/brand-realUse --scaffold when you want output that is closer to npm install && npm run dev/build:
# 1) Generate plan/layout/pages and write Vite + backend + Expo skeletons.
node src/cli.js run --prompt "Build a BTC market dashboard" --output ./generated/v2-mock --mock --force --max-pages 1 --scaffold
# 2) Validate generated files and scaffold requirements.
node src/cli.js validate --output ./generated/v2-mock
# 3) Install generated frontend dependencies and run Vite build.
node src/cli.js build-check --output ./generated/v2-mock --installThe scaffold adds package.json, index.html, Vite/Tailwind/PostCSS config, jsconfig.json, src/main.jsx, src/App.jsx, src/index.css, src/styles/theme.css, and a minimal shadcn-compatible src/components/ui/button.jsx with asChild support. src/App.jsx imports the generated Layout and page components, creates BrowserRouter routes, maps Home to /, maps other pages to lowercase paths, and includes a legacy /products alias for a generated Shop page when that path appears in layout output.
src/styles/theme.css is extracted from the plan block between ====== 全局样式theme.css开始 ====== and ====== 全局样式theme.css结束 ======. If no block exists, the agent writes safe default CSS variables.
The scaffold also creates:
backend/: Express API with/api/healthand/api/project-summary, runnable withcd backend && npm install && npm run dev.app/: simple Expo/React Native starter screens based on parsed pages. Expo is not built bybuild-check.
For real model full-page generation, continue to prefer the resume flow: generate shared context/layout once, then run pages one at a time with --resume --only-pages ... --skip-existing. Add --scaffold on the final run (or a resume run) to write/update the runnable skeleton.
OffByOne v3 upgrades the v2 runnable scaffold into a small real fullstack product scaffold. The DB stage output is extracted into SQLite-compatible SQL when possible; if the LLM SQL is unusable, the generator writes a safe default schema with products, leads, and metrics tables plus seed rows relevant to the prompt/pages.
Generated --scaffold output now includes:
backend/: Express + SQLite API. Startup initializesbackend/data/app.sqlitefrombackend/db/schema.sql.src/lib/api.js: Vite API client usingVITE_API_BASE_URLorhttp://localhost:3001/api.src/components/ApiStatus.jsx: unobtrusive backend status widget rendered bysrc/App.jsx.src/components/ProductSection.jsx,MetricsSection.jsx,LeadCaptureForm.jsx, andGeneratedApiShowcase.jsx: lightweight v3.4 API-driven React support components.src/lib/pageApiPlan.jsandsrc/components/PageApiPlanPanel.jsx: lightweight v3.5 per-page API planning artifacts.- root
.env.exampleandbackend/.env.example.
Common v3 commands:
node src/cli.js run --prompt "Build a premium iPhone case store" --output ./generated/v3-site --mock --force --max-pages 1 --scaffold
node src/cli.js validate --output ./generated/v3-site
node src/cli.js build-check --output ./generated/v3-site --install
node src/cli.js db-init --output ./generated/v3-site
node src/cli.js api-check --output ./generated/v3-site --install
node src/cli.js preview-check --output ./generated/v3-site --install --backend-port 3101 --frontend-port 5174
node src/cli.js acceptance-check --output ./generated/v3-site --install --backend-port 3101 --frontend-port 5174 --visual-backend-port 3201 --visual-frontend-port 5274
node src/cli.js preview --output ./generated/v3-site --installGenerated API endpoints:
GET /api/healthGET /api/project-summaryGET /api/productsGET /api/metricsGET /api/leadsPOST /api/leadswith JSON{ "name", "email", "message" }
Environment variables:
- Frontend:
VITE_API_BASE_URL=http://localhost:3001/api - Backend:
PORT=3001,CORS_ORIGIN=http://localhost:5173,DATABASE_FILE=./data/app.sqlite
Limitations: the scaffold is intentionally small, API-driven support components are appended outside LLM-generated page files rather than deeply merging into every page, and api-check --install requires network access to install generated backend dependencies.
OffByOne v3.4 keeps the default CLI workflow shape unchanged and makes --scaffold pages more useful by wiring real generated React components to the existing backend API. LLM-generated pages still render through the router as before; the API support area is appended by src/App.jsx below <Routes> so each generated page does not need manual imports.
OffByOne v3.6 passes each page's pageApiPlan into page generation so page source can bind directly to ../lib/api helpers such as getProjectSummary, getProducts, getMetrics, and createLead. A small scaffold fallback injector keeps mock --scaffold runs deterministic by safely adding planned helper imports and basic bindings when generated page code does not include them yet.
validate is also stricter for scaffold outputs: when .agent/state/page-api-plan.json expects helper bindings for a page, the generated src/pages/*.jsx file must reference those helpers, import from ../lib/api, and include a lead-submit path for leadCapture / createLead pages.
Generated frontend additions:
src/components/ProductSection.jsximportsgetProducts()and renders product cards fromGET /api/products.src/components/MetricsSection.jsximportsgetMetrics()and renders metric cards fromGET /api/metrics.src/components/LeadCaptureForm.jsximportscreateLead()and posts{ name, email, message }toPOST /api/leads, then shows success/error state.src/components/GeneratedApiShowcase.jsxcomposes the three sections in a conservative support area.src/App.jsximports and rendersGeneratedApiShowcasebelow the generated routes and keeps the v3 API status widget.
The components use React state/effects, the existing src/lib/api.js helpers, and simple Tailwind classes backed by the scaffold CSS variables. This gives every scaffolded output a live products/metrics/leads surface without requiring the LLM page generator to know about those files.
Recommended v3.4 smoke flow:
node src/cli.js run --prompt "Build a premium iPhone case store" --output ./generated/v3-4-site --mock --force --max-pages 1 --scaffold
node src/cli.js validate --output ./generated/v3-4-site
node src/cli.js build-check --output ./generated/v3-4-site --install
node src/cli.js api-check --output ./generated/v3-4-site --install
node src/cli.js preview-check --output ./generated/v3-4-site --install --backend-port 53108 --frontend-port 53109
node src/cli.js visual-check --output ./generated/v3-4-site --install --backend-port 53110 --frontend-port 53111v3.3 visual baseline/diff behavior is preserved. You can continue to use --save-baseline, --compare-baseline, --baseline-dir, --diff-output, and --diff-threshold with v3.4 scaffold outputs.
OffByOne v3.5 preserves the v3.4 scaffold and CLI workflow while adding a deterministic page-level API planning artifact. Existing prompts do not need to change: after step-plan is parsed, the agent derives one API plan entry per page from page names, page content, and the original prompt.
New v3.5 scaffold/state artifacts:
.agent/state/page-api-plan.json: JSON array of{ page, componentName, file, routeHint, endpoints, helpers, forms }.src/lib/pageApiPlan.js: exports the same plan aspageApiPlanfor frontend inspection.src/components/PageApiPlanPanel.jsx: compact planning panel that displays endpoint/helper/form badges for each page.src/App.jsx: still rendersGeneratedApiShowcase, and now also rendersPageApiPlanPanelnearby.
Endpoint inference is intentionally conservative: every page gets a summary read helper, contact/lead/signup/quote/inquiry pages get lead creation/form planning, product/shop/catalog pages get product reads, and metrics/dashboard/analytics pages get metric reads. Home pages may include summary plus product/metric reads when prompt/page context suggests them. This is a planning artifact only; generated page source files are not yet rewritten to consume the per-page plan directly.
Recommended v3.5 smoke flow:
node src/cli.js run --prompt "Build a premium SaaS dashboard with product cards, analytics metrics, and lead capture" --output ./generated/v3-5-site --mock --force --max-pages 2 --scaffold
node src/cli.js validate --output ./generated/v3-5-site
node src/cli.js build-check --output ./generated/v3-5-site --installOffByOne v4 turns a generated scaffold into a release-gated, client-handoff-ready website package. The v4 chain is:
run --scaffold
-> acceptance-check
-> delivery-package
-> deploy-check
-> project-doctor
-> delivery-bundle
Recommended v4 completion flow:
node src/cli.js run --prompt "Build a premium SaaS dashboard with product cards, analytics metrics, and lead capture" --output ./generated/v4-site --mock --force --max-pages 2 --scaffold
node src/cli.js project-doctor --output ./generated/v4-site --install --backend-port 57840 --frontend-port 57841 --visual-backend-port 57842 --visual-frontend-port 57843 --save-baseline --project-name "Premium SaaS Dashboard" --frontend-url https://frontend.example --backend-url https://backend.example
node src/cli.js delivery-bundle --output ./generated/v4-site --project-name "Premium SaaS Dashboard"v4 artifacts:
.agent/acceptance/report.jsonand.agent/acceptance/report.md: unified validate/build/API/preview/visual acceptance..agent/delivery/manifest.json,README_DEPLOY.md,.env.production.example, and deploy configs: deployment handoff package..agent/deploy-check/report.jsonand.agent/deploy-check/report.md: offline Netlify/Vercel/Render config validation plus readiness grade/score..agent/project-doctor/report.jsonand.agent/project-doctor/report.md: aggregate release gate. A complete handoff should pass acceptance, deploy-check, and readiness score >= 90..agent/delivery-bundle/bundle-manifest.json,CLIENT_HANDOFF.md,checksums.sha256, and.agent/delivery-bundle.tar.gz: client-ready source/artifact bundle.
The v4.4 reference validation passed both mock and real large-model smoke runs:
generated/v4-4-hermes-smoke doctor=pass/pass grade=A score=100 bundle=offbyone-v4.4 files=68 archive=true
generated/v4-4-real-smoke doctor=pass/pass grade=A score=100 bundle=offbyone-v4.4 files=70 archive=true
OffByOne v3.9 extends visual-check beyond the v3.7 source-level marker validation. During each desktop and mobile Playwright capture, visual acceptance now reads .agent/state/page-api-plan.json and verifies the live DOM contains visible API binding evidence:
- at least one visible
[data-offbyone-api-binding]marker when planned helpers exist; - visible per-helper markers for planned read helpers such as
getProjectSummary,getProducts, andgetMetrics; - a visible
createLeadhelper marker or visible form submit path forcreateLead/leadCaptureplans; - visible business labels for common helpers:
Live project data,Live products, andLive metrics.
When no page API plan exists, or the plan has no helpers, these assertions are recorded as a non-critical pass. When planned helpers exist, failures are critical and appear in the visual report checks. Each report.pages[] entry also includes a concise apiVisibility summary so v3.8 acceptance-check automatically surfaces runtime API visibility failures through its visual stage.
OffByOne v3.8 adds acceptance-check, a single report command that runs the existing validation, build, API, preview, and visual checks in sequence without changing those individual commands. It writes a unified JSON and Markdown report to OUTPUT/.agent/acceptance/report.json and OUTPUT/.agent/acceptance/report.md with overall PASS/FAIL, per-stage status summaries, generated timestamp, output path, and visual artifact paths when screenshots or baseline diffs are available.
Example:
node src/cli.js acceptance-check --output ./generated/v3-site --install --backend-port 3101 --frontend-port 5174 --visual-backend-port 3201 --visual-frontend-port 5274 --save-baseline --compare-baseline --diff-threshold 1If ports are omitted, deterministic defaults are used: preview 3001/5173 and visual 3101/5174 on 127.0.0.1.
OffByOne v3.1 adds a repeatable preview orchestrator for generated fullstack projects. It initializes SQLite, can install generated dependencies, starts the Express backend and Vite frontend with coordinated ports, waits for both URLs to respond, then prints the local URLs.
# Generate or reuse a v3 scaffold, then preview it locally.
node src/cli.js preview --output ./generated/v3-site --install
# Custom ports/host when defaults are busy or you want a stable smoke URL.
node src/cli.js preview --output ./generated/v3-site --backend-port 3101 --frontend-port 5174 --host 127.0.0.1
# Automated verification: starts both servers, waits for readiness, prints URLs, then shuts down.
node src/cli.js preview-check --output ./generated/v3-site --install --backend-port 3101 --frontend-port 5174
node src/cli.js acceptance-check --output ./generated/v3-site --install --backend-port 3101 --frontend-port 5174 --visual-backend-port 3201 --visual-frontend-port 5274Defaults are backend 127.0.0.1:3001, frontend 127.0.0.1:5173, and readiness timeout 20000 ms. The frontend receives VITE_API_BASE_URL=http://<host>:<backend-port>/api; the backend receives PORT=<backend-port> and CORS_ORIGIN=http://<host>:<frontend-port>. --no-open is accepted as a future-compatible no-op.
Without --mock, the CLI can now resolve first-class provider presets so you do not need to manually wire LLM_BASE_URL and LLM_MODEL for common OpenAI-compatible providers. This also helps avoid accidentally sending an OpenAI key to xAI or another provider.
Supported presets:
openai:OPENAI_API_KEY,https://api.openai.com/v1, default modelgpt-5.5xai:XAI_API_KEY,https://api.x.ai/v1, default modelgrok-3-miniopenrouter:OPENROUTER_API_KEY,https://openrouter.ai/api/v1, default modelopenai/gpt-4o-minideepseek:DEEPSEEK_API_KEY,https://api.deepseek.com/v1, default modeldeepseek-chatsiliconflow:SILICONFLOW_API_KEY,https://api.siliconflow.cn/v1, default modeldeepseek-ai/DeepSeek-V3
List them from the CLI:
node src/cli.js providersResolution order is:
- Constructor/programmatic options and CLI overrides like
--model,--base-url, and--api-key-env - Generic env overrides
LLM_API_KEY,LLM_BASE_URL, andLLM_MODEL - Selected provider key/defaults from
--providerorLLM_PROVIDER - OpenAI defaults when no provider is selected
Examples:
export XAI_API_KEY="your-xai-key"
node src/cli.js run --prompt "Build a BTC dashboard" --output ./generated/btc-xai --provider xai --force --max-pages 1
export OPENROUTER_API_KEY="your-openrouter-key"
node src/cli.js run --prompt "Build a SaaS landing page" --output ./generated/saas-router --provider openrouter --model openai/gpt-4o-mini --force --max-pages 1
export DEEPSEEK_API_KEY="your-deepseek-key"
node src/cli.js run --prompt "Build a docs portal" --output ./generated/docs-deepseek --provider deepseek --force --max-pages 1If a real smoke test fails, check region availability and key/provider matching first. For example, OpenAI access may be region-restricted for your environment, while xAI will fail if only OPENAI_API_KEY is set. Use the provider-specific env var or pass --api-key-env to read from a custom env name.
Without --mock, the CLI calls an OpenAI-compatible chat completions endpoint. Configure it with environment variables:
export LLM_API_KEY="your-key"
export LLM_BASE_URL="https://api.openai.com/v1" # optional, this is the default
export LLM_MODEL="gpt-5.5" # optional, this is the default
export LLM_RETRIES="2" # optional retry count
export LLM_RETRY_DELAY_MS="1500" # optional retry delay
node src/cli.js run --prompt "Build a SaaS landing page" --output ./generated/saas --force --max-pages 1 --timeout-ms 180000Any provider compatible with POST /chat/completions can still be used manually by changing LLM_BASE_URL and LLM_MODEL, or by selecting a preset with --provider or LLM_PROVIDER.
status never calls an LLM. It prints state files under .agent/state, parsed pages from pages.json, and written files from summary.json when present:
node src/cli.js status --output ./generated/my-projectvalidate also never calls an LLM. It exits 0 on pass and non-zero on failure. It checks that the output directory exists, pages.json and page-api-plan.json are valid when planning ran, completed summaries are readable, summary-listed files exist, JSX files are non-empty, layout ./components/Header imports have a matching src/layouts/components/Header.jsx, and page ../components/X imports have matching src/components/X.jsx files. When scaffold files are present it also checks the Vite root files, src/lib/pageApiPlan.js, src/components/PageApiPlanPanel.jsx, the src/App.jsx panel render, local UI button when imported, backend skeleton files, and Expo skeleton files:
node src/cli.js validate --output ./generated/my-projectbuild-check verifies package.json, optionally runs npm install, then runs npm run build in the generated output directory. It prints a short build summary and exits non-zero on failure:
db-init initializes the generated backend SQLite database from backend/db/schema.sql:
node src/cli.js db-init --output ./generated/my-projectapi-check optionally installs backend dependencies, initializes the database, starts the backend, verifies the required API routes, then stops the process:
node src/cli.js api-check --output ./generated/my-project --installpreview starts the generated backend and frontend together and keeps running until interrupted. preview-check uses the same flow but exits after readiness, which is suitable for CI or smoke tests:
node src/cli.js preview --output ./generated/my-project --install
node src/cli.js preview-check --output ./generated/my-project --install --backend-port 3101 --frontend-port 5174visual-check starts the same preview stack, opens the frontend in headless Chromium, captures desktop/mobile screenshots, performs lightweight DOM smoke checks, writes acceptance reports, and then stops automatically unless --keep-running is passed. v3.3 also supports optional baseline saving and pixel diff comparison:
node src/cli.js visual-check --output ./generated/my-project --install --backend-port 53110 --frontend-port 53111
node src/cli.js visual-check --output ./generated/my-project --install --visual-output ./generated/my-project/.agent/visual-review --keep-running
# Save the current screenshots as the visual baseline.
node src/cli.js visual-check --output ./generated/my-project --install --save-baseline
# Compare a later run against the saved baseline; fail if more than 1% of pixels changed.
node src/cli.js visual-check --output ./generated/my-project --install --compare-baseline --diff-threshold 1
# Optional custom baseline and diff directories.
node src/cli.js visual-check --output ./generated/my-project --compare-baseline --baseline-dir ./baselines/my-project --diff-output ./diffs/my-projectVisual artifacts are written to OUTPUT/.agent/visual/ by default. Baselines and diffs use separate directories so a compare run never compares screenshots to themselves. If --save-baseline and --compare-baseline are used together, offbyone compares against the existing baseline first, then saves the current screenshots as the new baseline.
OUTPUT/.agent/visual/
desktop.png
mobile.png
report.json
report.md
OUTPUT/.agent/visual-baseline/
desktop.png
mobile.png
OUTPUT/.agent/visual-diff/
desktop-diff.png
mobile-diff.png
If Playwright is not installed or Chromium binaries are missing, install them with:
npm install -D playwright
npx playwright install chromiumnode src/cli.js build-check --output ./generated/my-project --installA run writes files like:
generated/my-project/
.agent/acceptance/ # unified acceptance report
report.json
report.md
.agent/delivery/ # deployment handoff assets
manifest.json
README_DEPLOY.md
.env.production.example
deploy/
archive-list.txt
.agent/deploy-check/ # offline deploy readiness report
report.json
report.md
.agent/project-doctor/ # aggregate release gate report
report.json
report.md
.agent/delivery-bundle/ # client handoff bundle
bundle-manifest.json
CLIENT_HANDOFF.md
checksums.sha256
.agent/delivery-bundle.tar.gz
.agent/state/
step-chat.md
step-analysis.md
step-db.md
step-plan.md
pages.json
page-api-plan.json
step-layout.md
step-page-Home.md
step-page-About.md
step-backend.md
step-app.md
summary.json
package.json # when --scaffold is used
index.html # when --scaffold is used
vite.config.js # when --scaffold is used
src/
main.jsx # when --scaffold is used
App.jsx # when --scaffold is used
index.css # when --scaffold is used
styles/theme.css # when --scaffold is used
components/ApiStatus.jsx # when --scaffold is used
components/GeneratedApiShowcase.jsx # v3.4 API support area
components/PageApiPlanPanel.jsx # v3.5 page API planning panel
components/ProductSection.jsx # v3.4 getProducts() cards
components/MetricsSection.jsx # v3.4 getMetrics() cards
components/LeadCaptureForm.jsx # v3.4 createLead() form
lib/pageApiPlan.js # v3.5 exported page API plan
components/ui/button.jsx # when --scaffold is used
layouts/Layout.jsx
layouts/components/*.jsx
components/*.jsx
pages/*.jsx
backend/ # Express + SQLite starter when --scaffold is used
app/ # Expo starter when --scaffold is used
README.generated.md
Raw responses are overwritten in .agent/state/ during a normal run. With --resume, existing state files are reused instead of calling the LLM for those stages. Generated code files are not overwritten unless --force is passed; with --skip-existing, existing files are skipped and logged.
The six main templates are copied into prompts/:
step-chat.mdstep-analysis.mdstep-db.mdstep-plan.mdstep-layout.mdstep-page.md
The project also includes placeholder extension prompts:
step-backend.mdstep-app.md
Plan pages are parsed from blocks like:
====== 页面Home.jsx规划开始 ======
...
====== 页面Home.jsx规划结束 ======
Generated code is parsed from blocks like:
=== Layout:[Layout.jsx]开始生成 ===
...
=== Layout:[Layout.jsx]结束生成 ===
=== Component:[Name]开始生成 ===
...
=== Component:[Name]结束生成 ===
=== Page:Home开始生成 ===
...
=== Page:Home结束生成 ===
Parser functions are exported from src/agent/parsers.js and covered by npm run check fixtures.
const { runWorkflow, parsePlanPages, parseGenerationBlocks } = require('./src');
runWorkflow({
prompt: 'Build a BTC market dashboard',
output: './generated/btc-dashboard',
mock: true,
force: true
});From Kurt's current checkout:
cd /Users/kurticeberg/Projects/auto-fullstack-agent
node src/cli.js run --prompt "Build a BTC market dashboard" --output ./generated/btc-dashboard --mock --force --max-pages 1OffByOne v3.3 keeps the v3.2 visual-check acceptance smoke test behavior and adds optional visual baseline/diff support. It reuses the preview orchestration, starts SQLite/Express/Vite, opens the frontend in headless Chromium, captures desktop and mobile screenshots, runs lightweight DOM checks, writes reports, and shuts down unless --keep-running is passed.
node src/cli.js visual-check --output ./generated/v3-site --install --backend-port 53110 --frontend-port 53111
node src/cli.js visual-check --output ./generated/v3-site --backend-port 53110 --frontend-port 53111 --visual-output ./generated/v3-site/.agent/visual --keep-running
node src/cli.js visual-check --output ./generated/v3-site --install --save-baseline
node src/cli.js visual-check --output ./generated/v3-site --install --compare-baseline --diff-threshold 1Default report and image paths:
- JSON:
OUTPUT/.agent/visual/report.json - Markdown:
OUTPUT/.agent/visual/report.md - Current screenshots:
OUTPUT/.agent/visual/desktop.pngandOUTPUT/.agent/visual/mobile.png - Baseline screenshots:
OUTPUT/.agent/visual-baseline/desktop.pngandOUTPUT/.agent/visual-baseline/mobile.png - Diff images:
OUTPUT/.agent/visual-diff/desktop-diff.pngandOUTPUT/.agent/visual-diff/mobile-diff.png
Baseline options:
--save-baselinecopies the current desktop/mobile screenshots into the baseline directory after capture.--compare-baselinecompares current screenshots with the baseline screenshots and adds pass/fail diff results toreport.mdandreport.json.--baseline-dir DIRoverridesOUTPUT/.agent/visual-baseline.--diff-output DIRoverridesOUTPUT/.agent/visual-diff.--diff-threshold Nsets the allowed changed-pixel percentage; default is1.
If a baseline is missing, the report fails gracefully with the next step: run visual-check --save-baseline first. If --save-baseline and --compare-baseline are both passed, comparison runs against the existing baseline before the current screenshots are saved as the replacement baseline.
The acceptance report includes status, preview URLs, screenshot paths, check results, failures, and suggested next steps for non-engineer review. Critical checks include frontend HTTP 2xx/3xx load, no uncaught page errors, meaningful body text, at least one visible heading, at least one visible button/link/input, and non-empty screenshot files. The API health endpoint is also checked when available.
visual-check uses Playwright Chromium. If dependency or browser binaries are missing, install dependencies and then run:
npx playwright install chromiumRecommended v3.3 acceptance flow:
node src/cli.js validate --output ./generated/v3-site
node src/cli.js build-check --output ./generated/v3-site --install
node src/cli.js api-check --output ./generated/v3-site --install
node src/cli.js preview-check --output ./generated/v3-site --install --backend-port 53108 --frontend-port 53109
node src/cli.js visual-check --output ./generated/v3-site --install --backend-port 53110 --frontend-port 53111
node src/cli.js visual-check --output ./generated/v3-site --install --save-baseline --backend-port 53110 --frontend-port 53111
node src/cli.js visual-check --output ./generated/v3-site --install --compare-baseline --backend-port 53110 --frontend-port 53111 --diff-threshold 1OffByOne v3.6 turns the v3.5 per-page API plan into page source bindings. During page generation the workflow matches each parsed page to .agent/state/page-api-plan.json, injects page_api_plan_json and page_api_binding_instructions into prompts/step-page.md, and asks the page generator to import planned helpers from ../lib/api.
For regression safety, generated page blocks are also passed through a small deterministic binding layer. If a page plan has helpers, the written page keeps the generated component and adds a v3.6 binding section that imports the planned helpers, loads read helpers with useEffect/useState, and wires createLead/leadCapture plans to a real form submit path. validate now checks planned page files for the expected helper identifiers, ../lib/api imports, and lead submit handling.
OffByOne v3.7 keeps the CLI workflow unchanged while making bound API data easier to inspect. The deterministic page binding section renders getProjectSummary as project/product summary text, getProducts as product cards with price/category fields when present, and getMetrics as metric cards with label/value/unit/trend fields when present. Unknown helpers still use a compact JSON fallback, and lead forms keep their createLead submit path.
The binding section now exposes deterministic visibility markers: data-offbyone-api-binding="v3.7" plus per-helper data-offbyone-api-helper regions. Common helper regions include visible labels such as Live project data, Live products, and Live metrics; validate checks these markers and labels for planned helpers so preview tooling can assert that API data is actually visible.
Recommended smoke:
npm run check
node src/cli.js run --prompt "Build a premium SaaS dashboard with product cards, analytics metrics, and lead capture" --output ./generated/v36-hermes-smoke --mock --force --max-pages 2 --scaffold
node src/cli.js validate --output ./generated/v36-hermes-smoke
node src/cli.js build-check --output ./generated/v36-hermes-smoke --installRun a minimal local browser UI for the v4 generator workflow:
node src/cli.js ui
# open http://127.0.0.1:45845Options:
node src/cli.js ui --port 45845 --host 127.0.0.1The UI is intentionally dependency-free and serves static files from src/ui/public with Node's built-in http, fs, path, and url modules. It lets you enter a prompt, choose mock or real mode, set project name, max pages, output slug, and optional provider/model/base URL. API keys are never accepted by the UI; real runs use the existing environment-based LLM configuration.
Each submission creates a sequential job that runs:
runWorkflow({ scaffold: true, force: true, ... })intogenerated/ui-<slug>-<timestamp>runProjectDoctor(..., { saveBaseline: true })createDeliveryBundle(...)
The job view polls status and logs, then links to generated output, Project Doctor reports, and delivery-bundle handoff/manifest/archive artifacts. Report file reads are constrained to safe text files under this repo's generated/ directory.
OffByOne v4.7.2 adds a deterministic local Design System Router before generation. For each run, OffByOne classifies the prompt into a professional design profile (for example premium-consumer, ai-saas-devtool, enterprise-b2b-admin, fintech-crypto-data, local-service-commerce, content-editorial, or general-business) and selects one of five mock-safe Design DNA style packs distilled from awesome-design-md vocabulary:
precision-product-systemeditorial-craft-gallerytrust-data-infrastructurewarm-marketplace-servicereading-knowledge-system
The packs are local abstractions only: no external brand assets, logos, exact page structures, proprietary copy, remote images, or URLs are bundled or fetched. The design router writes:
.agent/design/design-profile.json.agent/design/design-profile.md.agent/design/style-pack.json.agent/design/style-pack.md.agent/state/design-profile.json
Generator prompts receive design_profile_json, design_profile_markdown, style_pack_json, style_pack_markdown, style_pack_id, design_reference_family, and design_site_type. Reference families such as Apple, Linear, Ant Design, Coinbase, Airbnb, or Notion are vocabulary labels only: use their mature spacing, hierarchy, density, and component rhythm as inspiration, not as cloning instructions. The visual asset plan reads the style pack for local SVG/placeholder directives, and the Product Design Supervisor reads the profile to validate expected signals, missing signals, style-pack QA signals, non-infringement boundaries, density expectations, and anti-patterns.