> dsh.works

Watch them work.
Take the keyboard.

dsh can already delegate to Claude Code and Codex — one task in, one sentence out. What it cannot do is let you see it happen. dsh-crew gives each crew member a real PTY in the session's workspace, streamed to a pane in the Web UI. The agent seats them and hands them work; you watch every keystroke of it, and you can type into any pane at any moment.

$ dsh plugin --profile web add @dshworks/dsh-crew
ChatTrajectoryCrew
seat + Claude Code + Codex + dsh
Claude Codepid 41207 · 90×34
> where does this repo refresh auth tokens?

 Read src/auth/session.ts (214 lines)
 Grep "refresh" — 6 files

 One place: session.ts:88, in ensureFresh().
  It refreshes inside 60s of expiry, and the
  interceptor already calls it.

  The retry path at :141 does not go through
  it. A 401 there refreshes a second time.

>  
Codexpid 41219 · 90×34
› where does this repo refresh auth tokens?

 src/auth/session.ts owns it. ensureFresh()
  swaps on a 60s skew; the interceptor calls it.

  Worth noting: refreshToken() is unguarded,
  so two requests racing an expiry both hit
  /oauth/token. The server rotates them, so the
  loser gets 400 invalid_grant and the session
  dies.

 
Send to all 2 panes… Send to all
One question, both crews, side by side — the broadcast line puts it in every live pane at once. Codex caught the race Claude did not. Rebuilt here in the page, so it wears your theme; the transcripts are the shape each product prints.

The two halves

The human half

A seat bar and one pane per agent. The pane is a real terminal — colour, cursor addressing, the product's own TUI — because the plugin carries the CLI's bytes instead of reimplementing its surface.

Type into it whenever you want. Interrupt with Ctrl-C. Or use the broadcast line and watch two agents answer the same question.

The agent half

Five tools, so the model in the centre column can run the team — and the delegation and the observation are the same terminal, not a task API beside a log.

Turn them off with tools: false and the split view still works, human-driven.

toolwhat it does
crew_listwho can be seated, who already is
crew_seatstarts a pane, returns its id and first screen
crew_sendtypes it, presses Enter, waits for quiet — or returns a job id
crew_peekthe screen right now, as the human sees it
crew_dismissends the process

Background delegation. crew_send(…, run_in_background: true) puts the wait on the harness's job seam instead of the calling turn: the call returns a job id, the model keeps working, and the completion notice wakes it with the answer. job_kill stops the watch and leaves the pane seated — a cancelled delegation is not a reason to close a terminal someone is watching.

What the shell could not tell us

The test suite seats bash, because a shell has a deterministic screen and no account. That is also its limit. Three corrections came only from running the real products, and each one had shipped green tests first.

Enter has to be its own keystroke

Claude Code and Codex both read one burst ending in a carriage return as a paste, and keep the return as a newline. So message + "\r" in a single write typed the task and submitted nothing — and the pane then went quiet, so a settle-on-quiet rule handed the model back its own unsent question as the answer.

Fixed by writing the message, pausing 250ms, then "\r" alone. bash submits either way and never saw it.

An unpainted screen is not a settled one

Claude Code draws its first frame after about 4.5 seconds and is perfectly quiet until then. Seating now waits for content and calm before it reports a crew member ready.

The first screen may be a dialog — and answering it is not ours to do

In a directory it has not been trusted in, each product opens on its own trust prompt rather than a composer. A task sent into a dialog is typed into the dialog, and its digits can pick an option: a "count from 1 to 12" prompt once chose 2. No, quit.

So the tools tell the caller to answer the dialog first — an empty message presses Enter — and send the task once the composer is up. Auto-answering a product's trust prompt is not a plugin's decision to make.

33tests, on real PTYs and real sockets
4more that seat the real claude and codex
0native dependencies

The opt-in suite runs behind CREW_REAL_CLI=1 and seats each product in a throwaway workspace, so answering a trust prompt in a test never marks a real project trusted. Last verified against claude 2.1.232 and codex 0.147.0 on 2026-08-17.

Install

$ dsh plugin --profile web add @dshworks/dsh-crew
$ dsh web

dsh plugin forwards to pnpm, so pnpm must be on PATH. A Crew tab appears beside Chat and Trajectory in the next session. Nothing else to configure: the seat bar shows every crew member it can find and disables the rest, with the reason on the button — a missing codex reads as codex is not on the host PATH, not a launch that fails a second later.

Adding a crew member is one row, never a package

# ~/.dsh/profiles/web/cordis.patch.yml - id: dsh-crew config: agents: - id: aider label: Aider command: aider accent: '#7c3aed'

A row whose id matches a built-in overrides that built-in field by field, so pointing claude at a wrapper script is one line. enabled: false removes one.

What it is not

A pane starts a real process on your machine, in the workspace of the dsh session that opened it. That is the feature, and it is also the risk: the two routes this plugin mounts are fenced on the Host authority and Sec-Fetch-Site, the control route requires application/json, and the WebSocket needs a single-use 30-second token. That fence answers "did this come from the dsh UI on this machine" — it is not authentication, and network reachability is still your webserver's bind policy.

Geometry is fixed at spawn, because the harness's subprocess seam allocates a PTY and exposes no resize; a pane shrinks its rendered grid to fit rather than reflowing under the agent. And if you only want the final sentence with no terminal at all, the harness's own subagent-claude-code provider is the smaller tool — this one exists for when you want to watch.

Not affiliated with DeepSeek, Anthropic, or OpenAI. Claude Code and Codex are their authors' products; dsh-crew only carries their bytes.