Skip to content

feat(dispatch): add New Agent In… to spawn an agent into a chosen project #852

Closed

Description

@Juliusolsson05

Motivation

Filling empty Grid Dispatch lanes takes a detour. When a lane is empty and its row is not bound to a project, resolveDispatchSpawnTarget files a new agent under the classic Dispatch focus (the last agent you selected) or activeTabId. So to put a Codex agent for project C into an empty lane, you first have to navigate to some existing agent in project C — only to move the "current project" — then return to the empty lane and run New Agent…. With five fresh lanes that detour happens five times.

The machinery to spawn into an explicit project already exists: createDetachedDispatchAgent(selection, { tabId, anchorSessionId }) is what the Dispatch project header's "+" and the external agents.create capability use, and it still places the agent in the focused lane. What is missing is a keyboard entry point that does not depend on focus.

Intended behavior

A new Dispatch command, New Agent In…:

  1. Step 1 — pick the agent: the same choices as New Agent… (Claude, Codex, OpenCode, OpenCode Terminal), from AGENT_PROVIDER_CHOICES.
  2. Step 2 — pick the project: project tabs, labelled with the same A · title vocabulary Dispatch uses. Backspace returns to step 1. The initial highlight is the project plain New Agent… would have used, so Enter-Enter is never worse than today.
  3. Commit spawns a detached Dispatch agent in the chosen project, with its working directory borrowed from an existing agent in that project, into the focused lane (same lane semantics as New Agent…).

Decisions:

  • Dispatch only (surface: 'dispatch'). In the grid a project is a tab one keystroke away, and a detached agent spawned from the grid would be invisible there.
  • If the focused lane's row is bound to projects, step 2 offers only those projects — the binding contract says a row's index only lists its bound projects, so an agent from another project would sit in a lane its own index cannot show. Unbound rows offer every project.
  • A project with no agent to borrow a directory from is listed but disabled, with the reason, rather than silently omitted.
  • No default keybinding.

Acceptance criteria

  • New Agent In… appears in the command palette only while Dispatch is active.
  • Choosing an agent then a project creates that agent in that project, in the focused lane, without changing which agent/project you had to be focused on beforehand.
  • Row project bindings restrict the project list; unbound rows list all projects.
  • Projects without a directory anchor are disabled with an explanation.
  • Escape, click-outside and Cancel close the dialog; Backspace on step 2 returns to step 1; a double Enter cannot spawn two agents.
  • Behavioral tests cover the project eligibility/anchor rules and the dialog's two-step flow.

Activity

  1. Juliusolsson05 commented on Sep 11, 2026

    @Juliusolsson05
    OwnerAuthor

    Implemented in #860 (branch feat/new-agent-in-project). Shipped as designed above: Dispatch-only, row bindings restrict the project list, initial highlight is plain New Agent's target, unanchorable projects are listed disabled with the reason, no default keybinding. The row-binding lookup is now one selector (focusedLaneBoundProjectTabIds) shared with resolveDispatchSpawnTarget so the picker and the spawn resolver can't disagree. Not yet exercised in the running app; see the PR's limitations section.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions