# The Coding Workspace

A **Coding Workspace** is one project's execution environment: a persistent, isolated sandbox that lives as long as the project does. Every task the project ever runs happens inside it, each in its own git worktree.
**Not the same as a Workspace:** A **Workspace** with no qualifier is the tenant — your organization. A **Coding Workspace** is this: one project's sandbox. Two concepts, one word, and telling them apart is load-bearing when you read anything else in these docs.

## When this matters to you

- You want to know where untrusted, agent-generated code runs — it is never your machine and never the hlix backend.
- Two tasks edited the same file and you want to know why they did not corrupt each other.
- You need a shell inside a running project to debug something the logs will not tell you.
- You are budgeting, and want to know what an idle project costs.

## One sandbox, many worktrees

One persistent sandbox per project holds a single shared clone, and every task gets its own git worktree and branch **inside that same sandbox** — never a sandbox of its own.

```text
Project ──▶ ONE Coding Workspace  (named hlix-cw-<projectId>)
                  │
                  │   /workspace
                  ├──── project/repos/<repoId>/repo   the shared clone, ONE per repo
                  │
                  ├──── tasks/<taskA>/repo            git worktree · branch task-A
                  ├──── tasks/<taskB>/repo            git worktree · branch task-B
                  └──── tasks/<taskC>/repo            git worktree · branch task-C
```

Each `tasks/<taskId>/repo` is a git worktree of that one shared clone — not a second copy of the repository.

The shared clone is the project's durable working state. Each task gets an isolated checkout and its own branch off it, so concurrent tasks — in the same wave or in different cycles — never share a working tree. Task isolation is a worktree inside one sandbox, not a sandbox of its own.

The `repos/<repoId>/` level is what makes a project **multi-repo**, and it also makes the git lock per repository: two repos of one project serialize independently instead of queueing behind one project-wide lock. A project with no repository uses a fixed key, so its shared clone reads `project/repos/default/repo`.

## Why per project and not per task

| Choice | Consequence |
| --- | --- |
| One sandbox per **project** | Dependencies install once. The second task starts warm. Build caches, `node_modules`, and toolchains survive. |
| One worktree per **task** | Parallel tasks cannot see each other's edits. A failed task's mess is confined to its own directory. |
| Sandbox is **non-ephemeral** | The filesystem outlives every individual run, so a project's state accumulates instead of being rebuilt. |

The sandbox is reconnected by a stable name derived from the project id, so every acquire — across tasks, across backend instances — reaches the same sandbox.

## Who runs inside it

The worktree layout above is the same whichever [harness](/guides/connect-agents/) writes the code. What differs is where the coder's own process lives.

- **Hlix**, our own harness and the default, is driven from the backend against the workspace's command and filesystem tools. The backend provisions the worktree, the agent edits files in it, and the runner does the git work.
- **External coders** — Claude Code, Codex, Cursor Agent — are launched by a driver process *inside* the sandbox, which mints the worktree in place, runs the coder there, and commits.

Either way the work lands in `tasks/<taskId>/repo` on its own branch, and the pipeline that reviews it does not know or care which one produced it.

## Lifecycle and cost

An idle Coding Workspace **stops itself** after an idle interval (60 minutes by default). Stopping is not deleting: the filesystem persists and billing falls to roughly storage. The next task's start resumes it.

A project that goes quiet for long enough — 14 days by default — has its Coding Workspace destroyed by a maintenance sweep. Activity is re-validated immediately before each destroy, so a project that woke up in the meantime is left alone. The project's durable history is preserved separately, so a destroyed sandbox is recreated rather than lost.

## Secrets in the workspace

The platform writes your project's secrets into a root `.env` inside the sandbox, and three independent layers stop it from ever entering a commit:

1. `/.env` is pinned in the shared clone's git exclude file.
2. Staging is `git add -A` followed by an explicit reset of `.env` — never a pathspec that could silently fail.
3. The secret writer refuses to overwrite a `.env` that is already tracked.

Tokens are never passed through command environment variables either, because the sandbox provider inlines environment into the session command string — which means argv and persisted shell history. Credentials reach the sandbox through the filesystem instead. [Secrets & protected files](/security/secrets/) covers the full path.

