lazy documentationv0.91

Web shell

This page is for anyone reviewing tasks in the local daemon dashboard. The dashboard can open an interactive terminal inside a task's container, right from the browser. It is the same thing as running lazy shell <task> at the command line — a shell in the exact sandbox the task's agent worked in — so you can try the work by hand while you review.

The Shell tab (/tasks/:task/shell) is the home for terminals you open directly, plus Pair and Chat. Verification steps mount a terminal under the step, not in this tab; the tab lists those sessions and links to them. The tab is hidden when the task's runner has no container.

Sessions live in this browser document. Reload or leave the page and they close — there is no server-side registry. lazy shell <task> survives.

Opening a shell

On the Shell tab, + New opens a full-height terminal in the task's container. Bash is used when the container has it, otherwise sh. You land in the task's working directory (its worktree), with TERM=xterm-256color, so full-screen programs like vi, less and htop render correctly.

The tab also lists every session this page already has open — label, where it came from (a verification step, Services, opened here, Pair, Chat), and whether it is connected — with go to and close. A session renders in exactly one place; the list is an index, not a second terminal.

Maximise enlarges that same terminal as an overlay. The element never moves in the page, so focus and scrollback stay put.

Pair and Chat

Pair takes over the agent's session in the same terminal, with the same lock as lazy pair: unblock and accept refuse until you stop, and a dropped connection ends pairing within 30 seconds so the task cannot stay locked forever. Only one Pair session per task.

Chat opens a read-only conversation with the task's agent (lazy chat). It does not lock the task and does not change the task's agent, model, or effort. A working task's agent owns the session — Chat refuses then, with the same message as the CLI.

Both ride the same WebSocket as a plain shell, not a second exec path.

Copy and paste

The panel takes the shortcuts a terminal user expects:

Keyboard paste reads the system clipboard through the browser, so the first paste may raise a clipboard permission prompt — and a browser that refuses clipboard reads (or a page not served over localhost/HTTPS) pastes nothing from the keyboard. Right-click paste is unaffected either way.

Running a verification step

The Verify tab gives every shell command block a Run in shell button next to Copy. One click mounts a terminal directly under that step — labelled Verify 1, Verify 2, … in the order the runnable blocks appear — and runs the block there. A second click on a live step offers Open (jump to it) and Re-run (a fresh session) rather than stacking another terminal under the same step. Nothing is ever typed into a shell you were already using.

What goes in is exactly what Copy would have put on your clipboard: the $ prompt markers of a console block are stripped, multi-line blocks go in whole and run in order. Commands always run inside the task's container, the same place its agent worked.

The commands are the ones the agent wrote in its report, so you read them before they run — the block is rendered right below the button, and the terminal prints the lines again as it feeds them in. Nothing runs until you click: opening the page never executes anything. When the block finishes, the shell prints [lazy] exit status: N, so a step that failed quietly still says so — and the terminal stays open and interactive for whatever you want to try next.

Run is offered only for blocks that could be shell input (a json, toml or ts block has no Run), and is disabled with the same reason as the Shell tab when no shell can be opened. A stopped container is not one of those reasons — Run starts it, and says so in the terminal it opens.

If the connection drops, Reconnect opens a fresh shell (the previous one is gone; a terminal session does not survive the socket closing, and a reconnected session does not re-run its block). Closing the terminal, leaving the page, or typing exit ends the session.

Starting the container

The shell needs a running container, and opening one is how you ask for it: if the container is down, the panel starts it and shows the progress on its own status line — pulling or building the image included — then connects. Watch, Pair and Chat do the same. Two panels opened together share one start; they never race two containers for the same task.

If the start fails — Docker not running, an image that will not build — the panel shows the failure text and its Reconnect button becomes Start container, so you can retry once you have fixed the cause. That is the only place a Start button appears next to a terminal.

When a shell cannot be opened

Two things a start cannot fix, which the page says instead of failing silently:

What a shell can reach

The terminal is a docker exec into the task's own container — nothing more. It is not a shell on the machine running the daemon, and it cannot be pointed at another task's container: which container to enter is decided entirely by the daemon from the task's session, and the browser has no say in it. The only things the browser sends are your keystrokes and the terminal size.

When you close the terminal, the shell inside the container is torn down with it. Reload the page and every session is gone — the Shell tab says so in one line. lazy shell <task> is the one that survives.

Access and security

The shell is behind the same gate as every other dashboard page: a signed-in browser session, obtained by running lazy dashboard in the project (it opens your browser with a one-time login link that becomes a session cookie). No session, no shell — the terminal connection is refused before the daemon even looks at which task you asked for. Anyone signed in can already unblock, accept and edit tasks; a shell into the agent's own sandbox is in the same class.

On a managed (Lazy Teams) daemon the dashboard does not exist, and the shell answers 404 along with the rest of it.

See Serve ports for how the daemon binds and Surface asymmetries for why there is no agent-facing (MCP) version of this — a shell is a human tool.