App Templates and Remix
Spin up a new app from a curated template in one call, or fork a public app
(“remix”) to get your own copy. Either path gives you a fresh app_id, a fresh
slug, and a clean secret boundary. Nothing is shared with the source: no env
values, no database contents, no auth bindings, no IDE state.
Use this when you want to start from something that works instead of an empty repo, or when you want users to be able to copy your app without inheriting your secrets.
Today (M1): The data plane is complete. Manifests, instantiate, remix, and the remixable flag all ship with the hard security rules in place. Declared services (Postgres, object storage, auth) are recorded on the new app but are not provisioned automatically. After
instantiate_app_templateorremix_app, the caller still chainsadd_app_database,add_app_bucket, orenable_app_authbefore deploy. Auto-provisioning lands in M1.5.
How it works
- Browse -
list_app_templatesreturns the gallery, optionally filtered by category (web,api,fullstack,static,job,data) or a free-text query. - Inspect -
get_app_templatereturns the full manifest: source git URL, declared env vars (with defaults and secret flags), declared services, and the rendered README. - Instantiate -
instantiate_app_templatecreates a new app owned by the caller, copies the env spec, applies any overrides you pass, and returns the newapp_idplus the list of services you still need to provision. - Or remix -
remix_appforks an existing app you have access to (your own, or any app wherevisibility=publicandremixable=true). The new app carriesgit_urlanddeployment_typefrom the source. Env values, secrets,db_refs,bucket_refs, auth binding, checkpoints, and IDE state are not copied. - Publish for remix -
set_app_remixabletoggles the flag on your own app. Combined withvisibility=public, this lets other users fork it.
Why fresh secrets
Remix and instantiate both refuse to copy secret material across an ownership
boundary. The new app starts with env_version=0 and no service bindings, so
there is no path for a fork to read the source app’s database URL, API keys, or
signed auth tokens. The remixer must provision their own services and supply
their own secrets before the app comes up.
MCP tools
list_app_templates
Browse the templates gallery with optional category filter and free-text search.
list_app_templates(category='api', q='postgres')Response:
{
"templates": [
{
"id": "fastapi-postgres-crud",
"name": "FastAPI + Postgres CRUD",
"description": "FastAPI service with SQLAlchemy + Alembic migrations...",
"category": "api",
"tags": ["fastapi", "python", "postgres"],
"declared_services": ["postgres"]
}
],
"session_token": "user-123"
}get_app_template
Fetch the full manifest for one template including source git URL, env spec, declared services, and rendered README.
get_app_template(template_id='fastapi-postgres-crud')Response:
{
"id": "fastapi-postgres-crud",
"name": "FastAPI + Postgres CRUD",
"source_git_url": "https://github.com/openfactory/templates-fastapi-postgres-crud.git",
"source_branch": "main",
"deployment_type": "web-service",
"port": 8000,
"env": [
{
"name": "APP_LOG_LEVEL",
"description": "Python logging level.",
"secret": false,
"default": "INFO",
"required": true
}
],
"declared_services": ["postgres"],
"readme_md": "# FastAPI + Postgres CRUD...",
"session_token": "user-123"
}instantiate_app_template
Create a new app from a template. Returns the new app_id, the count of env
vars applied, and the declared services the caller still needs to provision.
The MCP tool adds a next field with chaining hints; the REST endpoint does not
include this field.
instantiate_app_template(
template_id='fastapi-postgres-crud',
name='My API',
env={'APP_LOG_LEVEL': 'DEBUG'}
)MCP response (includes next field with chaining hints):
{
"app_id": "app-abc123",
"template_id": "fastapi-postgres-crud",
"slug": "my-api",
"git_url": "https://github.com/openfactory/templates-fastapi-postgres-crud.git",
"deployment_type": "web-service",
"declared_services": ["postgres"],
"env_set_count": 1,
"notes": "Template declares services [postgres]. M1 ships the declarations only. Call add_app_database / add_app_bucket / enable_app_auth after this returns to provision them.",
"session_token": "user-abc123",
"next": "add_app_database(app_id='app-abc123') then deploy_app(app_id='app-abc123', vm_name=...)"
}REST endpoint response (same fields except no next):
{
"app_id": "app-abc123",
"template_id": "fastapi-postgres-crud",
"slug": "my-api",
"git_url": "https://github.com/openfactory/templates-fastapi-postgres-crud.git",
"deployment_type": "web-service",
"declared_services": ["postgres"],
"env_set_count": 1,
"notes": "Template declares services [postgres]. M1 ships the declarations only. Call add_app_database / add_app_bucket / enable_app_auth after this returns to provision them."
}remix_app
Fork a public+remixable app (or your own app) with fresh secrets and no env or
DB content copied. The MCP tool adds a next field with chaining hints; the
REST endpoint does not include this field.
remix_app(source_app_id='app-xyz789', name='My App Remix')MCP response (includes next field):
{
"app_id": "app-new456",
"source_app_id": "app-xyz789",
"slug": "my-app-remix",
"git_url": "https://github.com/user/original-app.git",
"notes": "Remix complete. git_url and deployment_type carried over. Env values, secrets, db_refs, bucket_refs, auth binding, checkpoints, and IDE state were NOT copied per spec.",
"session_token": "user-abc123",
"next": "deploy_app(app_id='app-new456', vm_name=...) to bring the remix live. If the source had managed services, provision fresh ones for the remix: add_app_database / add_app_bucket / enable_app_auth (the remix has none yet)."
}REST endpoint response (same fields except no next):
{
"app_id": "app-new456",
"source_app_id": "app-xyz789",
"slug": "my-app-remix",
"git_url": "https://github.com/user/original-app.git",
"notes": "Remix complete. git_url and deployment_type carried over. Env values, secrets, db_refs, bucket_refs, auth binding, checkpoints, and IDE state were NOT copied per spec."
}set_app_remixable
Toggle the remixable flag on your own app. Combined with visibility=public,
this lets non-owners call remix_app against it.
set_app_remixable(app_id='app-xyz789', remixable=true)Response:
{
"app_id": "app-xyz789",
"remixable": true,
"session_token": "user-123"
}REST endpoints
| Method | Path | Purpose | Auth |
|---|---|---|---|
GET | /api/apps/templates | Browse gallery; optional category and q query params | None (public read) |
GET | /api/apps/templates/{template_id} | Full template manifest including env spec, declared services, README | None (public read) |
POST | /api/apps/templates/{template_id}/instantiate | Create a new app from a template. Body: {name?, env?: {key: value}}. Returns 202 with app_id, slug, declared_services, env_set_count, notes (no next field) | Required (caller becomes owner) |
POST | /api/apps/{app_id}/remix | Fork an existing app. Body: {name?}. Returns 202 with app_id, source_app_id, slug, git_url, notes (no next field). Returns 403 if source is not public+remixable for a non-owner | Required (remixer becomes owner of the new app) |
PATCH | /api/apps/{app_id}/remixable | Owner toggles the remixable flag. Body: {remixable: bool} | Required (owner only; 404 if not owner) |
Putting it together
A typical instantiate-then-remix flow:
- Agent calls
list_app_templates(q='fastapi')and gets two seed templates. - User picks
fastapi-postgres-crudand the agent callsinstantiate_app_template(template_id='fastapi-postgres-crud', name='My API'). - Instantiate returns
app_id=app-123withdeclared_services=['postgres']. - Caller chains
add_app_database(app_id='app-123')to provision Postgres.DATABASE_URLis injected into the app’s env automatically. - Caller chains
deploy_app(app_id='app-123', vm_name='tester-1')to bring the app live. - The app’s preview URL returns 200 from the FastAPI health endpoint.
- Owner calls
set_app_remixable(app_id='app-123', remixable=true)and patchesvisibility=public. - Another user calls
remix_app(source_app_id='app-123')and gets a new app with the samegit_urlanddeployment_type, but a fresh slug,env_version=0, and nodb_refsor secrets copied. - The remixer provisions fresh services and deploys. Both apps run live, cleanly isolated.
Notes
- Remix permission. Non-owners can remix an app only when both
visibility=publicandremixable=true. Owners can always remix their own apps regardless of the flag. - What carries over on remix.
git_url,source_branch(when set), anddeployment_type. Everything else is fresh. - What does not carry over. Env values, secrets,
db_refs,bucket_refs, auth bindings, checkpoints, IDE state, deploy history. - Slugs. Both instantiate and remix generate a new DNS-safe slug derived from
name(or a default). The slug determines the preview URL:https://<slug>.apps.openfactory.tech. - Env overrides on instantiate. Pass
env={KEY: value}to override template defaults. Anything you do not override is set to the template’s declared default. Secret-flagged vars are left unset; supply them withset_app_envbefore deploy. - MCP vs. REST. The MCP tools include a
nextfield with suggested chaining steps. The REST endpoints return the same data withoutnext. Use the MCP field as a convenience hint, or rely on the documentation to chain calls yourself via REST.
Related
- App Deployment — deploy the resulting app and get a public preview URL.
- Prompt to App — generate a new app from a prompt instead of starting from a template.
- App Secrets and Env — set the env values that template defaults leave blank.
- Managed Databases — provision the Postgres
instance for a template that declares
postgres. - Object Storage — provision a bucket for a template
that declares
storage. - App Auth Service — wire up the auth binding for a
template that declares
auth.