Skip to main content
Every Build and Captain run happens in an isolated VM. Setup defines how Capy prepares and maintains that VM: which branches to use, which scripts run automatically, which commands agents can invoke, and how much compute the VM receives. Configure it at Settings → Project → Dev environment.
Review runs use a separate, fixed environment: a Medium VM with only the pull request checkout. Project Setup scripts, Commands, tool hooks, environment variables, VM size, and Snapshots do not apply to Review.

Let Captain manage it

You do not have to write Setup by hand. Captain inspects your repositories and configures the environment for you.
1

Start from settings or chat

Open Settings → Project → Dev environment and click Set up with Captain — or tell Captain in any thread: “Set up this project’s dev environment.”
2

Captain writes and saves Setup

Captain reads package manifests, lockfiles, READMEs, and agent instructions for every attached repository. It chooses lifecycle scripts, useful commands, and a fitting VM size, then saves Setup for future runs.
3

Captain validates it

Captain starts a fresh validation run, exercises the configured environment, and fixes Setup if anything fails.
Already have Setup? Improve with Captain reviews it against the current state of your repositories. Saved changes apply to future runs immediately. The History section records changes made by people and Captain.

Manual setup

Open a repository from Setup & commands to edit its base branch, lifecycle scripts, per-script timeouts, and named Commands. Tool hooks and VM size are configured on the main Dev environment page. The equivalent Setup object looks like this:
{
  "vmSize": "medium",
  "repositories": [
    {
      "repository": "acme/app",
      "branch": "main",
      "scripts": {
        "initialize": "pnpm install --frozen-lockfile",
        "updateAfterCheckout": "pnpm install --frozen-lockfile",
        "startup": "nohup pnpm dev >/tmp/dev.log 2>&1 &"
      },
      "timeouts": {
        "initialize": 900,
        "updateAfterCheckout": 300,
        "startup": 300
      },
      "commands": [
        { "name": "Check", "command": "pnpm check" },
        { "name": "Test", "command": "pnpm test" }
      ]
    }
  ]
}
Scripts are optional. Leave a script empty when that lifecycle phase has no work to do.

What Setup defines

SectionWhat it controls
VM sizeCompute resources allocated to Build and Captain runs
RepositoriesPer-repo base branch, lifecycle scripts, and named commands
Tool hooksOptional commands that run before/after agent tool calls
Environment variables and Snapshots are configured alongside Setup and are covered below.

Mental model

ConceptWhat it is
SetupThe source of truth for branches, scripts, Commands, hooks, and VM size
Run preparationThe lifecycle Capy selects for each repository before the agent works
SnapshotAn optional cached VM produced from Setup to avoid repeating Initialize
Setup is always authoritative. Snapshots cache its results; they do not replace it. Run preparation reconciles whichever VM Capy obtains with the active Setup and requested checkout.

How a run becomes ready

Before the agent starts working, Capy:
  1. Allocates a new VM, restores a snapshot, or resumes the thread’s existing VM.
  2. Loads shared project environment variables. When a VM is prepared for a run you start, your personal variables are layered afterward and override shared variables with the same name.
  3. Refreshes GitHub credentials and attaches each repository at the requested branch and commit.
  4. Selects the required Setup path for each repository based on the VM’s saved state, active Setup revision, and current checkout.
  5. Runs the selected scripts. A Build agent becomes ready only after every blocking script succeeds.
Shared environment variables and credentials are refreshed after restoring or resuming cached VM state. A snapshot is never the authority for those values.

Lifecycle scripts

Each repository has three automatic scripts:
ScriptPurposeDefault timeout
InitializePrepare a repository on a new VM, after cloning and environment setup15 min
Update after checkoutMaintain dependencies after a reused environment moves to new code5 min
StartupStart services required for the run after repository preparation5 min
The path is selected per repository:
Environment stateAutomatic scripts
New VM or repository not previously preparedInitialize → Startup
Existing VM after Setup changesInitialize → Startup
Existing VM after its requested branch or commit changesUpdate after checkout → Startup
Existing VM with the same Setup revision and checkoutStartup
Snapshot buildInitialize, then capture
Run restored from a snapshot with a changed checkoutUpdate after checkout → Startup
Run restored from a snapshot with the captured checkoutStartup
The same phase runs across independent repositories in parallel, but phases remain ordered: all selected Initialize work finishes before Startup begins.

