WorkerDeck

Guides

Agents and teams

Long-lived, named agents with an avatar and a standing brief, grouped into one-level teams.

An agent is a session with a name. Every session keeps one id for its whole life; naming it adds an identity to that same session: a name, an avatar, a standing brief, its team and its sharing, kept by the gateway in <state-dir>/agents.json. An agent’s id is its session’s id, and un-naming a session leaves it a plain session with the same id and history.

What a session runs is its current conversation. Compaction, sleep and a gateway restart all keep it; New conversation starts a fresh one under the same id, identity and team (see Conversations).

Create one

  • VS Code: the person icon in the Sessions title (New Agent), or Make agent in a card’s ⋯ menu to keep an existing session as an agent.
  • Dashboard: the + split button opens the New agent dialog (name, project, model, brief, an optional first prompt). Leave the name blank and the gateway picks one.
  • Change one later: in VS Code, Edit settings and Edit brief in the card’s ⋯ menu open the agent’s settings as JSON (with completion) and its brief as markdown; saving applies them. Over REST, PATCH /v1/agents/:id with { "config": { ... } } merges keys, and null clears one.
  • REST: POST /v1/agents with { name, brief, config: { cwd, model, ... }, prompt }, or POST /v1/sessions with an agent: { name, brief } block. An existing session is named with PATCH /v1/sessions/:id { "agent": { "name": "..." } } and un-named with { "agent": null } (refused while it is in a team). The /agents routes and naming are operator-only.

The brief reaches the model as host instructions on every session the agent runs; it is not part of the session data clients receive.

Conversations

New conversation on a card (idle sessions only, named or not) starts a clean conversation: same card, same place in the list, an empty transcript. Previous chat context is not carried over. An agent can do the same itself with the context_reset tool, which runs once its turn ends, and a typed /clear does the same cut. If the session still has messages it has not answered, New conversation asks first: the dialog says how many, warns when some may come from peer agents, and discards them only when you confirm. A typed /clear in that state is refused with a message instead; use New conversation to decide.

The old conversation becomes a history entry of the same session: it stays readable, read-only, under Conversations on the agent (card menu on the dashboard and in VS Code, a long-press on the phones). Its history comes from the engine’s own session store, so it follows that engine’s retention: a transcript Claude Code or Codex has since pruned shows as unavailable. The session keeps its id, so a view that shows an agent stays on it.

Delete agent… retires the agent and releases its team members. Its conversations stay readable under Past agents. Closing a session that is not named keeps its conversations readable too. Over REST: POST /v1/sessions/:id/conversations (New conversation, for any session), GET /v1/sessions/:id/conversations, GET /v1/agents?retired=1, DELETE /v1/agents/:id. An agent’s id is its session id, so the session routes serve agents too. Each call that starts a conversation or retires an agent carries expectedGeneration, the conversation you were looking at, and is refused (409) if the session has moved on since.

Teams

A team is a lead and the agents that name it as their lead, one level deep: a lead cannot join another team, and nobody can join a member. Drag a card onto another agent to join its team, drop it between members to place it, and drag a member out to leave; the card menus offer the same moves. In the list, a team draws a member under its lead only while that member needs you: an approval waits, it failed, or it said it is blocked on you (set_status with waitingOn: "human"; your next message to it clears that). Each such card carries a chip (Approval, Failed, Blocked), and the lead shows how many members need you. The rest sit as avatars on the lead’s own line (“2 need you · 3 working · 1 idle”); the member you open stays drawn, and expanding the team shows everyone. The Needs attention filter and group use the same rule, for lone agents too.

The lead’s own panel lists the same members in a strip above its transcript: name, reason and what it is about (how many approvals wait, the failure, or the status the member is blocked on). Click a name to open that member. A member whose new conversation failed to start gets a Retry button. A row leaves the strip as soon as its reason clears.

Teams also scope peer messaging: a member reaches only its lead and teammates, and nobody outside the team reaches a member. With a relay a team can span gateways, and agents of different owners meet only in a team or as two shared agents (see Owners). In the composer, # finds an agent by its name.

One repository, one persona per folder

