Tutorial

Work in your project's dev container

A lot of repositories already say what they need to be built in — a devcontainer.json naming an image, a user, some mounts. Sinclair reads it, so a terminal in that project can be a terminal inside that environment rather than one beside it. This walkthrough opens a shell in a project's dev container, shares the container your editor already has running, and writes a devcontainer.json that works for people and coding agents alike.

Sinclair needs Docker or Podman and nothing else. It does not need VS Code or the devcontainer CLI installed, and it never requires a project to have a devcontainer.json — without one it builds its own environment. The file is an input, not a dependency. See Share one container with your agents for the no-devcontainer path.

1. Open a shell inside it

From a pane in the project, open File ▸ Sandbox and pick Use Sandbox for This Project, then Open Shell in Sandbox. Sinclair reads the project's devcontainer.json, brings a container up from it, and gives you an ordinary tab whose shell is inside.

Config files are looked for in the order the Dev Containers tooling uses:

.devcontainer/devcontainer.json
.devcontainer.json
.devcontainer/devcontainer.jsonc

Comments and trailing commas are fine — the file is parsed as JSONC, the same way Sinclair parses its own settings.

2. What Sinclair takes from the file

Only the fields that change how a container is created or entered. Anything else in your devcontainer.json is ignored rather than guessed at.

FieldWhat it does here
imageBecomes the base of the image Sinclair builds, so your agents get the project's toolchain plus the agent CLI on top.
containerEnv, remoteEnvMerged into the container's environment. Your own sandbox-env wins on conflicts.
mountsApplied, in the engine's type=bind,source=…,target=… form. An entry that doesn't parse becomes a note, not a failure.
remoteUser / containerUserThe user the container runs as, unless sandbox-user says otherwise.
shutdownActionRead to warn you — see step 4.
workspaceFolder, workspaceMountRead only to detect whether the project is mounted at its own path — see step 3.

The ${localWorkspaceFolder}, ${localWorkspaceFolderBasename}, ${containerWorkspaceFolder}, and ${containerWorkspaceFolderBasename} variables all resolve.

Not used: features, customizations, forwardPorts, and postCreateCommand belong to the Dev Containers tooling, and runArgs is left alone rather than passing arbitrary engine flags through. A build.dockerfile is not built for you — point sandbox-image at the image it produces and Sinclair uses it as-is.

3. One thing worth changing: mount at your own path

By default the Dev Containers convention mounts your repo at /workspaces/<name>. That is fine for a person, and awkward for a coding agent: git records absolute paths when it creates a worktree, so a worktree made inside the container has a .git pointer that resolves nowhere on the host, and one made on the host resolves nowhere inside.

Two spec-legal lines make the container path equal the host path, and the whole problem disappears:

// .devcontainer/devcontainer.json
{
  "workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind",
  "workspaceFolder": "${localWorkspaceFolder}"
}

When Sinclair creates the container itself it does this anyway. The lines matter for the container your editor creates, so both tools agree.

4. Don't let closing the editor kill a working team

shutdownAction defaults to stopContainer: close your editor window and the container stops. If a team of agents is working in that container, they stop with it, mid-task.

{
  "shutdownAction": "none"
}

Sinclair reads this field and says so in the Containers panel when it isn't none, so you find out before it costs you a run rather than after.

5. Sharing one container with your editor

Sinclair looks before it creates. If a container is already running for this folder — one VS Code's Dev Containers extension built, or one devcontainer up started — Sinclair enters that one instead of building a parallel environment beside it.

It also never stops or removes a container it did not create. Your editor is very likely attached to it, and Stop Sandbox pulling the floor out from under your editor session would be a bad surprise. The Containers panel tells you when the sandbox is one Sinclair adopted.

Discovery keys on the label the Dev Containers tooling stamps with the host workspace path:

docker ps -a --filter label=devcontainer.local_folder=$PWD

Sinclair stamps that same label on the containers it creates, so it works in both directions: open the project in VS Code afterwards and Reopen in Container finds the one already running rather than building a second.

6. If the project has no devcontainer.json

Nothing degrades. Sinclair generates a small image itself — a Debian base plus git, node, and your agent CLI — and builds it locally on first use. If you'd rather write a dev container the whole team shares, this is a reasonable starting point that works for people and agents:

// .devcontainer/devcontainer.json
{
  "name": "api",
  "image": "mcr.microsoft.com/devcontainers/javascript-node:22",

  // Same path inside and out, so git worktrees stay valid on both sides.
  "workspaceMount": "source=${localWorkspaceFolder},target=${localWorkspaceFolder},type=bind",
  "workspaceFolder": "${localWorkspaceFolder}",

  // Closing your editor shouldn't stop a container with agents working in it.
  "shutdownAction": "none",

  "remoteUser": "node",
  "containerEnv": { "DATABASE_URL": "postgres://host.docker.internal/dev" },
  "mounts": ["type=volume,source=api-node-modules,target=${containerWorkspaceFolder}/node_modules"]
}

Sinclair layers the agent CLI onto that image, so you do not need to install claude in it yourself.

Careful

Don't mount /var/run/docker.sock. It's a common dev container convenience and a one-line container escape — it hands anything in the container root on your host, which matters a great deal once agents are running there with their permission prompts turned off.

7. Turning it off

To ignore a project's devcontainer.json and let Sinclair build its own environment:

{
  "sandbox-devcontainer": false
}

The rest of the sandbox — mounts, environment, resource ceilings, the image — is configured the same way either way. Every key is in the settings reference.

Where next