Initialize

Use Initialize for work needed to make a clean repository usable:
  • Install language runtimes, system packages, and global tools
  • Authenticate a private package registry before the first dependency fetch
  • Install project dependencies
  • Compile native dependencies or generate required artifacts
Initialize runs from the repository directory with environment variables loaded. It also runs while building a snapshot. It does not run again on every unchanged resume.
Initialize example
node scripts/setup-npm-auth.js && pnpm install --frozen-lockfile
If dependency installation requires authentication, bootstrap credentials explicitly before invoking the package manager. A package-manager preinstall hook cannot authenticate the dependency fetch that must happen before the hook is available.

Update after checkout

Update after checkout is the maintenance phase. It repairs a prepared VM after Capy checks out a different branch or commit. Keep it fast and safe to rerun:
  • Synchronize dependencies from the current lockfile
  • Regenerate code derived from the checkout
  • Apply local, idempotent schema preparation needed by the development stack
  • Refresh repository-scoped configuration
Update after checkout example
pnpm install --frozen-lockfile
Capy records the repository, requested branch, resolved commit, Setup revision, and whether maintenance completed successfully. It skips Update after checkout when those inputs still match the last successful preparation. A changed checkout or an unsuccessful previous preparation causes it to run again. Do not duplicate an expensive bootstrap in both Initialize and Update after checkout unless both clean and reused environments genuinely require it.

Startup

Startup runs after the selected preparation phase whenever the run needs its services started. Use it for development servers, local databases, and other processes that must be available while the agent works. Startup is blocking, so the script itself must exit. Launch long-running processes in the background and wait until they are ready:
Startup example
nohup pnpm dev >/tmp/dev.log 2>&1 &
for attempt in {1..30}; do
  curl -fsS http://127.0.0.1:3000 >/dev/null && exit 0
  sleep 1
done
exit 1
Startup runs again when an existing VM resumes. Make the script idempotent: reuse a healthy service or replace stale processes instead of starting duplicates.

Execution and failures

Scripts run:
  • From the corresponding repository directory
  • In Bash with set -e
  • With shared and applicable personal environment variables loaded
  • With root access inside the isolated VM
  • With configurable timeouts from 60 to 3600 seconds
An exit code other than zero, a timeout, or a transport failure fails the phase. Build runs stop before the agent starts and show Setup failed. Captain threads receive the failure and continue in a degraded environment so Captain can inspect and repair Setup. The VM status menu shows live and most recently recorded Setup steps, including the repository, phase, duration, and result.

Multiple repositories

All repositories in a run share one VM but have separate working directories. Within a lifecycle phase, their scripts execute in parallel. The next phase starts only after the current phase succeeds for every configured repository. Avoid scripts that depend on another repository finishing first. If repositories need the same global tool or system package, make the installation idempotent and safe under concurrent execution. Repository-specific dependency work should stay in that repository’s script.

Commands

Commands are named, opt-in actions agents can run while working — build, test, lint, typecheck. They never run automatically during Setup; agents invoke them when relevant.
NameCommand
Type checkpnpm check-types
Testpnpm vitest run
Buildpnpm build
Keep Commands executable and specific. Prose guidance (“always run lint before committing”) belongs in agent instructions, not Commands.

Tool hooks

Setup can define commands that run before or after specific agent tools. Tool hooks are useful for policy checks and lightweight automatic formatting:
{
  "pre": {
    "bash_run": ["echo 'About to run command'"]
  },
  "post": {
    "edit": ["pnpm prettier --write ${file_path}"],
    "write": ["pnpm prettier --write ${file_path}"]
  }
}
Available tools: bash_run, edit, multi_edit, write, read, glob, grep.

VM size

SizeCPURAMDiskCost/hour
Small2 cores4 GB20 GB$0.30
Medium4 cores8 GB30 GB$0.60
Large8 cores16 GB40 GB$1.20
Ultra16 cores32 GB50 GB$2.40
Hyper16 cores64 GB50 GB$3.00
Small is the default and works for most tasks. Use larger sizes for heavy builds, large test suites, or resource-intensive compilation. Changes apply to the next run.