Claude Code and Codex both read instruction files from the session’s folder and every folder above it, so a member working in packages/db also loads the root AGENTS.md, often the lead’s persona. Set config.instructionScope: "cwd" on a member (or Loads instruction files from its project folder only in New agent, or PATCH /v1/agents/:id with { "config": { "instructionScope": "cwd" } }) and its sessions load only the files in its own folder and below: no AGENTS.md, CLAUDE.md, CLAUDE.local.md, .claude/CLAUDE.md, .claude/AGENTS.md or .claude/rules/ from the folders above. Your own ~/.claude/CLAUDE.md and ~/.codex/AGENTS.md still load. The default, "ancestors", is the engines’ own behaviour. A recommended layout: the lead persona in the root AGENTS.md, one persona per member folder, and anything every member needs in each member’s file or brief. The change applies from the agent’s next session start or wake. Claude Code does not follow an @-import that points outside the session’s folder (for example @../../docs/CONVENTIONS.md) unless you approve it, with or without this setting, and Codex does not follow imports at all, so keep shared text inside each member’s folder.

Private and shared

An agent is Private unless you choose Shared in New agent or its ⋯ menu. Sharing only matters toward other owners: a shared agent is listed for their shared agents, which can message it but never peek at it. Sharing is set on the lead; members are never shared on their own.

Status

Every session, agent or not, has a one-line status. On an agent card it sits under the name and the model badge; with no status set, the card shows the checklist item in progress, else the session title, else the agent’s state (“Idle”, “Working…”), slightly dimmer. The agent sets it with the set_status tool (text, an optional emoji; an empty text clears it), and you can set or clear it from the card menu or with PATCH /v1/sessions/:id { "statusLabel": { "text": "..." } }. It stays until changed and clears when the conversation resets. Every agent is told to keep it current (set it when starting a task, when blocked or waiting, and when done); add your own rules in AGENTS.md if you want more.

Goals

A goal is a condition the agent keeps working toward, turn after turn, until it holds: “all tests in packages/core pass”. Set one from the card or session menu on any client (Set goal…; Codex sessions also take a token budget), with POST /v1/sessions/:id/goal { "text": "..." }, or let the agent set its own with the goal_set tool (a lead can set one on its members). Claude checks the goal at the end of every turn and keeps going while it is not met; Codex runs goal turns by itself until the goal is met, the budget runs out, or you pause it (Pause goal / Resume goal, Codex only). Clear goal drops it; Stop interrupts the turn and pauses a Codex goal.

The transcript shows a line for each step (set, not met yet with the reason, met, failed, paused, cleared), the card shows the goal under the name when no status is set, and Session info lists its state, checks, last reason and token use. A goal you set is yours: an agent can change it only once it is met or failed. An active Codex goal keeps the engine awake, so the session does not sleep while idle until the goal is paused or cleared.

MCP servers that were down

An engine dials its MCP servers once, when it starts; one that was not running then stays failed. On Claude sessions WorkerDeck reconnects every failed server when the next message reaches a running engine (at most once a minute), and the agent has an mcp_reconnect tool for doing it itself: no argument reconnects every failed server, server reconnects that one. Servers waiting for sign-in or switched off are left alone. A sleeping engine needs neither: it dials everything again on wake.

A server that was added or changed after the engine started (claude mcp add, an edited .mcp.json) needs the engine to read its configuration again. The agent calls mcp_reload; when its turn ends the engine restarts on the same conversation (the card never shows it asleep), and the new server’s tools are there from the next message.

Codex sessions have mcp_reload only, and it works in place: the engine re-reads its MCP configuration mid-turn, which both adopts a new server and brings back one that was down, so the agent can use it on its very next step.

Sleep

An idle agent’s engine sleeps after 15 minutes by default, freeing its memory; the next message wakes it with its history. Set the gateway default with --agent-sleep-after 30m (never or 0 turns it off), the VS Code setting workerdeck.host.agentSleepAfterMinutes, or per agent (config.sleepAfterMs).

Avatars

Every agent wears a small robot: a head, an antenna, a visor, eyes and a mouth on a rounded backdrop, each part a kind and a colour. A new agent gets a random one in its project’s colour. The robot also shows what the agent is doing: it blinks when idle, scans and types while working, holds up a ! when it needs you, and dozes when its engine sleeps. On the agent’s card the backdrop fills with its context use, and turns amber when it is time to wrap up.

Change avatar in a card’s menu opens an editor: start from a few random robots, then pick each part’s kind and colour. An agent can change its own with the change_avatar tool, either rerolling or naming the parts it wants (eyes: { kind: "slit", color: "teal" }).