AI assistants

Agent threads

A supervised agent thread is a piece of work you hand to a coding agent and come back to. The Inbox is where every one of them reports in, tells you what it needs, and keeps its own isolated checkout of your repository.

The Inbox

The board is called the Inbox, and it opens three ways: from the Inbox chip that sits next to Dex, with Cmd/CtrlShiftJ (which also jumps straight to the next thread that needs you), or as a permanent page of the right-side notebook. It is one row per thread, sorted by how much each one wants from you rather than by when it started, so the thread that is stuck waiting on an approval sits above the one quietly working. When more than one project is on the board, rows group under the project they run against.

New task takes the board over with a draft composer, and the composer is the thread until the first send: nothing is created until the message goes out. Where the work runs is a chip menu: Local, New worktree, or an existing worktree, and the other chips pick the agent instance, model, effort and mode. For the worktree target the branch strip offers a base-branch chip, and Deska can fetch that base from origin first so the thread starts on what the remote has instead of a stale local branch. Check out a pull request… is a live picker that lists the repository’s open pull requests through gh; picking one forces the worktree target, because a pull request always runs in its own checkout.

A few controls keep a busy board readable:

  • Settle thread moves a row you are done with into a compact Settled fold at the bottom. It stays there until you move it back. An Archived fold sits below it, for rows you hid entirely.
  • Snooze thread demotes a row until a time you pick (in an hour, this evening, tomorrow, next week). A snoozed thread comes back early on its own if it hits an approval, asks a question, or fails, and carries a Woke marker until you look at it.

The board reads well from the keyboard: J and K (or the arrow keys) move the selection and Enter opens the selected row. Opening a row hands the whole panel to that thread, replaying the conversation from its durable log, including turns that ran before this app process started, and Esc hands the panel back to the board.

What a thread is asking for

Every row carries one state, listed here from most to least urgent:

  • Blocked means the agent hit an approval gate and cannot continue until you allow or deny it. The row reads approval.
  • Waiting for your input means the agent asked a question that is not a permission request. The row reads input.
  • Running means a turn is in flight. If a turn was accepted but has not started yet, the row says Preparing worktree… or Starting agent… so an accepted message never looks frozen.
  • Error means a turn or the underlying session failed. Where Deska could classify the failure it names the cause, for example Sign in to this provider or The installed CLI is too old.
  • Finished but unseen means a turn completed since the last time you opened that row. The flag clears when you actually look, not when the work ends.
  • Idle means the thread is alive and waiting for your next message.
  • Stopped means you stopped it. A stopped thread can be started again.

Press Cmd/CtrlShiftJ from anywhere in the app to jump to the next thread that needs you. It cycles through every waiting thread and then starts over, so repeated presses sweep the whole list. It skips archived, settled, and still-snoozed rows unless they are the ones raising a hand, and it does nothing at all when no thread is waiting.

TipThe chord is rebindable like any other action under Settings → Keybindings. See Keyboard shortcuts for the full list.

Threads versus one-off sessions

The board shows two kinds of row, and the difference is what survives. A thread is durable: its history, its pending questions, its checkpoints and its settings are written down, so it keeps raising its hand across a provider restart and reopens with the app. A one-off session is a provider session started outside the thread system; it appears on the board while it lives and dies with its process.

That difference shows up everywhere. One-off sessions have no branch, no worktree, no per-turn diffs, no plan card and no activity log, and they cannot be archived, settled or snoozed. When you want work you can walk away from and return to, start a thread.

Structured sessions of either kind run on the same runtime described in Coding agents. If you would rather drive a CLI by hand, that still works in a plain terminal.

Isolated git worktrees