Environment variables

Configure variables at Settings → Project → Environment variables:
  • Shared variables are available to every project run.
  • Personal variables are available only in project runs you start. A personal value overrides a shared variable with the same name.
Shared variables are available during snapshot builds. Personal variables are not stored in snapshots; Capy injects them when preparing the VM for your run. When a VM resumes, Capy refreshes shared project variables before lifecycle scripts execute. You can add key-value pairs directly or paste a full .env file.
Environment variables are available to the agent during task execution. Only provide secrets you’re comfortable sharing with the agent. Never put secret values inside Setup scripts — reference them as variables instead.

Snapshots

Environment Snapshots are currently available to select Enterprise customers. Contact us to request access for your organization.
Snapshots cache a prepared VM so later runs can avoid repeating Initialize. Enabling Snapshots requires a saved Setup. A snapshot build:
  1. Starts a clean VM at the configured size.
  2. Injects shared project environment variables and GitHub credentials.
  3. Clones each configured repository at its base branch.
  4. Runs Initialize for each repository.
  5. Removes platform-managed environment files, credentials, session tokens, and transient runtime state before capturing the VM.
Capy removes platform-managed secret files before capture, but it cannot know every path your scripts write. If Initialize writes a secret into another file, that file can persist in the snapshot. Keep credentials in environment variables and avoid writing secret values to disk.
When a run restores that snapshot, Capy injects current credentials and environment variables, checks out the requested code, runs Update after checkout only where the captured checkout no longer matches, and then runs Startup. From the Snapshots section of the Dev environment page you can:
  • Enable Snapshots — reuse a matching current snapshot, start the first build immediately, or queue it behind a build already in progress.
  • Set the rebuild schedule — snapshots refresh automatically every 1, 2, 4, or 8 hours to keep dependencies current.
  • Trigger a build manually — rebuild on demand after changing Setup.
  • Test a snapshot — run the full capture, restore, and warm-up lifecycle without promoting the result.
  • Inspect build history — every build has logs and status (ready, building, stale, or failed).
Snapshot builds are triggered by enabling Snapshots, a manual rebuild, a snapshot test, or the configured 1, 2, 4, or 8 hour refresh schedule. Saving Setup does not block on a snapshot build; rebuild after a Setup change when you want new runs to use the updated cached state.
StatusMeaning
BuildingA new snapshot is being prepared
ReadyA current snapshot is available for new runs
StaleThe cached artifact no longer matches the required environment
FailedThe latest build failed; inspect its step logs
Snapshots are an optimization, never a requirement: Setup stays the source of truth, and if no current snapshot is available a run falls back to fresh provisioning with the same Setup.

Troubleshooting

Initialize fails

Inspect the failing repository and phase in the VM status menu, then open that repository’s Setup to inspect the configured command. For snapshot builds, inspect the build logs. Common causes are missing package-manager authentication, an interactive installer, an unavailable system package, or a timeout.

Update after checkout fails

Run the command against the checked-out branch and current lockfile. Maintenance must be safe to repeat after a failed attempt. Prefer incremental dependency repair over deleting and rebuilding the entire environment.

Startup times out

The Startup script must return. Background long-running processes, add a bounded readiness check, and fail clearly when the service never becomes healthy. Also make Startup idempotent so a resumed VM does not accumulate duplicate servers.

A snapshot build fails

Open the build from Settings → Project → Dev environment → Build history and inspect the first failed step. Fix Setup, use Test snapshot to exercise the capture and restore lifecycle without promotion, then rebuild.

Iterate with Captain

Click Improve with Captain or ask Captain to inspect the failure. Captain can read Setup, the repositories, and build state, save a correction, and start a fresh validation run.

Migrating from .capy/settings.json

Repository hooks in .capy/settings.json are deprecated. Once any Setup exists for the project, those hooks are ignored. Carry over any setup commands and tool hooks you still need before saving; Captain detects and migrates them when it configures the project. The Dev environment page shows whether Setup, deprecated repository hooks, or default behavior is currently authoritative.

Manage via API

Everything on this page is also scriptable: read and save Setup with GET /setup and PATCH /setup, and control snapshot state through the Snapshots API. See the Setup API overview for the full object shape.