Skip to content

Run Devin Outposts on Daytona

View as Markdown

Set up Devin Outposts so that every Devin session in your org does its work inside a Daytona sandbox you own.

A Devin session is one task handed to Devin: fix this bug, upgrade this dependency, chase down this flaky test. You open the session from the Devin app or from Slack, describe the task, and Devin works on it while you follow its progress, answer questions, and course-correct.

A session runs across two components. The agent loop handles planning, model calls, tool selection, and the conversation you see, and it runs on Cognition’s side in every deployment model. The session machine is an environment with a shell, an editor, a browser, and Devin’s tooling installed; every tool call the agent loop issues executes there. In a standard session Cognition hosts the machine as well.

Outposts puts the session machine on compute you choose. You register an outpost with Cognition, and sessions created on that outpost are served by machines you operate. The agent loop stays hosted by Cognition, the session in the Devin app looks and behaves the same, and nobody creating sessions has to know anything changed. What moves is execution: shell commands, checked-out repositories, and browser automation now run on your infrastructure.

In this setup the machines are Daytona sandboxes. Each session gets its own, created on demand from a snapshot you define, stopped while the session sleeps, and deleted when the session ends.

  • Cognition hosts the Devin API, the agent loop, the outpost gateway, and a queue per outpost of sessions waiting for a machine.
  • An orchestrator, which you run, watches that queue, claims sessions for your outpost, and manages one sandbox per session.
  • Daytona hosts the sandboxes.

The flow for a new session: someone picks your outpost when creating it, the session lands in the outpost’s queue, and the orchestrator claims it. The orchestrator creates a sandbox from your snapshot and launches Cognition’s devin-remote binary inside: the sandbox downloads the exact build pinned for the session, verifies its checksum, and starts it, and the remote establishes an outbound WebSocket connection to the outpost gateway. All traffic between the agent loop and the machine flows through that tunnel, so a sandbox needs outbound HTTPS and nothing more. No inbound connectivity is required.

From there, session state drives sandbox state:

  • Active session: the sandbox runs and the worker serves it.
  • Session sleeps: the orchestrator releases its claim and stops the sandbox. The filesystem stays.
  • Session wakes: the orchestrator claims it again and starts the same sandbox. Repositories, branches, and half-finished work are where Devin left them.
  • Session terminated: the sandbox is deleted.

The orchestrator, the queue client, and the snapshot builders are published as a reference implementation in the Daytona guides repo under python/cognition/devin-outposts/. Clone it and install:

Terminal window
git clone https://github.com/daytona/guides.git
cd guides/python/cognition/devin-outposts
python3.12 -m venv .venv
source .venv/bin/activate
pip install -e .
cp .env.example .env

You will fill in the remaining Daytona settings in .env after connecting Devin.

Run the connection command on the same machine as your browser:

Terminal window
outposts-connect --platform linux

The command opens Devin’s connection page. A Devin organization administrator with permission to manage enterprise settings and service users confirms the outpost and clicks Connect. The browser returns a one-time code to a temporary listener on http://localhost:8765/callback; outposts-connect exchanges it with Devin and writes DEVIN_OUTPOSTS_TOKEN, DEVIN_API_URL, and OUTPOST_ID to this project’s .env. The listener exits when the attempt finishes, and the machine token never passes through the browser.

For a Windows outpost, the flow is identical:

Terminal window
outposts-connect --platform windows

To serve Linux and Windows outposts at the same time, run one orchestrator per outpost, each from its own checkout with its own .env.

The command and browser must run on the same machine because the callback uses localhost. For a headless or remote orchestrator host, run the connection on a workstation and transfer .env securely, or use manual setup.

The connection creates an outpost and a service user with a machine-serving token. The outpost appears in Devin under Settings and in the environment picker whenever someone in your org creates a session.

If the connection flow is unavailable, install the Devin CLI and use separate tokens for outpost creation and machine serving:

TokenScopeUsed for
Outpost-create tokenaccount.outposts.orchestratorOne-time outpost creation with devin worker outpost create. Remove it from your shell after the outpost exists.
DEVIN_OUTPOSTS_TOKENaccount.outposts.machineQueue list, watch, claim, and release. Sandboxes never receive this token; each remote gets its claim’s connect token.
Terminal window
export DEVIN_API_URL="https://api.devin.ai"
export DEVIN_OUTPOST_CREATE_TOKEN="replace-with-outpost-create-token"
devin worker outpost create daytona-linux \
--platform linux \
--description "Daytona Linux sandboxes for Devin Outposts" \
--api-url "$DEVIN_API_URL" \
--token "$DEVIN_OUTPOST_CREATE_TOKEN"

For Windows sandboxes, create a separate outpost with --platform windows. Each outpost serves one platform and runs under its own orchestrator process.

Set DEVIN_API_URL to the API base only, for example https://api.devin.ai; the queue client appends its own path segments. Copy the returned outpost ID into OUTPOST_ID in .env, and set DEVIN_OUTPOSTS_TOKEN to the machine-serving token.

Sandboxes are created from a snapshot, so build that next. You need a Daytona API key that can create snapshots and manage sandboxes; put it in DAYTONA_API_KEY in .env.