A thread whose run target is New worktree gets its own git worktree: a second checkout of the same repository, on its own branch, in its own directory. Several agents can then work on one project at the same time without ever touching each other’s files, and without touching yours.

  • Your branch does not move. The worktree is cut from the current HEAD (or the base you named) onto a fresh branch under the deska/ namespace, so it is obvious in git branch which branches Deska created. Your own working tree stays exactly where it was.
  • The checkout lives outside the repository, in Deska’s application data folder, so nothing appears inside your project directory.
  • Every completed turn is checkpointed. Snapshots go to a private git ref namespace, never to your branches, HEAD or index. The thread detail lists the files each turn changed with added and removed line counts, and offers to restore the tree to how it looked before that turn. A turn whose checkpoint could not be captured says so and disables its own revert rather than offering an action that would fail.
  • Deska notices when the checkout moves. If anything runs git checkout or git reset inside a thread’s worktree, the thread records a warning naming both branches and shows a banner with an action to switch back. It never refuses the turn, because the move may well have been deliberate.
  • Cleanup is conservative. Deska removes only checkouts inside its own worktrees folder that no thread owns any more, that git recognises, and that have nothing uncommitted in them. Anything with uncommitted work is left untouched, and branches are never deleted, so a thread’s commits are always still there.

The row menu can open a terminal already changed into the thread’s own checkout, which is the fastest way to inspect what an agent did.

Setting up fresh worktrees with deska.json

A brand new checkout usually needs work before an agent can do anything useful in it: dependencies installed, code generated, an env file written. Put a deska.json file at the root of your project and Deska will do that for you.

The file holds a scripts array, each entry with a name and a command. The first entry flagged with runOnWorktreeCreate set to true is the setup hook: it runs once, inside the freshly cut worktree, before the thread’s first turn starts. The script runs with the worktree as its working directory, and gets DESKA_PROJECT_ROOT and DESKA_WORKTREE_PATH in its environment. Only one setup hook runs per worktree, even if several entries carry the flag.

Deska reads the manifest from the worktree checkout first and falls back to the project root, so a branch can pin its own setup while an uncommitted deska.json still works.

NoteSetup is capped at ten minutes, which is generous enough for a cold dependency install. A script that fails, times out or never starts becomes a warning in the thread’s Activity log, with the tail of its output, and the thread starts anyway. The same goes for a malformed deska.json: bad entries are skipped and reported, and a file that is not valid JSON is ignored entirely. A hand-written config can never wedge a thread.

Inside a thread

Opening a row expands the same detail the full panel shows: the transcript, whatever the agent is waiting on, the files it changed, and what Deska did on your behalf.

  • Approvals arrive as cards. Enter allows the request, S allows it for the rest of the session, D denies it, and Esc cancels the turn. A request that looks destructive (a delete, a force push, a hard reset) loses the accept keys on purpose and has to be approved with a deliberate click.
  • Questions arrive as their own cards, with number keys 1 to 9 picking an option. A question with several steps renders as one stepped card, and a question with no options turns the composer into its answer box. Pending cards stack oldest first, so the front card is always the one to answer next.
  • Proposed plans render as a Proposed plan card when a planning turn finishes. From there you can send it back to the same thread with Implement, ask for changes with Refine, or spin the work out with Implement in new worktree thread so the plan and its execution stay separate.
  • Per-turn diffs list every completed turn with its changed files and line counts, and open into a file-by-file view. A very large branch diff is capped, and the panel says so instead of showing a prefix as if it were the whole change.
  • Compaction happens when the conversation approaches the model’s context limit and the provider summarises earlier turns to keep going. The row notes it (compacted once, compacted 3x) so you know the agent’s memory of the early turns is now a summary. A token and context readout sits beside it, with the context ring shown only when the provider reported a real window.

The composer stays live while a turn runs. Enter queues your message as the next turn, and Steer now interrupts the running turn to redirect it. Agents that cannot be steered mid-turn say so and queue the message instead. To stop the running turn, click Stop on the strip above the composer, or hold Esc until the ring on that button fills. Releasing early cancels nothing, so a reflexive tap never kills a turn.

The composer’s chips also read back the thread’s current tuning (agent instance, model, effort, thinking and mode), so what the chips say is what the next turn runs with, and each project remembers the defaults you last used for its new tasks.

For the chat surface that drives your canvas rather than your repository, see Agents & Dex.

💡 Ideas+🐛 BugsSuggest a feature or report a bug