docs(prd-0021): dashboard as left tmux pane, selected agent as right pane #49

Merged
didericis merged 16 commits from dashboard-tmux-split-pane into main 2026-05-26 15:40:55 -04:00
Showing only changes of commit 7e20d75f00 - Show all commits
+29 -2
View File
@@ -995,12 +995,19 @@ def _attach_in_tmux(
*,
resume: bool,
tmux_state: dict,
focus_right_pane: bool = False,
) -> str:
"""Spawn / respawn the right pane with `bottle`'s claude
session. Mutates `tmux_state` ({'pane_id': str|None,
'slug': str|None}) so the main loop can track which slug is
in the right pane (used by the agents-pane indicator + the
explicit-stop hook)."""
explicit-stop hook).
`focus_right_pane=True` runs `tmux select-pane` after the
respawn so the operator is dropped into claude immediately.
The Enter re-attach key passes this; passive paths (the
auto-attach after a stop) leave it False so the operator
stays in the dashboard pane."""
docker_argv = bottle.claude_docker_argv(
_claude_runtime_args(resume=resume),
)
@@ -1011,9 +1018,24 @@ def _attach_in_tmux(
# operator still gets a session.
return _attach_via_handoff(stdscr, bottle, slug, resume=resume)
tmux_state["slug"] = slug
if focus_right_pane:
_tmux_select_pane(pane_id)
return f"[{slug}] in right pane"
def _tmux_select_pane(pane_id: str) -> None:
"""`tmux select-pane -t <id>` — moves tmux's keyboard focus
to the pane. Best-effort; failure is silent (logged only via
subprocess's stderr, which we suppress)."""
try:
subprocess.run(
["tmux", "select-pane", "-t", pane_id],
capture_output=True, text=True, check=False,
)
except FileNotFoundError:
pass
def _attach_to_bottle(
stdscr: "curses._CursesWindow",
bottle,
@@ -1028,8 +1050,13 @@ def _attach_to_bottle(
blocks until the operator exits claude. Re-attach always uses
`--continue` — first attach happens via `_new_agent_flow`."""
if _in_tmux() and tmux_state is not None:
# Enter re-attach is an explicit "I want to interact with
# this agent" signal — move tmux focus to the right pane
# so keypresses land in claude instead of the dashboard.
return _attach_in_tmux(
stdscr, bottle, slug, resume=True, tmux_state=tmux_state,
stdscr, bottle, slug,
resume=True, tmux_state=tmux_state,
focus_right_pane=True,
)
return _attach_via_handoff(stdscr, bottle, slug, resume=True)