## Opening a shell

`GET /v1/api/projects/:id/terminal` returns access to a **running** sandbox. It never cold-starts one — opening a tab should not cost you a sandbox boot.

```bash
curl -sS "$HLIX_BASE_URL/v1/api/projects/$PROJECT_ID/terminal" \
  -H "x-api-key: $HLIX_API_KEY" \
  -H "X-Organization-Id: $HLIX_WORKSPACE_ID"
```

Expected result when the sandbox is up:

```json
{
  "available": true,
  "webTerminalUrl": "https://…",
  "sshCommand": "ssh …",
  "expiresAt": "2026-08-07T10:14:22.481Z"
}
```

The web terminal URL is a signed preview link and is best-effort — the key is omitted if minting it fails, and `sshCommand` still works. SSH access is short-lived (15 minutes) and suits VS Code Remote-SSH, JetBrains Gateway, or `scp`.

When the sandbox is not reachable you get a reason instead of an error:

```json
{"available": false, "reason": "sandbox not running (state: stopped)"}
```

Terminal access requires the agency `manage` tier — every client collaborator is refused, because the sandbox holds the project's secrets.

## Local development

Setting `SANDBOX_RUNTIME=local` runs the coding agent on the host with a local filesystem root instead of a cloud sandbox. That is a development convenience only: the boot guard refuses it in a cloud deployment, where it would run agent-generated code inside the backend container with the backend's own credentials.

## Common questions

**Does every task get its own sandbox?** No — and this is the design decision the page exists to explain. One sandbox lives per *project*, for the project's whole life. Each task gets its own git worktree inside it. Per-task sandboxes would mean paying a cold boot and a fresh clone for every task.

**What happens to my files when the sandbox stops?** Nothing. An idle sandbox pauses itself; the filesystem persists and the next task resumes it. Billing while paused is storage, not compute.

**Can I get a shell into it?** Yes — `GET /v1/api/projects/:id/terminal` returns a signed web-terminal URL and an `ssh` command suitable for VS Code Remote-SSH, JetBrains Gateway, or `scp`. It never cold-starts a stopped sandbox, because opening a tab should not cost you a boot.

**Is my code ever executed on hlix's own infrastructure?** No. Agent-generated code runs in the project's sandbox. A boot guard refuses the local runtime in a cloud deployment specifically because it would run that code inside the backend container with the backend's credentials.

**What if the project has no Git remote?** It still works. Task branches are merged inside the Coding Workspace under a lock, the result is snapshotted and downloadable, and the full history is bundled for recovery. GitHub adds an external review surface; it is not where the work happens.

## If the workspace will not open

- `{"available": false, "reason": "sandbox not running (state: stopped)"}` — the project is idle and its sandbox has auto-stopped. Run a task; the next acquire resumes it. The terminal endpoint will not cold-start one on your behalf.
- `{"available": false, "reason": …}` naming an absent sandbox — the project has never run a task, so no sandbox exists yet.
- `403` on the terminal endpoint — terminal access needs the agency `manage` tier. Every client collaborator is refused, because the sandbox holds the project's secrets.
- **`webTerminalUrl` is missing but `sshCommand` is present** — minting the signed preview link failed. That is best-effort; use SSH.
- **The SSH command stops working after a few minutes** — it is short-lived by design (15 minutes). Request a new one.
- **A task fails on a driver-layout mismatch** — the project's sandbox is persistent and keeps the driver it was created with. A backend deploy cannot change that; recovery is deliberately manual.

## Where to go next

| If you want to… | Read |
| --- | --- |
| Understand who runs inside this sandbox | [Agents & orchestration](/concepts/agents/) |
| See how tasks map onto branches | [Work tree](/concepts/work-tree/) |
| Know what hlix does with your credentials | [Secrets & protected files](/security/secrets/) |
| Watch a task use it | [Tasks](/running/tasks/) |

## Next steps

[Work tree](/concepts/work-tree/)
  [Secrets & protected files](/security/secrets/)
  [Agents & orchestration](/concepts/agents/)
  [Environment discovery](/cli/environment-discovery/)