devin_outposts/Dockerfile.default defines what every Linux session machine starts with. It builds on Daytona’s standard sandbox image, which already carries Chromium and ffmpeg for Devin’s browser and screen tooling, and it adds the GitHub CLI and the directories the Devin remote expects. Build and publish it with:

Terminal window
set -a
. ./.env
set +a
build-devin-outposts-snapshot

Snapshot names are derived from the Dockerfile contents, devin-outposts-default-<sha8>, which makes the script safe to rerun: with an unchanged Dockerfile it finds the existing snapshot and stops. When sessions need extra runtimes or internal tools, add them to devin_outposts/Dockerfile.default and run the build again. Either way, copy the printed snapshot name into SNAPSHOT_NAME in .env.

The snapshot allocates 2 vCPU, 8 GiB of memory, and 10 GiB of disk to every sandbox created from it, and each concurrently served session runs one sandbox. If sandbox creation fails with a quota error, check your organization’s tier limits and lower MAX_CONCURRENT_SESSIONS or the resource values in the builder.

Windows outposts use their own snapshot builder, build-devin-outposts-windows-snapshot; see the reference implementation’s README for the Windows setup.

With DEVIN_OUTPOSTS_TOKEN, DEVIN_API_URL, DAYTONA_API_KEY, OUTPOST_ID, and SNAPSHOT_NAME filled in, start it:

Terminal window
set -a
. ./.env
set +a
devin-outposts-orchestrator

Create a Devin session and pick your outpost in the environment picker. For each session it claims, the orchestrator will:

  1. Take the queue entry under its acceptor ID, so no other orchestrator instance grabs the same session.
  2. Create a sandbox named devin-<session_id> from SNAPSHOT_NAME, or restart the existing one when the session is waking from sleep.
  3. Clone any repositories listed in REPOS into the directory Devin expects, so its repository tooling finds them immediately.
  4. Download and checksum-verify the session’s pinned devin-remote binary in the sandbox, launch it, then supervise both the remote process and the queue entry.
  5. Release the claim and stop the sandbox when the session sleeps; delete the sandbox when the session terminates.

A janitor loop runs alongside. It selects sandboxes in your workspace by their devin.outpost_id label and removes any whose session no longer exists, so a crashed run cannot leak sandboxes.

The orchestrator itself runs anywhere with outbound HTTPS: a laptop, a VM, a container. Its state, the queue cursor and generated acceptor ID, lives in STATE_DIR and survives restarts. Restarting mid-session is safe; on startup it re-attaches to every queue entry claimed under its acceptor ID.

VariableRequiredNotes
DEVIN_OUTPOSTS_TOKENYesService-user key with the account.outposts.machine scope, written by outposts-connect or supplied during manual setup. Sent as a bearer token to the queue API. Sandboxes never receive it; each remote gets only its claim’s connect token.
DEVIN_API_URLYesDevin API base, for example https://api.devin.ai.
DAYTONA_API_KEYYesUsed by the Daytona SDK for snapshot creation and sandbox lifecycle calls.
OUTPOST_IDYesThe outpost ID written by outposts-connect or returned by manual outpost creation. Run one orchestrator process per outpost.
SNAPSHOT_NAMEYesSnapshot used to create serving sandboxes.
MAX_CONCURRENT_SESSIONSNoDefault 5. The orchestrator does not claim more sessions than this at once.
ACCEPTOR_IDNoLeave blank for a generated ID that persists in STATE_DIR. Do not share one acceptor ID across instances.
STATE_DIRNoStores the watch cursor and generated acceptor ID. Default is ~/.devin-outposts-orchestrator.
WORKDIRNoLinux sandbox working directory for repository clones and the remote launch. Default is /home/daytona/workspace.
REPOSNoComma-separated clone URLs to pre-clone into each sandbox.
GIT_USERNAMENoOptional username for private repositories in REPOS.
GIT_TOKENNoOptional token for private repositories in REPOS. Keep it local.
DEVIN_CHROME_PATHNoBrowser path inside Linux sandboxes. Default is /usr/bin/chromium.
WINDOWS_WORKDIRNoWindows outposts only: sandbox working directory. Default is C:\repos.
DEVIN_WINDOWS_CHROME_PATHNoWindows outposts only: browser path inside the sandbox. Default is C:\Program Files\Google\Chrome\Application\chrome.exe.

Use REPOS when Devin should find repositories already checked out at the start of a session:

Terminal window
REPOS=https://github.com/example/private-app.git,https://github.com/example/shared-lib.git
GIT_USERNAME=replace-with-git-username
GIT_TOKEN=replace-with-git-token

The orchestrator clones these with sandbox.git.clone() before the worker starts. On resume, existing clones are left untouched, so branches and uncommitted changes survive sleep. Treat GIT_TOKEN like any other secret and keep it in your local environment only.

  • Sleeping sessions are cheap. A session that sleeps costs you a stopped sandbox rather than a running machine, and it wakes with its filesystem intact.
  • Sessions cannot see each other. Each one works in its own sandbox, and termination deletes the whole machine.
  • You can look inside while Devin works. The sandbox appears in your Daytona dashboard under the session’s name; exec into it, follow Devin’s browser through the sandbox VNC view, or attach the observability you already use.
  • The machine image is under your control. Whatever you bake into the snapshot, every session starts with.