Skip to Content
TestingPrompt-to-App Agent

Prompt-to-App Agent

Give OpenFactory a one-sentence brief and a template repo, and you get back a deployed app at https://<slug>.apps.openfactory.tech. The brief is saved on the App record so later iteration instructions can be applied against the original ask without losing context.

Already have a Git repo to deploy? Skip the prompt path and use deploy_app directly. The prompt path is for “give me a draft from a brief” flows, not “deploy this exact repo”.

When to use this

  • You want a scaffolded app stood up from a short description, not a full repo.
  • You want to record iteration instructions (“make the header green”, “add CSV export”) against an app and have them tracked alongside the original brief.
  • You want a stable App record that an agent can take over later and keep refining.

Shipped today (M1: synchronous template fallback)

The shipped path is a synchronous template deploy. You supply both the brief and a template git URL; OpenFactory creates the App with the brief saved to App.origin, deploys the template via the existing deploy pipeline, and returns the URL.

What this means in practice:

  • Brief is preserved, not yet executed by an LLM. M1 does not generate source code from the brief. The template you pass is what gets deployed. Pick a scaffold close to what the brief asks for.
  • iterate_app records, it does not apply. Iteration instructions are appended to App.origin.iterations so the agent loop can read them later. To actually redeploy in M1, call deploy_app.
  • The data model and API surface are locked. When the agent loop lands, the swap is a localized change inside AppPromptService; the MCP tools, REST endpoints, and App.origin shape do not move.

LLM code generation, agent self-test loops (via walk_app), and automatic application of iteration instructions land in a follow-up milestone.

How it works

  1. Submit a brief with create_app_from_prompt(brief, template_git_url, vm_name, ...). OpenFactory creates an App, sets origin = {type: "prompt", brief, template_git_url, iterations: [], ...}, and deploys the template into your tester VM.
  2. Inspect with get_app_build_status(app_id) to read the brief, deploy history, current URL, env-version drift, and recorded iterations.
  3. Record iterations with iterate_app(app_id, instruction) as you refine the ask. Each instruction is timestamped on origin.iterations.

MCP tools

ToolUse
create_app_from_promptCreate an App from a brief, deploy a template, preserve the brief on App.origin
iterate_appRecord an iteration instruction against a prompt-built app
get_app_build_statusRead brief, deploy history, current URL, and iterations for a prompt-built app

create_app_from_prompt

Synchronous M1 path. Creates the App with origin.brief populated, runs the template through deploy_into_vm, and returns the deployed URL.

Example call:

create_app_from_prompt( brief="Invoice tracker for small shops with CSV export", template_git_url="https://github.com/example/nextjs-starter.git", vm_name="of-tester-001", name="Invoice Tracker", visibility="public" )

Example response:

{ "app_id": "app-abc123", "slug": "invoice-tracker", "status": "live", "url": "http://localhost:3000", "public_url": "https://invoice-tracker.apps.openfactory.tech", "origin": { "type": "prompt", "brief": "Invoice tracker for small shops with CSV export", "template_git_url": "https://github.com/example/nextjs-starter.git", "structure_id": null, "task_id": null, "iterations": [], "created_at": "2026-06-26T14:32:10.123456+00:00" }, "deploy_log": ["..."], "error": null, "next": "App deployed. iterate_app(app_id='app-abc123', instruction=…) to refine, walk_app(app_url='http://localhost:3000', mode='hybrid') to self-test." }

Validation errors come back as {"error": "..."} rather than throwing. The brief is required, template_git_url must be an http(s) or git@ URL, and vm_name is required.

iterate_app

Appends a timestamped instruction to App.origin.iterations. Only works on apps created via create_app_from_prompt (origin type must be prompt).

Example call:

iterate_app( app_id="app-abc123", instruction="Make the header green and add a CSV export button" )

Example response:

{ "app_id": "app-abc123", "iteration_count": 1, "iteration": { "ts": "2026-06-26T14:35:22.456789+00:00", "instruction": "Make the header green and add a CSV export button" }, "message": "Instruction recorded. M1 ships the iteration data model only; the agent loop that actually applies the instruction lands in M2." }

Common errors: "instruction is required", "App not found: <app_id>", and "App <app_id> was not created from a prompt …" when called against an App that was not created via the prompt path.

