Vibecode CodeSandbox
track this build4 phases, 12 steps, beginner friendly0%You can self-host a browser IDE, but fast templates, previews, cloud VMs, collaboration, and workflow integrations are the product.
You are building a lean indie version of CodeSandbox. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # CodeSandbox · indie build A hosted development environment service where the whole engineering problem is running arbitrary untrusted code quickly, safely and cheaply, and where the difference between a good product and an incident is entirely in isolation and resource control. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Isolation | One sandbox per environment with no shared kernel surface where possible | the boundary is the product | | Startup | Snapshot and restore rather than cold boot | a development environment that takes a minute to start is not used | | Filesystem | A layered image with a writable overlay per environment | shared base layers are what make hundreds of environments affordable | | Networking | Egress denied by default with declared allowances | a blocklist is always incomplete | | Runtime | TypeScript control plane with a container or microvm layer | the control plane is small; the isolation layer is the work | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the control plane. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **A container or microvm runtime you understand** · free - Why: The isolation boundary is the product, and choosing a runtime without understanding its escape history is choosing a boundary you cannot reason about. - Get it: A runtime with a documented isolation model, and read its known weaknesses before building on it. - Verify: A hostile workload cannot reach the host or a neighbour - [ ] **A machine you can afford to have compromised** · the price of one small instance - Why: You will be running deliberately hostile code against your own isolation, and doing that on a machine with anything else on it is unwise. - Get it: A dedicated machine or an isolated cloud instance with nothing else on it and no credentials attached. - Verify: The machine holds no credentials and hosts nothing else - [ ] **Your resource ceilings and abuse policy** · free - Why: Free compute attracts mining, outbound traffic and content hosting within days, and the response path has to exist before the first environment is public. - Get it: Decide the four ceilings, what triggers a suspension, and how someone reports abuse to you. - Verify: A written policy exists with a reporting route and the ceilings are configured - [ ] **A set of deliberately hostile test environments** · free - Why: Isolation claims are only meaningful when something has actually tried to break them, and writing those attempts is part of the build rather than an audit afterwards. - Get it: Write environments that attempt host access, neighbour access, control plane access and egress to an undeclared destination. - Verify: Four hostile environments exist and all four are contained ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - A full desktop-quality editor. - Scheduling and bin packing at scale. - Language and framework breadth. - Any claim of perfect isolation. - instant templates - cloud sandboxes - preview URLs - collaboration - managed infrastructure - integration polish If one of those is essential to you, that is the reason to keep paying for CodeSandbox, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · CodeSandbox The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me ephemeral development environments in the browser that start fast and cannot escape to replace CodeSandbox. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero Everything here runs someone else's code on your infrastructure, and for a public sandbox that someone is anyone on the internet. Treat that as the primary constraint rather than as a hardening step later. Concretely: every environment is isolated with no ambient credentials, no access to other environments, no access to your control plane, and network egress restricted by default rather than open with a blocklist. A blocklist is always incomplete and the first thing an abusive environment does is find what you forgot. The second constraint is that free compute attracts abuse. Cryptocurrency mining, outbound attack traffic and content hosting are the three uses that arrive within days of a public endpoint. Resource ceilings, egress limits and a suspension path are not features to add after launch, they are what makes launch possible. ### Stack (fixed, do not substitute) - Isolation: One sandbox per environment with no shared kernel surface where possible · the boundary is the product - Startup: Snapshot and restore rather than cold boot · a development environment that takes a minute to start is not used - Filesystem: A layered image with a writable overlay per environment · shared base layers are what make hundreds of environments affordable - Networking: Egress denied by default with declared allowances · a blocklist is always incomplete - Runtime: TypeScript control plane with a container or microvm layer · the control plane is small; the isolation layer is the work ### Data model (create this before Phase 1) - environments(id, owner_id, template_id, state, created_at, last_active_at, suspended_reason) - snapshots(environment_id, id, storage_key, bytes, taken_at) · what makes a restart fast - templates(id, name, base_image_ref, default_resources_json) - resource_limits(environment_id, cpu_millis, memory_bytes, disk_bytes, egress_bytes_per_hour) - usage(environment_id, window_start, cpu_millis, egress_bytes, disk_bytes) - egress_rules(environment_id, ordinal, destination, allowed) · default deny, allowances explicit - suspensions(environment_id, reason, at, evidence_json, lifted_at) - An environment is suspended rather than deleted when it breaches a limit, because the usual cause is a runaway loop rather than malice and the owner's work should survive. ### Phase 1 · An environment that cannot see out Build: Run each environment in an isolated sandbox with no ambient credentials, no access to the host or other environments, and egress denied by default. Test with a deliberately hostile environment attempting each escape. Trap: Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. Done when: A hostile environment cannot read the host filesystem, reach the control plane, or contact another environment, each tested explicitly. Egress is denied by default and an allowance must be declared. No credential belonging to the platform is present in any environment. Escaping attempts are logged with enough detail to act on. Do not build yet: No startup performance, persistence or collaboration. ### Phase 2 · Starting fast enough to be used Build: Snapshot a booted environment and restore from the snapshot rather than booting from scratch. Share base image layers across environments. Measure time from request to a usable shell. Trap: Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. Done when: Time from request to usable shell is measured and is a couple of seconds for a warm template. Base image layers are shared, so a hundred environments from one template do not cost a hundred copies. A template change invalidates its snapshot rather than serving a stale one. Restoring produces an environment identical to the snapshot. Do not build yet: No persistence, limits or collaboration yet. ### Phase 3 · Limits that stop a runaway Build: Enforce processor, memory, disk and egress ceilings per environment. Suspend rather than destroy on breach, keeping the filesystem. Report the breach to the owner with what caused it. Trap: Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. Done when: An environment exceeding processor, memory, disk or egress limits is suspended rather than destroyed, with its filesystem intact. The owner is told which limit was breached and when. Suspension is liftable. A single environment cannot degrade performance for others, tested with a deliberate resource hog. Do not build yet: No persistence or collaboration yet. ### Phase 4 · Work that survives closing the tab Build: Persist the writable overlay and restore it on resume. Hibernate idle environments to reclaim compute while keeping the filesystem. Handle a browser disconnection mid-write. Trap: Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. Done when: Closing the browser and returning restores the environment with all changes intact. An idle environment hibernates, releasing compute while preserving the filesystem, and resumes quickly. A disconnection mid-write does not corrupt the overlay. Storage use per environment is visible and bounded. Do not build yet: No collaboration or sharing yet. ### Phase 5 · Sharing, forking and abuse Build: Forking an environment from a snapshot without copying secrets. Shared links with an access level and expiry. An abuse response path with suspension, evidence and a route to report. Trap: Forking an environment by copying its filesystem copies whatever the owner left in an environment file, so a shared template quietly hands out someone's credentials to everyone who forks it. Exclude secret-bearing paths from the fork and require the forker to supply their own. Done when: Forking excludes secret-bearing paths and requires the forker to supply their own, verified with a deliberately planted credential. Shared links carry an access level and expire. An abuse report produces a suspension with evidence retained. Egress patterns typical of mining or outbound scanning are detected and surfaced. Do not build yet: Nothing after this. ### Out of scope (and why) - A full editor experience comparable to a desktop environment, which is a very large project on its own. - Running at a scale where scheduling and bin packing become the hard problem, which is where this becomes a business. - Language and framework breadth, which is template maintenance without end. - Any claim of perfect isolation. Containers and virtual machines both have escape history and the mitigations are layered rather than absolute. ### README must contain - That every environment runs untrusted code and egress is denied by default rather than blocklisted - That environments are snapshotted warm and restored, because installing at start costs everyone the same minute - That a limit breach suspends rather than destroys, since most breaches are an accidental loop - That forking excludes secret-bearing paths, or a shared template hands out the owner's credentials - That the abuse response path exists before launch, because free compute attracts mining within days ===== AGENTS.md ===== # Agent instructions · CodeSandbox indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: One sandbox per environment with no shared kernel surface where possible, Snapshot and restore rather than cold boot, A layered image with a writable overlay per environment, Egress denied by default with declared allowances, TypeScript control plane with a container or microvm layer. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. - Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. - Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. - Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. ===== BUILD_PLAN.md ===== # Build plan · CodeSandbox A hosted development environment service where the whole engineering problem is running arbitrary untrusted code quickly, safely and cheaply, and where the difference between a good product and an incident is entirely in isolation and resource control. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · An environment that cannot see out Code inside a sandbox reaches nothing it was not given. ### Steps 1. Isolate with no ambient credentials Nothing in the environment belongs to the platform. Files: `src/sandbox/`, `tests/escape.test.ts` 2. Deny egress by default A blocklist is always incomplete and abuse finds the gap first. Files: `src/network.ts` 3. Test each escape route explicitly Host filesystem, control plane, neighbour environment. Files: `tests/escape.test.ts` ### Done when - [ ] A hostile environment cannot reach host, control plane or neighbours - [ ] Egress is denied by default - [ ] No platform credentials exist inside an environment - [ ] Escape attempts are logged usefully ### Watch out - Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. ## Phase 2 · Starting fast enough to be used An environment is ready in a couple of seconds, not a minute. ### Steps 1. Snapshot warm, restore from it Installing dependencies at start costs every environment the same minute. Files: `src/snapshots.ts` 2. Share base layers A hundred environments from one template should not be a hundred copies. Files: `src/images.ts` 3. Measure to usable, not to created Created and usable are different moments and only one matters. Files: `src/metrics.ts` ### Done when - [ ] Warm template start is a couple of seconds to usable shell - [ ] Base layers are shared across environments - [ ] A template change invalidates its snapshot - [ ] Restore is identical to the snapshot ### Watch out - Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. ## Phase 3 · Limits that stop a runaway A loop consuming everything is contained and its owner keeps their work. ### Steps 1. Enforce four ceilings Processor, memory, disk and egress. Egress is the one people forget. Files: `src/limits.ts` 2. Suspend, do not destroy Most breaches are a loop, not abuse. The work should survive. Files: `src/suspend.ts` 3. Prove neighbour isolation under load A resource hog must not degrade anyone else. Files: `tests/noisy-neighbour.test.ts` ### Done when - [ ] All four limits suspend rather than destroy - [ ] The filesystem survives suspension - [ ] The owner is told which limit was hit - [ ] A resource hog does not degrade neighbours ### Watch out - Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. ## Phase 4 · Work that survives closing the tab An environment resumes with the changes you made. ### Steps 1. Persist the writable overlay It is the user's work and it is not in version control yet. Files: `src/overlay.ts` 2. Hibernate rather than destroy People leave tabs open for days assuming safety. Files: `src/hibernate.ts` 3. Survive a mid-write disconnection Browsers close, networks drop, and neither should corrupt anything. Files: `src/overlay.ts` ### Done when - [ ] Returning restores all changes - [ ] Idle environments hibernate and resume quickly - [ ] A mid-write disconnection does not corrupt - [ ] Storage per environment is visible and bounded ### Watch out - Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. ## Not in this build - A full desktop-quality editor. - Scheduling and bin packing at scale. - Language and framework breadth. - Any claim of perfect isolation. ## After v1, if you want it - Preview URLs per environment, which need the same egress thinking in reverse - Collaborative editing inside one environment, which is a synchronisation project of its own - Prebuilt environments per repository branch, once snapshotting is reliable ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required · secret. Control plane state. Never reachable from inside an environment. DATABASE_URL=postgres://localhost:5432/environments # Required. Present as a constant. A blocklist is always incomplete. EGRESS_DEFAULT=deny # Required. Per environment. Exceeding suspends rather than destroys. CPU_MILLIS_LIMIT=2000 # Required. The limit that catches mining and outbound traffic first. EGRESS_BYTES_PER_HOUR=1073741824 # Required. Releases compute while preserving the filesystem. HIBERNATE_AFTER_MINUTES=30 # Required. Secret-bearing paths, excluded so a shared template does not leak credentials. FORK_EXCLUDE_PATHS=./config/fork-exclude.txt
You are building a lean indie version of CodeSandbox. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== README.md ===== # CodeSandbox · indie build A hosted development environment service where the whole engineering problem is running arbitrary untrusted code quickly, safely and cheaply, and where the difference between a good product and an incident is entirely in isolation and resource control. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Isolation | One sandbox per environment with no shared kernel surface where possible | the boundary is the product | | Startup | Snapshot and restore rather than cold boot | a development environment that takes a minute to start is not used | | Filesystem | A layered image with a writable overlay per environment | shared base layers are what make hundreds of environments affordable | | Networking | Egress denied by default with declared allowances | a blocklist is always incomplete | | Runtime | TypeScript control plane with a container or microvm layer | the control plane is small; the isolation layer is the work | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the control plane. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **A container or microvm runtime you understand** · free - Why: The isolation boundary is the product, and choosing a runtime without understanding its escape history is choosing a boundary you cannot reason about. - Get it: A runtime with a documented isolation model, and read its known weaknesses before building on it. - Verify: A hostile workload cannot reach the host or a neighbour - [ ] **A machine you can afford to have compromised** · the price of one small instance - Why: You will be running deliberately hostile code against your own isolation, and doing that on a machine with anything else on it is unwise. - Get it: A dedicated machine or an isolated cloud instance with nothing else on it and no credentials attached. - Verify: The machine holds no credentials and hosts nothing else - [ ] **Your resource ceilings and abuse policy** · free - Why: Free compute attracts mining, outbound traffic and content hosting within days, and the response path has to exist before the first environment is public. - Get it: Decide the four ceilings, what triggers a suspension, and how someone reports abuse to you. - Verify: A written policy exists with a reporting route and the ceilings are configured - [ ] **A set of deliberately hostile test environments** · free - Why: Isolation claims are only meaningful when something has actually tried to break them, and writing those attempts is part of the build rather than an audit afterwards. - Get it: Write environments that attempt host access, neighbour access, control plane access and egress to an undeclared destination. - Verify: Four hostile environments exist and all four are contained ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - A full desktop-quality editor. - Scheduling and bin packing at scale. - Language and framework breadth. - Any claim of perfect isolation. - instant templates - cloud sandboxes - preview URLs - collaboration - managed infrastructure - integration polish If one of those is essential to you, that is the reason to keep paying for CodeSandbox, and the README should say so rather than pretend. ===== BRIEF.md ===== # Build brief · CodeSandbox The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me ephemeral development environments in the browser that start fast and cannot escape to replace CodeSandbox. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero Everything here runs someone else's code on your infrastructure, and for a public sandbox that someone is anyone on the internet. Treat that as the primary constraint rather than as a hardening step later. Concretely: every environment is isolated with no ambient credentials, no access to other environments, no access to your control plane, and network egress restricted by default rather than open with a blocklist. A blocklist is always incomplete and the first thing an abusive environment does is find what you forgot. The second constraint is that free compute attracts abuse. Cryptocurrency mining, outbound attack traffic and content hosting are the three uses that arrive within days of a public endpoint. Resource ceilings, egress limits and a suspension path are not features to add after launch, they are what makes launch possible. ### Stack (fixed, do not substitute) - Isolation: One sandbox per environment with no shared kernel surface where possible · the boundary is the product - Startup: Snapshot and restore rather than cold boot · a development environment that takes a minute to start is not used - Filesystem: A layered image with a writable overlay per environment · shared base layers are what make hundreds of environments affordable - Networking: Egress denied by default with declared allowances · a blocklist is always incomplete - Runtime: TypeScript control plane with a container or microvm layer · the control plane is small; the isolation layer is the work ### Data model (create this before Phase 1) - environments(id, owner_id, template_id, state, created_at, last_active_at, suspended_reason) - snapshots(environment_id, id, storage_key, bytes, taken_at) · what makes a restart fast - templates(id, name, base_image_ref, default_resources_json) - resource_limits(environment_id, cpu_millis, memory_bytes, disk_bytes, egress_bytes_per_hour) - usage(environment_id, window_start, cpu_millis, egress_bytes, disk_bytes) - egress_rules(environment_id, ordinal, destination, allowed) · default deny, allowances explicit - suspensions(environment_id, reason, at, evidence_json, lifted_at) - An environment is suspended rather than deleted when it breaches a limit, because the usual cause is a runaway loop rather than malice and the owner's work should survive. ### Phase 1 · An environment that cannot see out Build: Run each environment in an isolated sandbox with no ambient credentials, no access to the host or other environments, and egress denied by default. Test with a deliberately hostile environment attempting each escape. Trap: Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. Done when: A hostile environment cannot read the host filesystem, reach the control plane, or contact another environment, each tested explicitly. Egress is denied by default and an allowance must be declared. No credential belonging to the platform is present in any environment. Escaping attempts are logged with enough detail to act on. Do not build yet: No startup performance, persistence or collaboration. ### Phase 2 · Starting fast enough to be used Build: Snapshot a booted environment and restore from the snapshot rather than booting from scratch. Share base image layers across environments. Measure time from request to a usable shell. Trap: Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. Done when: Time from request to usable shell is measured and is a couple of seconds for a warm template. Base image layers are shared, so a hundred environments from one template do not cost a hundred copies. A template change invalidates its snapshot rather than serving a stale one. Restoring produces an environment identical to the snapshot. Do not build yet: No persistence, limits or collaboration yet. ### Phase 3 · Limits that stop a runaway Build: Enforce processor, memory, disk and egress ceilings per environment. Suspend rather than destroy on breach, keeping the filesystem. Report the breach to the owner with what caused it. Trap: Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. Done when: An environment exceeding processor, memory, disk or egress limits is suspended rather than destroyed, with its filesystem intact. The owner is told which limit was breached and when. Suspension is liftable. A single environment cannot degrade performance for others, tested with a deliberate resource hog. Do not build yet: No persistence or collaboration yet. ### Phase 4 · Work that survives closing the tab Build: Persist the writable overlay and restore it on resume. Hibernate idle environments to reclaim compute while keeping the filesystem. Handle a browser disconnection mid-write. Trap: Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. Done when: Closing the browser and returning restores the environment with all changes intact. An idle environment hibernates, releasing compute while preserving the filesystem, and resumes quickly. A disconnection mid-write does not corrupt the overlay. Storage use per environment is visible and bounded. Do not build yet: No collaboration or sharing yet. ### Phase 5 · Sharing, forking and abuse Build: Forking an environment from a snapshot without copying secrets. Shared links with an access level and expiry. An abuse response path with suspension, evidence and a route to report. Trap: Forking an environment by copying its filesystem copies whatever the owner left in an environment file, so a shared template quietly hands out someone's credentials to everyone who forks it. Exclude secret-bearing paths from the fork and require the forker to supply their own. Done when: Forking excludes secret-bearing paths and requires the forker to supply their own, verified with a deliberately planted credential. Shared links carry an access level and expire. An abuse report produces a suspension with evidence retained. Egress patterns typical of mining or outbound scanning are detected and surfaced. Do not build yet: Nothing after this. ### Out of scope (and why) - A full editor experience comparable to a desktop environment, which is a very large project on its own. - Running at a scale where scheduling and bin packing become the hard problem, which is where this becomes a business. - Language and framework breadth, which is template maintenance without end. - Any claim of perfect isolation. Containers and virtual machines both have escape history and the mitigations are layered rather than absolute. ### README must contain - That every environment runs untrusted code and egress is denied by default rather than blocklisted - That environments are snapshotted warm and restored, because installing at start costs everyone the same minute - That a limit breach suspends rather than destroys, since most breaches are an accidental loop - That forking excludes secret-bearing paths, or a shared template hands out the owner's credentials - That the abuse response path exists before launch, because free compute attracts mining within days ===== AGENTS.md ===== # Agent instructions · CodeSandbox indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: One sandbox per environment with no shared kernel surface where possible, Snapshot and restore rather than cold boot, A layered image with a writable overlay per environment, Egress denied by default with declared allowances, TypeScript control plane with a container or microvm layer. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. - Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. - Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. - Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. ===== BUILD_PLAN.md ===== # Build plan · CodeSandbox A hosted development environment service where the whole engineering problem is running arbitrary untrusted code quickly, safely and cheaply, and where the difference between a good product and an incident is entirely in isolation and resource control. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · An environment that cannot see out Code inside a sandbox reaches nothing it was not given. ### Steps 1. Isolate with no ambient credentials Nothing in the environment belongs to the platform. Files: `src/sandbox/`, `tests/escape.test.ts` 2. Deny egress by default A blocklist is always incomplete and abuse finds the gap first. Files: `src/network.ts` 3. Test each escape route explicitly Host filesystem, control plane, neighbour environment. Files: `tests/escape.test.ts` ### Done when - [ ] A hostile environment cannot reach host, control plane or neighbours - [ ] Egress is denied by default - [ ] No platform credentials exist inside an environment - [ ] Escape attempts are logged usefully ### Watch out - Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. ## Phase 2 · Starting fast enough to be used An environment is ready in a couple of seconds, not a minute. ### Steps 1. Snapshot warm, restore from it Installing dependencies at start costs every environment the same minute. Files: `src/snapshots.ts` 2. Share base layers A hundred environments from one template should not be a hundred copies. Files: `src/images.ts` 3. Measure to usable, not to created Created and usable are different moments and only one matters. Files: `src/metrics.ts` ### Done when - [ ] Warm template start is a couple of seconds to usable shell - [ ] Base layers are shared across environments - [ ] A template change invalidates its snapshot - [ ] Restore is identical to the snapshot ### Watch out - Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. ## Phase 3 · Limits that stop a runaway A loop consuming everything is contained and its owner keeps their work. ### Steps 1. Enforce four ceilings Processor, memory, disk and egress. Egress is the one people forget. Files: `src/limits.ts` 2. Suspend, do not destroy Most breaches are a loop, not abuse. The work should survive. Files: `src/suspend.ts` 3. Prove neighbour isolation under load A resource hog must not degrade anyone else. Files: `tests/noisy-neighbour.test.ts` ### Done when - [ ] All four limits suspend rather than destroy - [ ] The filesystem survives suspension - [ ] The owner is told which limit was hit - [ ] A resource hog does not degrade neighbours ### Watch out - Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. ## Phase 4 · Work that survives closing the tab An environment resumes with the changes you made. ### Steps 1. Persist the writable overlay It is the user's work and it is not in version control yet. Files: `src/overlay.ts` 2. Hibernate rather than destroy People leave tabs open for days assuming safety. Files: `src/hibernate.ts` 3. Survive a mid-write disconnection Browsers close, networks drop, and neither should corrupt anything. Files: `src/overlay.ts` ### Done when - [ ] Returning restores all changes - [ ] Idle environments hibernate and resume quickly - [ ] A mid-write disconnection does not corrupt - [ ] Storage per environment is visible and bounded ### Watch out - Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. ## Not in this build - A full desktop-quality editor. - Scheduling and bin packing at scale. - Language and framework breadth. - Any claim of perfect isolation. ## After v1, if you want it - Preview URLs per environment, which need the same egress thinking in reverse - Collaborative editing inside one environment, which is a synchronisation project of its own - Prebuilt environments per repository branch, once snapshotting is reliable ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required · secret. Control plane state. Never reachable from inside an environment. DATABASE_URL=postgres://localhost:5432/environments # Required. Present as a constant. A blocklist is always incomplete. EGRESS_DEFAULT=deny # Required. Per environment. Exceeding suspends rather than destroys. CPU_MILLIS_LIMIT=2000 # Required. The limit that catches mining and outbound traffic first. EGRESS_BYTES_PER_HOUR=1073741824 # Required. Releases compute while preserving the filesystem. HIBERNATE_AFTER_MINUTES=30 # Required. Secret-bearing paths, excluded so a shared template does not leak credentials. FORK_EXCLUDE_PATHS=./config/fork-exclude.txt
You are building a production product version of CodeSandbox. Create the following project files first, then implement the application by following them. Keep the files updated as decisions change. Do not collapse this into a single README or prompt. ===== PRODUCT.md ===== # CodeSandbox · product brief ## Problem You can self-host a browser IDE, but fast templates, previews, cloud VMs, collaboration, and workflow integrations are the product. ## Product outcome Development environments that open in seconds, cannot reach each other or your infrastructure, and suspend a runaway loop without losing the owner's work. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - container host - code-server/devcontainer tooling - reverse proxy - git integration - auth ## Explicit non-goals for v1 - A full desktop-quality editor. - Scheduling and bin packing at scale. - Language and framework breadth. - Any claim of perfect isolation. - instant templates - cloud sandboxes - preview URLs - collaboration - managed infrastructure - integration polish ## Success criteria - Four hostile environments are confirmed contained - Egress is confirmed denied by default - A limit breach is confirmed to suspend with the filesystem intact - Returning is confirmed to restore all changes - Forking is confirmed to exclude planted credentials ===== BRIEF.md ===== # Build brief · CodeSandbox The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me ephemeral development environments in the browser that start fast and cannot escape to replace CodeSandbox. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero Everything here runs someone else's code on your infrastructure, and for a public sandbox that someone is anyone on the internet. Treat that as the primary constraint rather than as a hardening step later. Concretely: every environment is isolated with no ambient credentials, no access to other environments, no access to your control plane, and network egress restricted by default rather than open with a blocklist. A blocklist is always incomplete and the first thing an abusive environment does is find what you forgot. The second constraint is that free compute attracts abuse. Cryptocurrency mining, outbound attack traffic and content hosting are the three uses that arrive within days of a public endpoint. Resource ceilings, egress limits and a suspension path are not features to add after launch, they are what makes launch possible. ### Stack (fixed, do not substitute) - Isolation: One sandbox per environment with no shared kernel surface where possible · the boundary is the product - Startup: Snapshot and restore rather than cold boot · a development environment that takes a minute to start is not used - Filesystem: A layered image with a writable overlay per environment · shared base layers are what make hundreds of environments affordable - Networking: Egress denied by default with declared allowances · a blocklist is always incomplete - Runtime: TypeScript control plane with a container or microvm layer · the control plane is small; the isolation layer is the work ### Data model (create this before Phase 1) - environments(id, owner_id, template_id, state, created_at, last_active_at, suspended_reason) - snapshots(environment_id, id, storage_key, bytes, taken_at) · what makes a restart fast - templates(id, name, base_image_ref, default_resources_json) - resource_limits(environment_id, cpu_millis, memory_bytes, disk_bytes, egress_bytes_per_hour) - usage(environment_id, window_start, cpu_millis, egress_bytes, disk_bytes) - egress_rules(environment_id, ordinal, destination, allowed) · default deny, allowances explicit - suspensions(environment_id, reason, at, evidence_json, lifted_at) - An environment is suspended rather than deleted when it breaches a limit, because the usual cause is a runaway loop rather than malice and the owner's work should survive. ### Phase 1 · An environment that cannot see out Build: Run each environment in an isolated sandbox with no ambient credentials, no access to the host or other environments, and egress denied by default. Test with a deliberately hostile environment attempting each escape. Trap: Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. Done when: A hostile environment cannot read the host filesystem, reach the control plane, or contact another environment, each tested explicitly. Egress is denied by default and an allowance must be declared. No credential belonging to the platform is present in any environment. Escaping attempts are logged with enough detail to act on. Do not build yet: No startup performance, persistence or collaboration. ### Phase 2 · Starting fast enough to be used Build: Snapshot a booted environment and restore from the snapshot rather than booting from scratch. Share base image layers across environments. Measure time from request to a usable shell. Trap: Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. Done when: Time from request to usable shell is measured and is a couple of seconds for a warm template. Base image layers are shared, so a hundred environments from one template do not cost a hundred copies. A template change invalidates its snapshot rather than serving a stale one. Restoring produces an environment identical to the snapshot. Do not build yet: No persistence, limits or collaboration yet. ### Phase 3 · Limits that stop a runaway Build: Enforce processor, memory, disk and egress ceilings per environment. Suspend rather than destroy on breach, keeping the filesystem. Report the breach to the owner with what caused it. Trap: Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. Done when: An environment exceeding processor, memory, disk or egress limits is suspended rather than destroyed, with its filesystem intact. The owner is told which limit was breached and when. Suspension is liftable. A single environment cannot degrade performance for others, tested with a deliberate resource hog. Do not build yet: No persistence or collaboration yet. ### Phase 4 · Work that survives closing the tab Build: Persist the writable overlay and restore it on resume. Hibernate idle environments to reclaim compute while keeping the filesystem. Handle a browser disconnection mid-write. Trap: Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. Done when: Closing the browser and returning restores the environment with all changes intact. An idle environment hibernates, releasing compute while preserving the filesystem, and resumes quickly. A disconnection mid-write does not corrupt the overlay. Storage use per environment is visible and bounded. Do not build yet: No collaboration or sharing yet. ### Phase 5 · Sharing, forking and abuse Build: Forking an environment from a snapshot without copying secrets. Shared links with an access level and expiry. An abuse response path with suspension, evidence and a route to report. Trap: Forking an environment by copying its filesystem copies whatever the owner left in an environment file, so a shared template quietly hands out someone's credentials to everyone who forks it. Exclude secret-bearing paths from the fork and require the forker to supply their own. Done when: Forking excludes secret-bearing paths and requires the forker to supply their own, verified with a deliberately planted credential. Shared links carry an access level and expire. An abuse report produces a suspension with evidence retained. Egress patterns typical of mining or outbound scanning are detected and surfaced. Do not build yet: Nothing after this. ### Out of scope (and why) - A full editor experience comparable to a desktop environment, which is a very large project on its own. - Running at a scale where scheduling and bin packing become the hard problem, which is where this becomes a business. - Language and framework breadth, which is template maintenance without end. - Any claim of perfect isolation. Containers and virtual machines both have escape history and the mitigations are layered rather than absolute. ### README must contain - That every environment runs untrusted code and egress is denied by default rather than blocklisted - That environments are snapshotted warm and restored, because installing at start costs everyone the same minute - That a limit breach suspends rather than destroys, since most breaches are an accidental loop - That forking excludes secret-bearing paths, or a shared template hands out the owner's credentials - That the abuse response path exists before launch, because free compute attracts mining within days ===== ARCHITECTURE.md ===== # Architecture · CodeSandbox ## Stack | Part | Choice | Why | | --- | --- | --- | | Isolation | One sandbox per environment with no shared kernel surface where possible | the boundary is the product | | Startup | Snapshot and restore rather than cold boot | a development environment that takes a minute to start is not used | | Filesystem | A layered image with a writable overlay per environment | shared base layers are what make hundreds of environments affordable | | Networking | Egress denied by default with declared allowances | a blocklist is always incomplete | | Runtime | TypeScript control plane with a container or microvm layer | the control plane is small; the isolation layer is the work | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Isolation | The boundary around untrusted code. | Any runtime, provided its escape history is understood rather than assumed away. | | Snapshots | Fast start from warm state. | Any mechanism, provided the cost is paid per template rather than per environment. | | Limits | Four ceilings with suspension. | Any enforcement, provided breach suspends rather than destroys. | | Persistence | The writable overlay and hibernation. | Any store, provided idle reclamation preserves the filesystem. | | Abuse | Detection, suspension and reporting. | Not swappable for a later addition. Free compute is abused within days. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `DATABASE_URL` · required, secret · Control plane state. Never reachable from inside an environment. - `EGRESS_DEFAULT` · required · Present as a constant. A blocklist is always incomplete. - `CPU_MILLIS_LIMIT` · required · Per environment. Exceeding suspends rather than destroys. - `EGRESS_BYTES_PER_HOUR` · required · The limit that catches mining and outbound traffic first. - `HIBERNATE_AFTER_MINUTES` · required · Releases compute while preserving the filesystem. - `FORK_EXCLUDE_PATHS` · required · Secret-bearing paths, excluded so a shared template does not leak credentials. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it. ===== AGENTS.md ===== # Agent instructions · CodeSandbox product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: One sandbox per environment with no shared kernel surface where possible, Snapshot and restore rather than cold boot, A layered image with a writable overlay per environment, Egress denied by default with declared allowances, TypeScript control plane with a container or microvm layer. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. - Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. - Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. - Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. - Forking an environment by copying its filesystem copies whatever the owner left in an environment file, so a shared template quietly hands out someone's credentials to everyone who forks it. Exclude secret-bearing paths from the fork and require the forker to supply their own. ===== MILESTONES.md ===== # Delivery milestones · CodeSandbox Estimated effort: **multi-day** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · An environment that cannot see out Code inside a sandbox reaches nothing it was not given. ### Steps 1. Isolate with no ambient credentials Nothing in the environment belongs to the platform. Files: `src/sandbox/`, `tests/escape.test.ts` 2. Deny egress by default A blocklist is always incomplete and abuse finds the gap first. Files: `src/network.ts` 3. Test each escape route explicitly Host filesystem, control plane, neighbour environment. Files: `tests/escape.test.ts` ### Done when - [ ] A hostile environment cannot reach host, control plane or neighbours - [ ] Egress is denied by default - [ ] No platform credentials exist inside an environment - [ ] Escape attempts are logged usefully ### Watch out - Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. ## M2 · Starting fast enough to be used An environment is ready in a couple of seconds, not a minute. ### Steps 1. Snapshot warm, restore from it Installing dependencies at start costs every environment the same minute. Files: `src/snapshots.ts` 2. Share base layers A hundred environments from one template should not be a hundred copies. Files: `src/images.ts` 3. Measure to usable, not to created Created and usable are different moments and only one matters. Files: `src/metrics.ts` ### Done when - [ ] Warm template start is a couple of seconds to usable shell - [ ] Base layers are shared across environments - [ ] A template change invalidates its snapshot - [ ] Restore is identical to the snapshot ### Watch out - Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. ## M3 · Limits that stop a runaway A loop consuming everything is contained and its owner keeps their work. ### Steps 1. Enforce four ceilings Processor, memory, disk and egress. Egress is the one people forget. Files: `src/limits.ts` 2. Suspend, do not destroy Most breaches are a loop, not abuse. The work should survive. Files: `src/suspend.ts` 3. Prove neighbour isolation under load A resource hog must not degrade anyone else. Files: `tests/noisy-neighbour.test.ts` ### Done when - [ ] All four limits suspend rather than destroy - [ ] The filesystem survives suspension - [ ] The owner is told which limit was hit - [ ] A resource hog does not degrade neighbours ### Watch out - Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. ## M4 · Work that survives closing the tab An environment resumes with the changes you made. ### Steps 1. Persist the writable overlay It is the user's work and it is not in version control yet. Files: `src/overlay.ts` 2. Hibernate rather than destroy People leave tabs open for days assuming safety. Files: `src/hibernate.ts` 3. Survive a mid-write disconnection Browsers close, networks drop, and neither should corrupt anything. Files: `src/overlay.ts` ### Done when - [ ] Returning restores all changes - [ ] Idle environments hibernate and resume quickly - [ ] A mid-write disconnection does not corrupt - [ ] Storage per environment is visible and bounded ### Watch out - Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. ## M5 · Sharing, forking and abuse (production only) An environment can be shared safely and abuse is handled before it becomes your problem. ### Steps 1. Exclude secrets from forks A shared template otherwise hands out the owner's credentials. Files: `src/fork.ts`, `tests/fork-secrets.test.ts` 2. Expire shared links A link to a running environment is access to compute. Files: `src/sharing.ts` 3. Build the abuse path before launch Free compute attracts mining and outbound traffic within days. Files: `src/abuse.ts` ### Done when - [ ] Forking excludes planted credentials - [ ] Shared links carry access levels and expire - [ ] Abuse reports produce suspensions with evidence - [ ] Mining and scanning egress patterns are surfaced ### Watch out - Forking an environment by copying its filesystem copies whatever the owner left in an environment file, so a shared template quietly hands out someone's credentials to everyone who forks it. Exclude secret-bearing paths from the fork and require the forker to supply their own. ===== OPERATIONS.md ===== # Operations · CodeSandbox ## Backup User overlays are their unsaved work and are the thing they would be most upset to lose. Snapshots and base images regenerate. Back up overlays and treat everything else as rebuildable. ## Restore Restore and confirm suspended environments come back suspended rather than running, since restoring a suspended abusive environment to a running state resumes whatever it was doing. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Egress volume per environment and processor saturation are the abuse signals, and they lead the abuse report rather than following it. Start-to-usable time is the product metric. ## Incident checklist Outbound attack traffic from your address range is the incident that costs you your hosting, and it arrives as an abuse report rather than an alert unless egress is monitored. The default-deny posture is what makes it rare rather than routine. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Four hostile environments are confirmed contained - [ ] Egress is confirmed denied by default - [ ] A limit breach is confirmed to suspend with the filesystem intact - [ ] Returning is confirmed to restore all changes - [ ] Forking is confirmed to exclude planted credentials ## Launch constraint Do not market omitted CodeSandbox capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered. ===== .env.example ===== # Copy to .env and fill in. Never commit .env; this file documents it. # Required · secret. Control plane state. Never reachable from inside an environment. DATABASE_URL=postgres://localhost:5432/environments # Required. Present as a constant. A blocklist is always incomplete. EGRESS_DEFAULT=deny # Required. Per environment. Exceeding suspends rather than destroys. CPU_MILLIS_LIMIT=2000 # Required. The limit that catches mining and outbound traffic first. EGRESS_BYTES_PER_HOUR=1073741824 # Required. Releases compute while preserving the filesystem. HIBERNATE_AFTER_MINUTES=30 # Required. Secret-bearing paths, excluded so a shared template does not leak credentials. FORK_EXCLUDE_PATHS=./config/fork-exclude.txt
# CodeSandbox · indie build A hosted development environment service where the whole engineering problem is running arbitrary untrusted code quickly, safely and cheaply, and where the difference between a good product and an incident is entirely in isolation and resource control. Estimated effort: **multi-day**. Work `BUILD_PLAN.md` top to bottom · every phase ends in a check that has to pass before the next one starts. ## Stack | Part | Choice | Why | | --- | --- | --- | | Isolation | One sandbox per environment with no shared kernel surface where possible | the boundary is the product | | Startup | Snapshot and restore rather than cold boot | a development environment that takes a minute to start is not used | | Filesystem | A layered image with a writable overlay per environment | shared base layers are what make hundreds of environments affordable | | Networking | Egress denied by default with declared allowances | a blocklist is always incomplete | | Runtime | TypeScript control plane with a container or microvm layer | the control plane is small; the isolation layer is the work | ## Before you start Have every one of these ready. The plan assumes them from step one. - [ ] **Node.js 22 or newer** · free - Why: Runs the control plane. - Get it: nodejs.org, or nvm install 22. - Verify: node --version prints v22 or higher - [ ] **A container or microvm runtime you understand** · free - Why: The isolation boundary is the product, and choosing a runtime without understanding its escape history is choosing a boundary you cannot reason about. - Get it: A runtime with a documented isolation model, and read its known weaknesses before building on it. - Verify: A hostile workload cannot reach the host or a neighbour - [ ] **A machine you can afford to have compromised** · the price of one small instance - Why: You will be running deliberately hostile code against your own isolation, and doing that on a machine with anything else on it is unwise. - Get it: A dedicated machine or an isolated cloud instance with nothing else on it and no credentials attached. - Verify: The machine holds no credentials and hosts nothing else - [ ] **Your resource ceilings and abuse policy** · free - Why: Free compute attracts mining, outbound traffic and content hosting within days, and the response path has to exist before the first environment is public. - Get it: Decide the four ceilings, what triggers a suspension, and how someone reports abuse to you. - Verify: A written policy exists with a reporting route and the ceilings are configured - [ ] **A set of deliberately hostile test environments** · free - Why: Isolation claims are only meaningful when something has actually tried to break them, and writing those attempts is part of the build rather than an audit afterwards. - Get it: Write environments that attempt host access, neighbour access, control plane access and egress to an undeclared destination. - Verify: Four hostile environments exist and all four are contained ## Quick start Follow Phase 1 in `BUILD_PLAN.md`; it creates the project. Then copy `.env.example` to `.env` and fill in the values it documents. ## Honest limits This build deliberately does not replace: - A full desktop-quality editor. - Scheduling and bin packing at scale. - Language and framework breadth. - Any claim of perfect isolation. - instant templates - cloud sandboxes - preview URLs - collaboration - managed infrastructure - integration polish If one of those is essential to you, that is the reason to keep paying for CodeSandbox, and the README should say so rather than pretend.
# Build brief · CodeSandbox The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me ephemeral development environments in the browser that start fast and cannot escape to replace CodeSandbox. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero Everything here runs someone else's code on your infrastructure, and for a public sandbox that someone is anyone on the internet. Treat that as the primary constraint rather than as a hardening step later. Concretely: every environment is isolated with no ambient credentials, no access to other environments, no access to your control plane, and network egress restricted by default rather than open with a blocklist. A blocklist is always incomplete and the first thing an abusive environment does is find what you forgot. The second constraint is that free compute attracts abuse. Cryptocurrency mining, outbound attack traffic and content hosting are the three uses that arrive within days of a public endpoint. Resource ceilings, egress limits and a suspension path are not features to add after launch, they are what makes launch possible. ### Stack (fixed, do not substitute) - Isolation: One sandbox per environment with no shared kernel surface where possible · the boundary is the product - Startup: Snapshot and restore rather than cold boot · a development environment that takes a minute to start is not used - Filesystem: A layered image with a writable overlay per environment · shared base layers are what make hundreds of environments affordable - Networking: Egress denied by default with declared allowances · a blocklist is always incomplete - Runtime: TypeScript control plane with a container or microvm layer · the control plane is small; the isolation layer is the work ### Data model (create this before Phase 1) - environments(id, owner_id, template_id, state, created_at, last_active_at, suspended_reason) - snapshots(environment_id, id, storage_key, bytes, taken_at) · what makes a restart fast - templates(id, name, base_image_ref, default_resources_json) - resource_limits(environment_id, cpu_millis, memory_bytes, disk_bytes, egress_bytes_per_hour) - usage(environment_id, window_start, cpu_millis, egress_bytes, disk_bytes) - egress_rules(environment_id, ordinal, destination, allowed) · default deny, allowances explicit - suspensions(environment_id, reason, at, evidence_json, lifted_at) - An environment is suspended rather than deleted when it breaches a limit, because the usual cause is a runaway loop rather than malice and the owner's work should survive. ### Phase 1 · An environment that cannot see out Build: Run each environment in an isolated sandbox with no ambient credentials, no access to the host or other environments, and egress denied by default. Test with a deliberately hostile environment attempting each escape. Trap: Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. Done when: A hostile environment cannot read the host filesystem, reach the control plane, or contact another environment, each tested explicitly. Egress is denied by default and an allowance must be declared. No credential belonging to the platform is present in any environment. Escaping attempts are logged with enough detail to act on. Do not build yet: No startup performance, persistence or collaboration. ### Phase 2 · Starting fast enough to be used Build: Snapshot a booted environment and restore from the snapshot rather than booting from scratch. Share base image layers across environments. Measure time from request to a usable shell. Trap: Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. Done when: Time from request to usable shell is measured and is a couple of seconds for a warm template. Base image layers are shared, so a hundred environments from one template do not cost a hundred copies. A template change invalidates its snapshot rather than serving a stale one. Restoring produces an environment identical to the snapshot. Do not build yet: No persistence, limits or collaboration yet. ### Phase 3 · Limits that stop a runaway Build: Enforce processor, memory, disk and egress ceilings per environment. Suspend rather than destroy on breach, keeping the filesystem. Report the breach to the owner with what caused it. Trap: Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. Done when: An environment exceeding processor, memory, disk or egress limits is suspended rather than destroyed, with its filesystem intact. The owner is told which limit was breached and when. Suspension is liftable. A single environment cannot degrade performance for others, tested with a deliberate resource hog. Do not build yet: No persistence or collaboration yet. ### Phase 4 · Work that survives closing the tab Build: Persist the writable overlay and restore it on resume. Hibernate idle environments to reclaim compute while keeping the filesystem. Handle a browser disconnection mid-write. Trap: Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. Done when: Closing the browser and returning restores the environment with all changes intact. An idle environment hibernates, releasing compute while preserving the filesystem, and resumes quickly. A disconnection mid-write does not corrupt the overlay. Storage use per environment is visible and bounded. Do not build yet: No collaboration or sharing yet. ### Phase 5 · Sharing, forking and abuse Build: Forking an environment from a snapshot without copying secrets. Shared links with an access level and expiry. An abuse response path with suspension, evidence and a route to report. Trap: Forking an environment by copying its filesystem copies whatever the owner left in an environment file, so a shared template quietly hands out someone's credentials to everyone who forks it. Exclude secret-bearing paths from the fork and require the forker to supply their own. Done when: Forking excludes secret-bearing paths and requires the forker to supply their own, verified with a deliberately planted credential. Shared links carry an access level and expire. An abuse report produces a suspension with evidence retained. Egress patterns typical of mining or outbound scanning are detected and surfaced. Do not build yet: Nothing after this. ### Out of scope (and why) - A full editor experience comparable to a desktop environment, which is a very large project on its own. - Running at a scale where scheduling and bin packing become the hard problem, which is where this becomes a business. - Language and framework breadth, which is template maintenance without end. - Any claim of perfect isolation. Containers and virtual machines both have escape history and the mitigations are layered rather than absolute. ### README must contain - That every environment runs untrusted code and egress is denied by default rather than blocklisted - That environments are snapshotted warm and restored, because installing at start costs everyone the same minute - That a limit breach suspends rather than destroys, since most breaches are an accidental loop - That forking excludes secret-bearing paths, or a shared template hands out the owner's credentials - That the abuse response path exists before launch, because free compute attracts mining within days
# Agent instructions · CodeSandbox indie build - Read `README.md` and `BUILD_PLAN.md` before writing code. The stack is fixed: One sandbox per environment with no shared kernel surface where possible, Snapshot and restore rather than cold boot, A layered image with a writable overlay per environment, Egress denied by default with declared allowances, TypeScript control plane with a container or microvm layer. Do not substitute. - Work one phase at a time, in order. Do not start a phase until every "Done when" item of the previous one passes. - Prefer the fewest moving parts that satisfy the step. No frameworks, services or dependencies the plan does not name. - Secrets live in `.env`, never in source or logs. Keep `.env.example` current when a variable is introduced. - Do not invent cryptography, security guarantees, APIs or compliance claims. - Add a focused test for every destructive, security-sensitive or data-loss path the plan names. - Run the project checks before declaring a phase complete, and record any deliberate shortcut in the README under "Tradeoffs". ## Known traps - Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. - Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. - Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. - Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost.
# Build plan · CodeSandbox A hosted development environment service where the whole engineering problem is running arbitrary untrusted code quickly, safely and cheaply, and where the difference between a good product and an incident is entirely in isolation and resource control. Phases are in dependency order. Each ends in a "Done when" list; treat an unticked item as a blocker, not a note. ## Phase 1 · An environment that cannot see out Code inside a sandbox reaches nothing it was not given. ### Steps 1. Isolate with no ambient credentials Nothing in the environment belongs to the platform. Files: `src/sandbox/`, `tests/escape.test.ts` 2. Deny egress by default A blocklist is always incomplete and abuse finds the gap first. Files: `src/network.ts` 3. Test each escape route explicitly Host filesystem, control plane, neighbour environment. Files: `tests/escape.test.ts` ### Done when - [ ] A hostile environment cannot reach host, control plane or neighbours - [ ] Egress is denied by default - [ ] No platform credentials exist inside an environment - [ ] Escape attempts are logged usefully ### Watch out - Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. ## Phase 2 · Starting fast enough to be used An environment is ready in a couple of seconds, not a minute. ### Steps 1. Snapshot warm, restore from it Installing dependencies at start costs every environment the same minute. Files: `src/snapshots.ts` 2. Share base layers A hundred environments from one template should not be a hundred copies. Files: `src/images.ts` 3. Measure to usable, not to created Created and usable are different moments and only one matters. Files: `src/metrics.ts` ### Done when - [ ] Warm template start is a couple of seconds to usable shell - [ ] Base layers are shared across environments - [ ] A template change invalidates its snapshot - [ ] Restore is identical to the snapshot ### Watch out - Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. ## Phase 3 · Limits that stop a runaway A loop consuming everything is contained and its owner keeps their work. ### Steps 1. Enforce four ceilings Processor, memory, disk and egress. Egress is the one people forget. Files: `src/limits.ts` 2. Suspend, do not destroy Most breaches are a loop, not abuse. The work should survive. Files: `src/suspend.ts` 3. Prove neighbour isolation under load A resource hog must not degrade anyone else. Files: `tests/noisy-neighbour.test.ts` ### Done when - [ ] All four limits suspend rather than destroy - [ ] The filesystem survives suspension - [ ] The owner is told which limit was hit - [ ] A resource hog does not degrade neighbours ### Watch out - Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. ## Phase 4 · Work that survives closing the tab An environment resumes with the changes you made. ### Steps 1. Persist the writable overlay It is the user's work and it is not in version control yet. Files: `src/overlay.ts` 2. Hibernate rather than destroy People leave tabs open for days assuming safety. Files: `src/hibernate.ts` 3. Survive a mid-write disconnection Browsers close, networks drop, and neither should corrupt anything. Files: `src/overlay.ts` ### Done when - [ ] Returning restores all changes - [ ] Idle environments hibernate and resume quickly - [ ] A mid-write disconnection does not corrupt - [ ] Storage per environment is visible and bounded ### Watch out - Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. ## Not in this build - A full desktop-quality editor. - Scheduling and bin packing at scale. - Language and framework breadth. - Any claim of perfect isolation. ## After v1, if you want it - Preview URLs per environment, which need the same egress thinking in reverse - Collaborative editing inside one environment, which is a synchronisation project of its own - Prebuilt environments per repository branch, once snapshotting is reliable
# Copy to .env and fill in. Never commit .env; this file documents it. # Required · secret. Control plane state. Never reachable from inside an environment. DATABASE_URL=postgres://localhost:5432/environments # Required. Present as a constant. A blocklist is always incomplete. EGRESS_DEFAULT=deny # Required. Per environment. Exceeding suspends rather than destroys. CPU_MILLIS_LIMIT=2000 # Required. The limit that catches mining and outbound traffic first. EGRESS_BYTES_PER_HOUR=1073741824 # Required. Releases compute while preserving the filesystem. HIBERNATE_AFTER_MINUTES=30 # Required. Secret-bearing paths, excluded so a shared template does not leak credentials. FORK_EXCLUDE_PATHS=./config/fork-exclude.txt
# CodeSandbox · product brief ## Problem You can self-host a browser IDE, but fast templates, previews, cloud VMs, collaboration, and workflow integrations are the product. ## Product outcome Development environments that open in seconds, cannot reach each other or your infrastructure, and suspend a runaway loop without losing the owner's work. ## Target user A builder who needs a maintainable product foundation, not a one-off demo. ## Required capabilities - container host - code-server/devcontainer tooling - reverse proxy - git integration - auth ## Explicit non-goals for v1 - A full desktop-quality editor. - Scheduling and bin packing at scale. - Language and framework breadth. - Any claim of perfect isolation. - instant templates - cloud sandboxes - preview URLs - collaboration - managed infrastructure - integration polish ## Success criteria - Four hostile environments are confirmed contained - Egress is confirmed denied by default - A limit breach is confirmed to suspend with the filesystem intact - Returning is confirmed to restore all changes - Forking is confirmed to exclude planted credentials
# Build brief · CodeSandbox The one-shot brief this plan expands. `BUILD_PLAN.md` (or `MILESTONES.md`) is the same sequence broken into steps and checks; where the two disagree, the plan wins. Build me ephemeral development environments in the browser that start fast and cannot escape to replace CodeSandbox. Build it in phases, in the order below. Do not write the whole thing in one pass. Finish a phase, run its "Done when" check, fix what fails, and only then start the next phase. ### Rule zero Everything here runs someone else's code on your infrastructure, and for a public sandbox that someone is anyone on the internet. Treat that as the primary constraint rather than as a hardening step later. Concretely: every environment is isolated with no ambient credentials, no access to other environments, no access to your control plane, and network egress restricted by default rather than open with a blocklist. A blocklist is always incomplete and the first thing an abusive environment does is find what you forgot. The second constraint is that free compute attracts abuse. Cryptocurrency mining, outbound attack traffic and content hosting are the three uses that arrive within days of a public endpoint. Resource ceilings, egress limits and a suspension path are not features to add after launch, they are what makes launch possible. ### Stack (fixed, do not substitute) - Isolation: One sandbox per environment with no shared kernel surface where possible · the boundary is the product - Startup: Snapshot and restore rather than cold boot · a development environment that takes a minute to start is not used - Filesystem: A layered image with a writable overlay per environment · shared base layers are what make hundreds of environments affordable - Networking: Egress denied by default with declared allowances · a blocklist is always incomplete - Runtime: TypeScript control plane with a container or microvm layer · the control plane is small; the isolation layer is the work ### Data model (create this before Phase 1) - environments(id, owner_id, template_id, state, created_at, last_active_at, suspended_reason) - snapshots(environment_id, id, storage_key, bytes, taken_at) · what makes a restart fast - templates(id, name, base_image_ref, default_resources_json) - resource_limits(environment_id, cpu_millis, memory_bytes, disk_bytes, egress_bytes_per_hour) - usage(environment_id, window_start, cpu_millis, egress_bytes, disk_bytes) - egress_rules(environment_id, ordinal, destination, allowed) · default deny, allowances explicit - suspensions(environment_id, reason, at, evidence_json, lifted_at) - An environment is suspended rather than deleted when it breaches a limit, because the usual cause is a runaway loop rather than malice and the owner's work should survive. ### Phase 1 · An environment that cannot see out Build: Run each environment in an isolated sandbox with no ambient credentials, no access to the host or other environments, and egress denied by default. Test with a deliberately hostile environment attempting each escape. Trap: Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. Done when: A hostile environment cannot read the host filesystem, reach the control plane, or contact another environment, each tested explicitly. Egress is denied by default and an allowance must be declared. No credential belonging to the platform is present in any environment. Escaping attempts are logged with enough detail to act on. Do not build yet: No startup performance, persistence or collaboration. ### Phase 2 · Starting fast enough to be used Build: Snapshot a booted environment and restore from the snapshot rather than booting from scratch. Share base image layers across environments. Measure time from request to a usable shell. Trap: Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. Done when: Time from request to usable shell is measured and is a couple of seconds for a warm template. Base image layers are shared, so a hundred environments from one template do not cost a hundred copies. A template change invalidates its snapshot rather than serving a stale one. Restoring produces an environment identical to the snapshot. Do not build yet: No persistence, limits or collaboration yet. ### Phase 3 · Limits that stop a runaway Build: Enforce processor, memory, disk and egress ceilings per environment. Suspend rather than destroy on breach, keeping the filesystem. Report the breach to the owner with what caused it. Trap: Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. Done when: An environment exceeding processor, memory, disk or egress limits is suspended rather than destroyed, with its filesystem intact. The owner is told which limit was breached and when. Suspension is liftable. A single environment cannot degrade performance for others, tested with a deliberate resource hog. Do not build yet: No persistence or collaboration yet. ### Phase 4 · Work that survives closing the tab Build: Persist the writable overlay and restore it on resume. Hibernate idle environments to reclaim compute while keeping the filesystem. Handle a browser disconnection mid-write. Trap: Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. Done when: Closing the browser and returning restores the environment with all changes intact. An idle environment hibernates, releasing compute while preserving the filesystem, and resumes quickly. A disconnection mid-write does not corrupt the overlay. Storage use per environment is visible and bounded. Do not build yet: No collaboration or sharing yet. ### Phase 5 · Sharing, forking and abuse Build: Forking an environment from a snapshot without copying secrets. Shared links with an access level and expiry. An abuse response path with suspension, evidence and a route to report. Trap: Forking an environment by copying its filesystem copies whatever the owner left in an environment file, so a shared template quietly hands out someone's credentials to everyone who forks it. Exclude secret-bearing paths from the fork and require the forker to supply their own. Done when: Forking excludes secret-bearing paths and requires the forker to supply their own, verified with a deliberately planted credential. Shared links carry an access level and expire. An abuse report produces a suspension with evidence retained. Egress patterns typical of mining or outbound scanning are detected and surfaced. Do not build yet: Nothing after this. ### Out of scope (and why) - A full editor experience comparable to a desktop environment, which is a very large project on its own. - Running at a scale where scheduling and bin packing become the hard problem, which is where this becomes a business. - Language and framework breadth, which is template maintenance without end. - Any claim of perfect isolation. Containers and virtual machines both have escape history and the mitigations are layered rather than absolute. ### README must contain - That every environment runs untrusted code and egress is denied by default rather than blocklisted - That environments are snapshotted warm and restored, because installing at start costs everyone the same minute - That a limit breach suspends rather than destroys, since most breaches are an accidental loop - That forking excludes secret-bearing paths, or a shared template hands out the owner's credentials - That the abuse response path exists before launch, because free compute attracts mining within days
# Architecture · CodeSandbox ## Stack | Part | Choice | Why | | --- | --- | --- | | Isolation | One sandbox per environment with no shared kernel surface where possible | the boundary is the product | | Startup | Snapshot and restore rather than cold boot | a development environment that takes a minute to start is not used | | Filesystem | A layered image with a writable overlay per environment | shared base layers are what make hundreds of environments affordable | | Networking | Egress denied by default with declared allowances | a blocklist is always incomplete | | Runtime | TypeScript control plane with a container or microvm layer | the control plane is small; the isolation layer is the work | ## Modules Each module has one owner concern and a documented way to replace it. | Module | Owns | How to replace it | | --- | --- | --- | | Isolation | The boundary around untrusted code. | Any runtime, provided its escape history is understood rather than assumed away. | | Snapshots | Fast start from warm state. | Any mechanism, provided the cost is paid per template rather than per environment. | | Limits | Four ceilings with suspension. | Any enforcement, provided breach suspends rather than destroys. | | Persistence | The writable overlay and hibernation. | Any store, provided idle reclamation preserves the filesystem. | | Abuse | Detection, suspension and reporting. | Not swappable for a later addition. Free compute is abused within days. | ## Configuration Every runtime setting is an environment variable documented in `.env.example`, validated at startup, with a safe local default wherever one exists. - `DATABASE_URL` · required, secret · Control plane state. Never reachable from inside an environment. - `EGRESS_DEFAULT` · required · Present as a constant. A blocklist is always incomplete. - `CPU_MILLIS_LIMIT` · required · Per environment. Exceeding suspends rather than destroys. - `EGRESS_BYTES_PER_HOUR` · required · The limit that catches mining and outbound traffic first. - `HIBERNATE_AFTER_MINUTES` · required · Releases compute while preserving the filesystem. - `FORK_EXCLUDE_PATHS` · required · Secret-bearing paths, excluded so a shared template does not leak credentials. ## Production baseline - Security: least privilege, input validation at every boundary, secret redaction in logs, rate limits on abuse-prone paths, no invented security primitives. - Data: explicit schema and migrations, transactional writes where integrity matters, backup and restore procedures that have been exercised. - Integrations: adapters around third-party providers, idempotent webhook or job processing, bounded retries, timeouts. - Observability: structured logs with request or operation ids, an error-tracking hook, and health and readiness checks where a server exists. - Quality: unit tests for domain rules, integration tests at module boundaries, one end-to-end test of the critical path. ## Decision records For each dependency in the stack table, keep a short note: why it was chosen, its failure mode, and how it is replaced. Do not add infrastructure until a requirement in `PRODUCT.md` justifies it.
# Agent instructions · CodeSandbox product build - Read `PRODUCT.md` and `ARCHITECTURE.md` before changing code. The stack is fixed: One sandbox per environment with no shared kernel surface where possible, Snapshot and restore rather than cold boot, A layered image with a writable overlay per environment, Egress denied by default with declared allowances, TypeScript control plane with a container or microvm layer. - Implement milestone by milestone from `MILESTONES.md`; keep each change reviewable and leave the application runnable at every commit. - Treat authentication, payments, encryption, imports, webhooks and destructive actions as high-risk boundaries when present. - Never invent cryptography or silently weaken a requirement to make a check pass. - Put every external service behind an interface with a deterministic fake for tests. - Add migrations and rollback or recovery notes for every persistent data change. - Log useful operational context without credentials, tokens, passwords or personal data. - Update documentation and run every check before completing a milestone. ## Known traps - Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. - Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. - Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. - Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. - Forking an environment by copying its filesystem copies whatever the owner left in an environment file, so a shared template quietly hands out someone's credentials to everyone who forks it. Exclude secret-bearing paths from the fork and require the forker to supply their own.
# Delivery milestones · CodeSandbox Estimated effort: **multi-day** for the indie phases; the production-only milestones add the trust and operability layer. ## M1 · An environment that cannot see out Code inside a sandbox reaches nothing it was not given. ### Steps 1. Isolate with no ambient credentials Nothing in the environment belongs to the platform. Files: `src/sandbox/`, `tests/escape.test.ts` 2. Deny egress by default A blocklist is always incomplete and abuse finds the gap first. Files: `src/network.ts` 3. Test each escape route explicitly Host filesystem, control plane, neighbour environment. Files: `tests/escape.test.ts` ### Done when - [ ] A hostile environment cannot reach host, control plane or neighbours - [ ] Egress is denied by default - [ ] No platform credentials exist inside an environment - [ ] Escape attempts are logged usefully ### Watch out - Allowing egress by default and blocking known-bad destinations means the first abusive environment finds the destination you did not list, and outbound attack traffic from your address range is a problem that arrives as an abuse report. Deny by default and allow explicitly, which is the only version that holds. ## M2 · Starting fast enough to be used An environment is ready in a couple of seconds, not a minute. ### Steps 1. Snapshot warm, restore from it Installing dependencies at start costs every environment the same minute. Files: `src/snapshots.ts` 2. Share base layers A hundred environments from one template should not be a hundred copies. Files: `src/images.ts` 3. Measure to usable, not to created Created and usable are different moments and only one matters. Files: `src/metrics.ts` ### Done when - [ ] Warm template start is a couple of seconds to usable shell - [ ] Base layers are shared across environments - [ ] A template change invalidates its snapshot - [ ] Restore is identical to the snapshot ### Watch out - Installing dependencies at start means every environment pays the same minute, and a development environment that takes a minute to open is one people stop opening. Snapshot after the environment is warm and restore from that, so the cost is paid once per template. ## M3 · Limits that stop a runaway A loop consuming everything is contained and its owner keeps their work. ### Steps 1. Enforce four ceilings Processor, memory, disk and egress. Egress is the one people forget. Files: `src/limits.ts` 2. Suspend, do not destroy Most breaches are a loop, not abuse. The work should survive. Files: `src/suspend.ts` 3. Prove neighbour isolation under load A resource hog must not degrade anyone else. Files: `tests/noisy-neighbour.test.ts` ### Done when - [ ] All four limits suspend rather than destroy - [ ] The filesystem survives suspension - [ ] The owner is told which limit was hit - [ ] A resource hog does not degrade neighbours ### Watch out - Destroying an environment that breached a limit loses the owner's work, and the overwhelming majority of breaches are an accidental infinite loop rather than abuse. Suspend, preserve the filesystem, and say which limit was hit so the person can fix their code. ## M4 · Work that survives closing the tab An environment resumes with the changes you made. ### Steps 1. Persist the writable overlay It is the user's work and it is not in version control yet. Files: `src/overlay.ts` 2. Hibernate rather than destroy People leave tabs open for days assuming safety. Files: `src/hibernate.ts` 3. Survive a mid-write disconnection Browsers close, networks drop, and neither should corrupt anything. Files: `src/overlay.ts` ### Done when - [ ] Returning restores all changes - [ ] Idle environments hibernate and resume quickly - [ ] A mid-write disconnection does not corrupt - [ ] Storage per environment is visible and bounded ### Watch out - Reclaiming an idle environment by destroying it loses uncommitted work, and people leave tabs open for days assuming their changes are safe. Hibernate by persisting the overlay and releasing the compute, so resuming is fast and nothing is lost. ## M5 · Sharing, forking and abuse (production only) An environment can be shared safely and abuse is handled before it becomes your problem. ### Steps 1. Exclude secrets from forks A shared template otherwise hands out the owner's credentials. Files: `src/fork.ts`, `tests/fork-secrets.test.ts` 2. Expire shared links A link to a running environment is access to compute. Files: `src/sharing.ts` 3. Build the abuse path before launch Free compute attracts mining and outbound traffic within days. Files: `src/abuse.ts` ### Done when - [ ] Forking excludes planted credentials - [ ] Shared links carry access levels and expire - [ ] Abuse reports produce suspensions with evidence - [ ] Mining and scanning egress patterns are surfaced ### Watch out - Forking an environment by copying its filesystem copies whatever the owner left in an environment file, so a shared template quietly hands out someone's credentials to everyone who forks it. Exclude secret-bearing paths from the fork and require the forker to supply their own.
# Operations · CodeSandbox ## Backup User overlays are their unsaved work and are the thing they would be most upset to lose. Snapshots and base images regenerate. Back up overlays and treat everything else as rebuildable. ## Restore Restore and confirm suspended environments come back suspended rather than running, since restoring a suspended abusive environment to a running state resumes whatever it was doing. Do a restore drill before the first real user, and write the date here when it passes. ## Monitoring Egress volume per environment and processor saturation are the abuse signals, and they lead the abuse report rather than following it. Start-to-usable time is the product metric. ## Incident checklist Outbound attack traffic from your address range is the incident that costs you your hosting, and it arrives as an abuse report rather than an alert unless egress is monitored. The default-deny posture is what makes it rare rather than routine. 1. Contain the issue without destroying evidence or user data. 2. Record the timeline and affected scope. 3. Rotate exposed secrets and revoke compromised sessions or credentials. 4. Restore from a verified backup when needed. 5. Document the root cause, the remediation and the regression test. ## Release gate - [ ] Four hostile environments are confirmed contained - [ ] Egress is confirmed denied by default - [ ] A limit breach is confirmed to suspend with the filesystem intact - [ ] Returning is confirmed to restore all changes - [ ] Forking is confirmed to exclude planted credentials ## Launch constraint Do not market omitted CodeSandbox capabilities as implemented. The non-goals in `PRODUCT.md` remain user-visible limitations until they are deliberately delivered.
# Copy to .env and fill in. Never commit .env; this file documents it. # Required · secret. Control plane state. Never reachable from inside an environment. DATABASE_URL=postgres://localhost:5432/environments # Required. Present as a constant. A blocklist is always incomplete. EGRESS_DEFAULT=deny # Required. Per environment. Exceeding suspends rather than destroys. CPU_MILLIS_LIMIT=2000 # Required. The limit that catches mining and outbound traffic first. EGRESS_BYTES_PER_HOUR=1073741824 # Required. Releases compute while preserving the filesystem. HIBERNATE_AFTER_MINUTES=30 # Required. Secret-bearing paths, excluded so a shared template does not leak credentials. FORK_EXCLUDE_PATHS=./config/fork-exclude.txt
$ choose a build depth, inspect the files, then open the complete pack in your agent
They pay to avoid managing dev machines for experiments and previews.
xinstant templates
xcloud sandboxes
xpreview URLs
xcollaboration
xmanaged infrastructure
xintegration polish
Don't feel like building it? These folks already made it free.
all 3 free alternatives to CodeSandbox →· no votes, no pay-to-list · just what's real
Vibecode CodeSandbox
Kinda. The core of CodeSandbox is buildable in a weekend with the prompt on this page, but there are real gaps: instant templates, cloud sandboxes. Read the honest list above before committing.
How much does CodeSandbox cost?
CodeSandbox costs about $12/month (Pro, checked 2026-07-30), which is $144 per year.
What do I lose by replacing CodeSandbox?
Honestly: instant templates; cloud sandboxes; preview URLs; collaboration; managed infrastructure; integration polish. If any of those are load-bearing for you, keep paying.
Is there an open-source alternative to CodeSandbox?
Yes: code-server (VS Code in a browser; the cloud part is your server.) Coder (Full cloud workspaces on your infrastructure; Terraform and PostgreSQL come along for the ride.) Eclipse Che (A real browser IDE platform, assuming Kubernetes already counts as normal in your house.) All 3 curated free alternatives are at vibecodeit.com/codesandbox/alternatives. The prompt is for when you want it exactly your way.