Skip to Content
TestingApp Templates and Remix

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_template or remix_app, the caller still chains add_app_database, add_app_bucket, or enable_app_auth before deploy. Auto-provisioning lands in M1.5.

How it works

  1. Browse - list_app_templates returns the gallery, optionally filtered by category (web, api, fullstack, static, job, data) or a free-text query.
  2. Inspect - get_app_template returns the full manifest: source git URL, declared env vars (with defaults and secret flags), declared services, and the rendered README.
  3. Instantiate - instantiate_app_template creates a new app owned by the caller, copies the env spec, applies any overrides you pass, and returns the new app_id plus the list of services you still need to provision.
  4. Or remix - remix_app forks an existing app you have access to (your own, or any app where visibility=public and remixable=true). The new app carries git_url and deployment_type from the source. Env values, secrets, db_refs, bucket_refs, auth binding, checkpoints, and IDE state are not copied.
  5. Publish for remix - set_app_remixable toggles the flag on your own app. Combined with visibility=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

MethodPathPurposeAuth
GET/api/apps/templatesBrowse gallery; optional category and q query paramsNone (public read)
GET/api/apps/templates/{template_id}Full template manifest including env spec, declared services, READMENone (public read)
POST/api/apps/templates/{template_id}/instantiateCreate 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}/remixFork 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-ownerRequired (remixer becomes owner of the new app)
PATCH/api/apps/{app_id}/remixableOwner toggles the remixable flag. Body: {remixable: bool}Required (owner only; 404 if not owner)

Putting it together

A typical instantiate-then-remix flow:

  1. Agent calls list_app_templates(q='fastapi') and gets two seed templates.
  2. User picks fastapi-postgres-crud and the agent calls instantiate_app_template(template_id='fastapi-postgres-crud', name='My API').
  3. Instantiate returns app_id=app-123 with declared_services=['postgres'].
  4. Caller chains add_app_database(app_id='app-123') to provision Postgres. DATABASE_URL is injected into the app’s env automatically.
  5. Caller chains deploy_app(app_id='app-123', vm_name='tester-1') to bring the app live.
  6. The app’s preview URL returns 200 from the FastAPI health endpoint.
  7. Owner calls set_app_remixable(app_id='app-123', remixable=true) and patches visibility=public.
  8. Another user calls remix_app(source_app_id='app-123') and gets a new app with the same git_url and deployment_type, but a fresh slug, env_version=0, and no db_refs or secrets copied.
  9. 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=public and remixable=true. Owners can always remix their own apps regardless of the flag.
  • What carries over on remix. git_url, source_branch (when set), and deployment_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 with set_app_env before deploy.
  • MCP vs. REST. The MCP tools include a next field with suggested chaining steps. The REST endpoints return the same data without next. Use the MCP field as a convenience hint, or rely on the documentation to chain calls yourself via REST.
  • 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.
Last updated on