Anything where dsh web runs. No other dependencies — the plugin itself has zero runtime dependencies.
dsh plugin --profile web add dsh-abyss
dsh webOpen http://127.0.0.1:3080 — a dock appears in the bottom-right corner:
🐋🐙 empty
Abyss
Click it to open the panel. That is the whole install — no configuration.
To remove:
dsh plugin --profile web remove dsh-abyss, effective after a restart.
Run a normal task, for example:
Delegate with subagent: have the child run `ls | wc -l` and report the count, then relay it.
Watch the panel:
| What you see | The logged event behind it |
|---|---|
| the lead's card appears, "thinking" | turn/start |
| it turns "delegating · subagent", a bubble carries the brief | tool/call subagent |
| a new colleague arrives as a different sea creature | subagent/descriptor |
| they turn "terminal · bash" | tool/call bash |
| their report appears in a bubble, verbatim | tool/call report |
| the card fades and reads "left" | turn/end (a one-shot child) |
| tokens and spend climb live | assistant/message.usage |
Every line in a bubble is text from the log, never a template.
Each card is one agent session:
- Avatar: hue hashed from the session id, so two colleagues from the same vendor are still distinguishable; the lead is always the whale, everyone else draws from a pool of seven sea creatures.
- Corner dot: the firm (DeepSeek / Claude Code / Codex / ACP / SDK).
- Activity line: thinking / terminal / reading / writing / browsing / delegating / messaging / archiving…
- Chips: firm, staff-vs-temp, model, preset, delegation depth.
- Thin bar: context load — drawn only when the route advertised a window.
- Badges: ⚠ failures, ↻ retries, ⏳ waiting on you (with elapsed), 🗄 compactions.
Click a card for the dossier: every fact, the reporting line (clickable both ways), their own task list, and every scene they took part in.
Oldest first, one line per event: assigned, messaged, reported, said, blocked, waiting, decided, retry, failed, archived, left.
Beyond 80 lines it folds, with one control to bring back the earlier ones. New lines only auto-follow while you are already at the bottom.
Eight numbers, rolled up over the whole session tree:
| Metric | Meaning |
|---|---|
| Spend | money, from your price table |
| Tokens | input + output + reasoning + cache reads |
| Tool calls | every tool/call in the case |
| Failures | tool calls that actually errored (a non-zero shell exit is not one — dsh reports it as ordinary output) |
| Retries | provider retries |
| Compactions | context compactions |
| Blocked | total time waiting on a human decision |
| Elapsed | first arrival to last activity |
Below that:
- Context load:
held / windowper member, amber at 70%, red at 90%. A route that never advertised a window gets no gauge — inventing a denominator invents an alarm. - Attendance: one lane per member; a shift is an open turn.
And below that, past cases — the logs on disk are the archive.
The delegation tree, grown from real parent/child sessions: SessionHeader.parentSession and delegationDepth, stamped by the harness rather than guessed.
In Stats, click "Export write-up" on any case. The host rebuilds the whole case from the logs on disk and returns Markdown:
# Five agents researching game logic
- Case: `session-9af1dd1b-…`
- Started: 2026-08-15 21:19 · Last activity: 2026-08-15 21:22
- Elapsed: 2m 45s
- Staff: 6 (1 still on)
- Spend: $0.0903 over 312,000 tokens
- Tool calls: 72 · failures: 0 · provider retries: 0
## Staff
| Member | Firm | Depth | Tools | Fails | Tokens | Spend | Blocked |
…
## Transcript
- `21:19:59` **assign** … → …: …Readable in the panel; "Copy" puts it on the clipboard (if the browser blocks that, it selects the text and says so).
"Past cases" at the bottom of Stats lists every case on disk. Each one offers:
- Replay — the whole performance from its first assignment, pausable and restartable, paced by the compressed real gaps.
- Export write-up — as above.
That is the payoff of an event-sourced runtime: the panel did not need to be open; the log is the complete record.
Add config in the profile's cordis.yml. Prices and currency are what people change:
- id: dsh-abyss
config:
currency: "$"
prices:
deepseek-v4-pro: { input: 0.55, output: 2.19, cacheRead: 0.07 }Restart dsh web. A mistake here fails loudly at startup rather than silently falling back.
The panel is empty. The current session has no events yet. Start a task, or switch the scope to "All". Opening an older session rebuilds its office from disk automatically.
The panel covers the composer. Drag it by its header (the position is remembered), double-click the header to send it back, or drag the bottom-right corner to resize.
No context load in Stats.
That model route never advertised a contextWindow. Drawing nothing is deliberate — see above.
The report says "N member logs could not be read". Those sessions' logs are corrupt (dsh's persistence refuses them, e.g. a seq gap). The numbers exclude them, and that line is there so you do not read them as complete.
Does any of my data leave the machine?
No. Everything is served on the product's own origin under /abyss: no cross-origin header, no outbound request, no telemetry.