<!-- Markdown rendering of index.html for AI agents.
     The HTML page is the same content with diagrams and styling;
     this view exists so an agent spends its context on the instructions. -->
# Put a _running prototype_ in front of people

Some deliverables are software, not documents. PitchStation Apps takes a project with a `docker-compose.yml` (or a Vite + React or Next.js app), builds it on a host the platform manages, and gives it a live HTTPS address under its host's base domain, such as `demo-crm.apps-ap.pitchstation.ai`, or your own domain. Public or password-gated, with an expiry if you want one, release history, rollback and proof that the address really serves your app. New here? Start with the [user manual](manual.html).

## §01 What you get

**A live address with TLS**

Every app gets an address under its host's base domain: `SLUG.apps-ap.pitchstation.ai` on Singapore's hosts, `SLUG.apps.pitchstation.ai` on Oregon's, and the host's own label in between (`SLUG.hN.…`) on an isolated host without per-app DNS. Each name gets its own Let's Encrypt certificate, renewed automatically. Custom domains and aliases are added with a DNS ownership proof.

**Releases and rollback**

Each upload is a numbered release, and data on named volumes survives every release. A rollback runs an earlier release's Compose file again; it brings back that release's code when each release tags its images differently. A failed health check leaves the new release serving, so the fix is usually a redeploy. [Details](manual.html#rollback).

**Access you control**

Public, or gated by a password you choose, with an optional expiry that is enforced on every request — even if PitchStation itself is unreachable.

**Secrets stored encrypted**

Environment variables are stored encrypted and written to the release at deploy time. The API only ever returns key names.

**Operations you can resume**

Deploys, rollbacks and address changes run as durable operations with an ID. Closing your laptop does not cancel them; retrying with the same key never deploys twice.

**Readiness evidence**

A readiness check proves each address answers over TLS with the right access policy, serves this app's identity marker and its critical assets — not just "HTTP 200 from something".

## §02 How a deploy works

[Diagram: A content deploy: the client packages your directory, the API accepts it as a durable operation, the worker builds and health-checks it on the app host, then the managed route serves it with TLS and the access policy.]

Content and configuration are separate on purpose. A **deploy** changes the code that runs. A **domains** or **policy** change edits the address or who may reach it, without touching the running containers. An **env** change updates secrets and restarts the current release. Each is its own operation, planned first and applied explicitly.

## §03 Five ways in

All five speak the same REST API, so anything one can do the API can do. Pick by where you are working. Stopping and deleting an app are REST calls only; the client and the web page have neither. The [user manual](manual.html#ways) has the full task-by-channel table.

| Channel | Best for | Create app | Deploy | Domains · access | Env · rollback | Stop · delete | Status · readiness |
| --- | --- | --- | --- | --- | --- | --- | --- |
| **Web** · [/apps.html](/apps.html) | Owners changing addresses and access by hand | — | — | yes | — | — | yes |
| **AI skill** · create-pitchstation-app | Asking Claude Code, Codex or another agent to make a project deployable and ship it | yes | yes | yes | yes | by REST | yes |
| **MCP** · 6 `pitchstation_app_*` tools | Assistants without a shell (Claude Desktop, Cline, Cursor) | — | yes | a password, on deploy | operation retry/cancel | — | yes |
| **Apps client** · `pitchstation-apps.cjs` | Terminals and CI: one dependency-free Node file | yes | yes | yes | yes | — | yes |
| **REST API** · `/api/apps` | Your own tooling; the complete surface | yes | yes | yes | yes | yes | yes |

**Why MCP stops at deploy and status.** Domain, access and environment changes are reviewed plans guarded by a configuration version (an ETag): the change you approve is exactly the change applied. That review is a conversation with the user, not a single tool call, so those steps stay in the client, the skill (which walks the review) and the web page.

## §04 Before you start

**The app.deploy capability**

Running your own prototypes and running someone else's code are different trust levels, so hosting is never on by default. An administrator grants `app.deploy` to your account. Without it every call answers 403 `CAPABILITY_REQUIRED`.

**A personal access token**

Create one with the **Apps** preset at [/tokens.html](/tokens.html) (it starts with `pst_`). Tools read it from `PITCHSTATION_APPS_TOKEN` (the MCP server from `PITCHSTATION_MCP_TOKEN`), or the shared `PITCHSTATION_TOKEN`; never paste it into a command line or a chat.

**A host your account may use**

Either a host registered to your account, or a **shared host** the platform offers to teammates. `GET /api/apps/targets` (client `targets`, or `pitchstation_app_list`) lists both with free slots, budget headroom, architecture and region, plus your quota on shared hosts (3 apps unless an admin changes it). Leave the host out when you create an app and the platform places it for you and says why.

**Choose public or private up front**

Say at creation whether the app is `private` (with a password you keep) or `public`. A public app also declares that it restricts nobody itself (application policy `none`) — at creation or later — or readiness will not certify it. [Why](deploy.html#declare).

## §05 Status in this release

| Area | State | Notes |
| --- | --- | --- |
| App hosts | live | Singapore (`*.apps-ap.pitchstation.ai`, ARM64) is the **shared host** for teammates: Compose rules and per-app budgets are enforced there. Oregon (`*.apps.pitchstation.ai`, x86) is the platform account's own host. It was resized on 30 September and stays out of the pool until four of its apps stop publishing ports on every interface; there the rules and budgets warn. On Singapore every image and binary must be available for ARM64. A host an admin has not approved answers `HOST_NOT_APPROVED` to an apply; dry runs work everywhere. |
| Shared hosts, placement and quota | live | Teammates with `app.deploy` can create apps on shared hosts without a host of their own; 3 apps each by default. Admins approve hosts (host check, onboarding, live and pool flags) on the admin page, with no restart. |
| Status, logs, failed-step output | live | Containers, health, restarts, out-of-memory kills and usage against the budget; redacted logs; a failed step shows the redacted tail of its output. |
| Resolving an uncertain deploy | live | When only your containers were involved (a migration, `up`, health), you inspect and confirm it yourself; routing and host-level cases go to an admin. |
| Managed route (per-host TLS + access policy) | live | New apps use it from their first deploy (first production app on 27 September 2026, after a fix to how the policy is linked on the host). |
| Apps deployed before 18 September | legacy route | Six earlier apps keep serving on their original routes. They were inventoried; their first domains or policy change moves them onto the managed route after checking the existing route has not changed. |
| Custom domains | first use pending | Implemented with per-host `_pitchstation.HOSTNAME` TXT proofs; not yet exercised on a production custom domain. |
| AI skill · Apps client · MCP tools | live | The client is a single download (with `targets`, `status`, `logs`, `resources`, `reconcile`, `releases` and private-first `--password-file`); it prints each error's fields and details. MCP has six app tools, and its deploy takes a readiness `marker`. See the [user manual](manual.html) and the [deploy guide](deploy.html). |
| Sign-in page and access links | live | A private app shows people a sign-in page (a 12-hour session; API clients keep HTTP Basic) and passes their own Authorization header to the app once they are in. Per-recipient access links open it for one person each, revocable on their own. |
| Backups and restore | live | Declare how the data is backed up. A deploy of an app that already has a release then backs it up first (before its first pre-deploy hook, else its migration, else its start), as well as on demand and daily if asked. Copies leave the host with the platform backups. Restore is previewed and confirmed. |
| Moving between hosts | live | The release is copied, all source services stop, then a final volume backup is taken; the destination builds the release (or loads its image archive), restores the data and takes over the routing. Stateful moves require volume backups. The old copy is kept 7 days; admins can evacuate a whole host. |
| Image archives and the build ceiling | live | Build elsewhere (your machine, CI, a Devbox) and deploy the images: `archive`, then `deploy --image-archive`; the host loads them and builds nothing. Builds that do run on a host run inside its build ceiling, installed by each host's next onboarding. |
| Deploy settings and packaging | live | A migration service and pre/post-deploy hooks; a Compose file in a subdirectory; `.pitchstationignore`; env templates kept; local databases left out; Next.js (standalone) scaffolding for npm and pnpm workspaces. Build-time env keys say when a change needs a redeploy. |
| Private apps: callbacks, caching, sign-in, link use | live | Callback paths skip the gate (never expiry); content-hashed assets may be cached in the viewer's browser; listed PitchStation people and teams sign in with their account; each access link shows its use. Each host's policy verifier upgrades at its next routing operation; link use arrives once its reporter is updated by onboarding. |
| Strict hosts, egress controls | live | A Compose allowlist and no-new-privileges on strict hosts; outbound mail, the metadata service and connection floods blocked on restricted hosts. The team hosts stay standard and open unless an admin switches them. On an owner's own host an admin can grandfather a reviewed finding (audited), so the host can enforce the rules. |
| Isolated host per developer, spend cap | first launch pending | Reserve a host of your own inside your monthly cap (shared with dev instances); an administrator launches it with the scoped AWS profile, and it runs strict, user-namespace remapped and egress-restricted from its first boot. Every host reports memory, disk and load every 5 minutes, with a growth proposal when it stays full. |
| Per-app DNS records | zone delegation pending | Implemented for Route 53: each app gets its own record, so apps can move between hosts under one name. Active once the app zones are delegated. |
| Abuse reports, takedown, terms | live | Public reports at [/abuse.html](/abuse.html) go to an admin queue; takedown stops an app and answers 404 until lifted. Publisher terms can be required (off for the team). |
| Renewal alerts by email | not enabled | Certificates renew automatically; expiry alerts need separate monitoring configuration. |

## §06 Limits

| What | Limit |
| --- | --- |
| Source upload | 80 MiB compressed, 256 MiB expanded, 20,000 files; no links, devices, traversal or duplicate paths; files containing private keys are refused |
| Health check | Your `healthPath` must answer HTTP 200 within the poll window (60 s) after start; a redirect is a failure |
| Step time budgets | build 20 min · migrate 15 min · up 10 min · health 5 min; any single remote step 30 min |
| Requests to your app | 64 MiB request bodies · 300 s proxy read timeout · WebSockets supported |
| Plans and evidence | A reviewed domains/policy plan expires after 15 minutes; a readiness result is valid for 5 minutes |
| Preview password | 12–72 UTF-8 bytes, chosen and kept by the owner |
| Host ports | One permanent port per app in 41000–41999, loopback only |
| Budget per app | Default 512 MB memory, 1 CPU, 256 processes (64–16,384 MB, 0.1–16 CPUs, 32–4,096 processes). A host admits budgets up to its memory minus the host's reserve (512 MB unless an administrator changes it), times an overcommit factor: ×1.25 on owner hosts and ×1.0 on shared hosts (server settings `APP_MEM_OVERCOMMIT_OWNER` and `APP_MEM_OVERCOMMIT_POOL`) |
| Shared hosts | 3 apps per person by default; an app there must be stopped before it is deleted |
| Logs | Up to 1,000 lines or 256 KiB per read; 10 status or log reads a minute per person per app |

## §07 Where next

**User manual**

Task by task: access and setup, a first deploy, the Apps web page panel by panel, domains, access, settings, monitoring, recovery, error codes, data, limits and a FAQ.

**Deploy guide**

The app contract, then step-by-step deploys through the skill, MCP, the client and REST; addresses, access, env, rollback and troubleshooting.

**API reference**

Every endpoint, the dry-run / ETag / idempotency conventions, operation states and the typed error codes.

**Architecture & separation**

How the pieces fit, what Apps borrows from the rest of PitchStation, and the staged design for running it as a separate service or platform.
