Environments
The three environments a request can run in, how it lands in one, and why that decision is never re-derived downstream.
A request to a Remy app runs in exactly one of three environments: live, preview, or dev. This chapter covers what each one is, how a request lands in one, and why that decision is made once, at the boundary, and never re-derived downstream.
#The Three Environments
Live. The app's promoted release: every request to the app's own origin, its custom domain, its API keys, its cron jobs, its webhooks, and its inbound email resolves here. Live moves only when a new release is promoted.
Preview. A branch build. Pushing any branch other than the default produces a preview release, served on a gated host with a double-hyphen label so it is never mistaken for the app's own origin. A preview has its own cloned data plane: it never reads or writes live data. Preview hosts are gated by default, shareable outside the workspace only through share links.
Dev. A person's working copy. A dev environment is keyed to the app, the person, and where their code runs, either a dev box inside the untrusted cluster or a laptop connected through the CLI tunnel. Each person with edit access has their own dev database, cloned from live at session start, which they can reset or truncate. Dev is not a branch. A branch is a git ref anyone can move, and the platform tracks nothing about branches beyond which one is production.
| Live | Preview | Dev | |
|---|---|---|---|
| Release | The promoted release | The branch's preview release | A dev release per workspace |
| Host | The app's origin and custom domains | A gated preview host | The dev box's preview host, via the sandbox proxy |
| Data plane | The live databases | A clone for the preview release | A clone for the dev release |
| Execution | A release sandbox | A release sandbox | The dev box, or the CLI tunnel |
| Who reaches it | Anyone the app admits | Workspace members and share-link holders | The person, and their own preview |
#The Boundary Decides Once
Three boundary checks turn a request into an environment:
- The host. An app's own origin serves live; a gated double-hyphen origin serves that branch's build. A host is only ever one of those two things.
- The session. The credential a request carries can refine the host's answer, but only in a fixed order, highest priority first:
- A preview host wins outright: a dev-session token presented there cannot retarget a gated origin.
- Otherwise, the session's own declared environment governs, dev before preview.
- Otherwise, a validated dev-session header, the tunnel's escape hatch for requests it proxies in from outside.
- Otherwise, whatever the host said.
- The hook token. A callback carries the environment its hook token was minted in, so a call from inside a sandbox lands in the same world as the request that started it.
Each check produces one environment object that lazily answers which release a request is on, along with its manifest, app name, method map, and interface config. That object is a required parameter to every serve handler, so a new surface cannot be built without deciding its environment.
Downstream code may read which of the three worlds it is in, but it may not re-derive which release, config, or data plane it is on. All three cases answer those questions the same way, and a call site cannot tell them apart.
#What Dev Is Keyed To
A dev environment is keyed to the app, the person, and where their code runs: a dev box or a laptop. The dev release is per workspace and is resumed rather than recreated, so hook tokens and data-plane keys stay valid across a box restart.
The dev box's preview is served on its own domain, separate from the app's, so unreleased, agent-authored code never shares a cookie scope with deployed apps or with the preview gate. The control channel and language server are authenticated routes on the API host, a different origin again, so code running in a preview cannot reach the box's control surfaces.
Figure 03, "Environments": a decision funnel that resolves to one of three worlds, read top to bottom. Three request signals -- the host, the session credential, and the hook token -- drop as arrows into the Environment boundary, a node inside a dashed "DECIDED ONCE" zone. The boundary carries the precedence ladder that resolves the session check, highest first: 1 preview host, 2 session env (declared), 3 dev-session header, 4 host; the first match wins. It emits one Resolved environment object (release, manifest, app name, method map, interface config), annotated "required on every serve handler" and "never re-derived downstream". The object fans to exactly one of three world pipelines -- Live, Preview, Dev -- each a top-down stack of world (host and who reaches it), running release (which build, where it runs), and data. The comparison reads across the row: the "runs in" line is a release sandbox for live and preview, a dev box or the CLI tunnel for dev. Along the bottom, a "DATA PLANE" band shows isolation. Live databases is a plain node; the Preview clone and Dev clone are drawn as stacked duplicates (a ghost sheet behind the node) so they read as copies, with the note "clones never read or write live". There is no trust boundary in this figure, so there is no crimson.