get_app_build_status

Cheap read of the App’s current state. No agent round-trip in M1.

Example call:

get_app_build_status(app_id="app-abc123")

Example response:

{ "app_id": "app-abc123", "slug": "invoice-tracker", "status": "live", "url": "http://localhost:3000", "public_url": "https://invoice-tracker.apps.openfactory.tech", "origin": { "type": "prompt", "brief": "Invoice tracker for small shops with CSV export", "template_git_url": "https://github.com/example/nextjs-starter.git", "iterations": [ { "ts": "2026-06-26T14:35:22.456789+00:00", "instruction": "Make the header green and add a CSV export button" } ], "created_at": "2026-06-26T14:32:10.123456+00:00" }, "deploy_count": 2, "last_deploy": { "deploy_id": "d-abc123de", "ref": "main", "mode": "inplace", "status": "live", "started_at": "2026-06-26T14:35:50.000000+00:00", "completed_at": "2026-06-26T14:35:55.000000+00:00", "duration_s": 5, "error": null }, "env_version": 0, "applied_env_version": 0 }

env_version vs applied_env_version is the drift signal from App Secrets & Environment: if they differ, the App has pending env changes that have not been redeployed.

REST endpoints

All three are owner-scoped via the standard Authorization: Bearer <jwt> or X-Guest-Id header. Wrong-owner and unknown app_id both return 404. Validation errors return 422.

MethodPathBody / use
POST/api/apps/from-prompt{brief, template_git_url, vm_name, name?, visibility?, branch?}
POST/api/apps/{app_id}/iterate{instruction}
GET/api/apps/{app_id}/agent-statusRead brief, deploy history, iterations
curl -X POST http://localhost:8000/api/apps/from-prompt \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{ "brief": "Guestbook app with entries and comments", "template_git_url": "https://github.com/example/nextjs-starter.git", "vm_name": "of-tester-001", "visibility": "public" }'
curl -X POST http://localhost:8000/api/apps/app-abc123/iterate \ -H "Authorization: Bearer $JWT" \ -H "Content-Type: application/json" \ -d '{"instruction": "Add a delete button for guestbook entries"}'
curl http://localhost:8000/api/apps/app-abc123/agent-status \ -H "Authorization: Bearer $JWT"

End-to-end (M1)

1. create_app_from_prompt(brief="Guestbook with entries and comments", template_git_url="https://github.com/example/nextjs-starter.git", vm_name="of-tester-001") → { app_id: "app-xyz", url: "http://localhost:3000", public_url: "https://guestbook.apps.openfactory.tech", origin: {...} } 2. get_app_build_status(app_id="app-xyz") → full origin (brief + iterations), deploy_count, last_deploy, env_version 3. iterate_app(app_id="app-xyz", instruction="Add a delete button for guestbook entries") → iteration recorded on origin.iterations 4. deploy_app(app_id="app-xyz") # M1: manual redeploy after editing the template → new entry in deploy_history; same public_url 5. walk_app(app_url="https://guestbook.apps.openfactory.tech", mode="hybrid") → findings (console_error, dead_control, ...) and auto-emitted scenarios

In the next milestone, step 4 is the agent’s job: the iteration is applied via a Direktor task-tune, the app is redeployed, and walk_app is invoked automatically as the agent’s self-test step.

Notes

  • The brief is capped at 2000 characters, the instruction at 1000. Keep iterations focused; long history lives in the iterations array, not in any single instruction.
  • origin.type is the discriminator. Apps created via create_app (no brief) have origin = None and cannot be iterated through this path; use deploy_app on those instead.
  • Public URL only appears when status == "live" and visibility == "public". Private apps still get a url, but it requires an OpenFactory login to reach.
  • VM must stay running. The deployed app serves from its tester VM. If the VM is stopped, the public URL stops resolving.
  • App Deployment — the deploy_app pipeline the prompt path delegates to, and the home of create_app for non-prompt apps.
  • App UI Testing — drive the deployed URL with reusable, self-hardening GUI scenarios. Also the surface the agent’s eventual self-test loop will call into via walk_app.
  • MCP Integration — set up the OpenFactory MCP server so these tools are reachable from your agent.
Last updated on