Chapter 11: Embedded Terminal Tabs and One-Key Agent Task Handoff

Modern technical authoring and software architecture rarely happen in isolation from execution. While reading an architecture decision record (ADR) or triaging a backlog in AutoDoc, you frequently need to run a shell command, inspect git log, or delegate an implementation task to an interactive CLI coding agent such as Claude Code, Gemini CLI, OpenAI Codex, or Aider.

AutoDoc embeds full pseudo-terminal (PTY) multiplexers directly inside both the terminal UI (--ui) and the native GUI (--gui). Rather than treating shells and AI agents as opaque external windows, AutoDoc wires its terminals and agents features (tui/terminals.go, tui/agenttabs.go, tui/agentinstances.go) into the narrow Core host interface and connects them directly to the built-in Todo Task Engine (tui/todos_assign.go). With a single keystroke (A) inside the Todos Panel (SPC x), you can assign a task, transition its status to in-progress, launch or focus the target agent's PTY tab, and paste a structured task brief straight into its prompt.


1. Configuring Terminal Tabs and Agent Profiles

AutoDoc organizes embedded PTYs into two distinct, dockable TerminalTabs drawers contributed to the program's panel registry:

  1. The Shell Terminal Panel (terminalView): General-purpose interactive shells (bash, zsh, fish) for running builds, tests, and Git commands.
  2. The Dedicated Agent Panel (agentView, SPC g): Long-lived CLI coding agents, each started from an agent profile, identified by a persistent codename and scoped to the active workspace.

Agent profiles live in AutoDoc's preferences and are managed in System › Agent profiles… (SPC G); there is no config-file section for them. The dialog lists each profile (● marks the default, ▶ a running one) with Use, Add…, Edit…, Make default and Remove. A profile has three fields:

The first profile added becomes the default, which SPC g starts; Make default chooses another. The shell terminal's tabs need no profile: + starts your login shell.

Delivery Identity: Display label vs. Immutable codename

In tui/agentinstances.go, AutoDoc strictly separates an agent's human-facing display label (Name) from its routing identity (Codename):


2. Operating the Terminal and Agent Drawers

Both the shell terminal drawer (SPC ` / :terminal) and the agent drawer (SPC g) share a unified tab strip controller (tui/tabmenus.go over widget.TerminalPanel) while remaining independent dock panels that can be placed on any window edge (left, right, top, bottom) or floated freely (Alt+drag or SPC L).

Tab Strip Controls and Lifecycle

The terminal's and the agents' tabs: each shell or agent has a tab; + adds one, and the strip's menu (≡, a right click anywhere on the strip or an empty panel, or Enter on the strip) has Go to ›, the panel's own rows (the terminal: New, Close; the agents: Restart, Close, Profiles…), Theme and font… (the terminals' theme, and in the GUI their font: the same settings as Preferences and Fonts and zoom…; Esc puts them back), in the GUI Text size › (the shells' text in both panels, Smaller and Larger a step of 10 % each, 50 % to 150 % of the cell size; Fonts and zoom… sets it too), Maximize (the panel filling the dock area; Restore while it does) and Hide, which closes the panel and leaves every shell and agent running. At the strip's right end, _ does the same, + maximizes the panel (again to restore), as Maximize does, and x stops every shell or agent in the panel and closes it, asked once while any runs.

Live Input vs. PTY Normal Mode (Ctrl+T)

Every key goes to the shell or agent, Esc included; Ctrl+T toggles Normal mode, which moves over its history (h j k l, /, v, y …), and Esc in Normal mode hides the panel. Ctrl+T on the page stays the Rendered view's. Interactive TUI agents (such as Claude Code, Vim inside a shell, or htop) so behave as they do in a terminal of their own.

To scroll back through history, search terminal output, or copy text without reaching for the mouse:

  1. Press Ctrl+T to switch the PTY into Normal Mode.
  2. Navigate history using standard Vim motions (h, j, k, l, gg, G, Ctrl+U, Ctrl+D), search scrollback with /, n, and N, or select and yank text with v and y.
  3. Press Ctrl+T again (or i) to return to live PTY input mode, or press Esc while in PTY Normal Mode to hide the panel and return keyboard focus to the document editor (RestoreKeyboardPane).

3. The One-Key Agent Task Handoff Workflow (SPC x -> A)

Without integrated task handoff, delegating a backlog item to an AI coding agent requires a tedious, error-prone sequence: finding the task file path, manually editing its YAML frontmatter to set status: in-progress and assignee:, moving the file from .todo-list/open/ to .todo-list/in-progress/, copying the task title and linked ADR paths, switching to the agent terminal, and pasting a prompt.

AutoDoc collapses this entire workflow into a single keystroke inside the Todos Panel (tui/todos_assign.go):

sequenceDiagram
    autonumber
    actor User
    participant Todos as Todos Panel (SPC x)
    participant Picker as AgentAssignPicker
    participant Daemon as AutoDoc Daemon (core/todo)
    participant Agents as TerminalTabs / Agent PTY

    User->>Todos: Press 'A' on selected task
    Todos->>Picker: Open Picker with assignable AgentEntries
    User->>Picker: Select agent (e.g. Claude Code, codename: claude)
    Picker->>Todos: Prompt for optional Instructions line
    User->>Todos: Enter instruction (default: "Task assigned to you.")
    Todos->>Daemon: todos.assign(at, id, rev, "autodoc:claude", instruction)
    Note over Daemon: D1 Rule: Atomically transition open to in-progress, move file to in-progress/, and record journal row
    Daemon-->>Todos: Updated task (status: "in-progress", new path & rev)
    Todos->>Todos: Follow task to In Progress tab (if workspace ticket current)
    Todos->>Agents: Core.HandTask(AgentRef{Codename: "claude"}, TaskRef, instruction)
    alt Agent PTY not yet running
        Agents->>User: Ask confirmation to start agent profile
        User-->>Agents: Confirm start (&Yes)
        Agents->>Agents: Write workspace guide & spawn PTY tab
    end
    Agents->>Agents: Send bracketed paste (Task, File, ID, Instruction), no Enter
    Agents->>User: Open agent panel, tab selected, keyboard in input mode
    Agents-->>Todos: Delivery complete callback on UI loop
    Todos-->>User: Toast: "todos: assigned to Claude Code, and typed into its input: press Enter there to send it"
    User->>Agents: Enter (submits the task)

Step-by-Step Handoff Execution

  1. Open the Todos Panel (SPC x) and Select a Task: Move the cursor to any task in an active bucket (Open, In progress, Deferred, or Completed) within a claimed, writable store.
  2. Press A (Shift+A, App.todoAssign):
    • AutoDoc queries Core.AgentEntries() and filters them via assignable()—excluding any instance currently shutting down (Closing) and any stopped Orphan whose profile was removed.
    • It opens the Agent Assign Picker (agentAssignPicker), displaying each agent's display name, codename, and live state (running or stopped), alongside a live right-hand preview pane showing the exact command and autodoc:<codename> assignee string.
  3. Choose the Target Agent and Enter Optional Instructions:
    • Press Enter on an agent (for example, Claude Code (claude)).
    • AutoDoc opens the Instructions prompt (todoAssign). Type a custom directive (single line; newlines are rejected by ErrAgentTask) or press Enter on an empty line to use the default instruction: "Task assigned to you." (Pressing Esc cancels before any store write occurs.)
  4. Atomic Store Mutation (todos.assign):
    • AutoDoc records a TicketWorkspace guard (ws: t.c.Ticket(nil, TicketWorkspace)) and invokes todos.assign(at, id, rev, "autodoc:<codename>", instruction).
    • Inside the daemon (core/todo), todos.assign verifies the task's SHA-256 rev token. If the task is currently open, Decision D1 atomically transitions its status to in-progress, stamps status_changed and updated, moves the Markdown file into .todo-list/in-progress/, and commits the SQLite journal row.
    • In the Todos Panel, followTask automatically switches the active tab to In progress and places the selection cursor on the moved task.
  5. PTY Spawn/Focus and Bracketed Paste Delivery (Core.HandTask):
    • Once todos.assign succeeds and the TicketWorkspace guard confirms the user has not switched workspaces mid-flight, handOver constructs a TaskRef{Title, Path, ID} using the post-move file path in in-progress/ and calls Core.HandTask(AgentRef{Codename}, ref, instruction, done).
    • If the chosen agent is stopped, AutoDoc prompts: "Start <Agent Name> to hand over this task?" Upon confirmation, startInstance opens the agent drawer, writes the workspace's agent guide (writeAgentGuide: AGENTS.md, CLAUDE.md and bin/autodoc), spawns the PTY in AutoDoc's own folder for the workspace (<state dir>/agent/<workspace>), not the workspace root, and selects its tab.
    • HandTask formats the canonical 4-line payload:
      Task: Implement SQLite crash-recoverable todo journal
      File: /abs/path/to/workspace/.todo-list/in-progress/2026-10-17-implement-sqlite-todo-journal.md
      ID: 2026-10-17-implement-sqlite-todo-journal
      Instruction: Task assigned to you.
      
    • It dispatches the payload via panel.SendBracketedPaste(tab, payload): one bracketed paste (\x1b[200~...\x1b[201~), so the multi-line text lands intact at the prompt. A program that hasn't enabled bracketed paste gets nothing, never keystrokes, and the toast says why. An agent HandTask just started is tried again every agentReadyPoll (100ms) for up to agentReadyWait (10s) while its program starts.
    • AutoDoc never presses Enter (ADR 1792991980). An Enter can't tell the agent's input from a permission or select prompt it is showing, so it could answer one. Instead the payload waits in the agent's input, and the agent's panel opens with its tab selected and the keyboard in input mode. The toast says "assigned to Claude Code, and typed into its input: press Enter there to send it", and the user's Enter starts the agent on the task file and its linked $KB_ROOT ADRs.
Illustrative Workflow Time: Manual Copy-Paste vs One-Key Handoff0246810121416Elapsed Time (Seconds)1. Locate Task2. Update Status & Assignee3. Gather ADR Paths4. Paste Prompt to AgentHandoff Workflow StepDispatch MethodAutoDoc One-Key (SPC x -> A)Manual Copy-Paste

4. Separation of Concerns: autodoc:<codename> vs. Other Tools' Agents

A critical architectural boundary in ADR 1791532020 (§2.7a) is that AutoDoc manages only its own embedded terminal agents; an agent another tool runs is that tool's to manage:

CategoryKey_or_BindingType_or_ScopeDefault_or_FormatDescription
Config / Profilelabel / namestringRequiredHuman-readable display name shown on the terminal tab strip and in the Agent Assign Picker (may repeat across profiles)
Config / ProfilecodenamestringDerived lowercase-hyphen slugStable delivery identity persisted on first save; used for autodoc:<codename> assignee routing and tab lookup
Config / ProfilecommandstringRequired (e.g. claude --model opus)The command line that starts the agent, run through /bin/sh -c; {root} and {workspace} become the workspace's folder and name, each shell-quoted
KeybindingSPC ` / :terminalGlobal WindowToggle Terminal PanelOpens or hides the embedded shell TerminalTabs drawer while keeping background PTY processes alive
KeybindingSPC gGlobal WindowToggle Agent PanelOpens or hides the dedicated AI Agent TerminalTabs drawer; starts the default agent if none is running
KeybindingF11Terminal / Agent PanelMaximize / RestoreToggles fullscreen dock expansion for the active TerminalTabs or Agent panel (also in strip menu ≡)
KeybindingCtrl+TTerminal / Agent PTYToggle PTY Normal ModeSwitches between live PTY input forwarding (where Esc goes to the shell/agent) and Vim scrollback Normal mode (h/j/k/l, /, v, y)
KeybindingEsc (in PTY Normal Mode)Terminal / Agent Normal ModeHide PanelCloses the terminal or agent drawer without terminating running child processes
Keybinding+ / ≡ (Strip Menu)Tab StripTab ManagementSpawns a new shell or profile (+), switches tabs (Go to ›), restarts/closes an agent, or opens Profiles… and Theme/font…
KeybindingShift+A (A)Todos Panel (SPC x)Assign Task to AgentOpens AgentAssignPicker, transitions open task to in-progress with autodoc:<codename>, and dispatches task brief to PTY
Conventionautodoc:<codename>Assignee Prefixe.g. autodoc:claudeDistinguishes AutoDoc-managed terminal agents from agents another tool assigns (agent:<name>)
ConventionagentReadyWaitDelivery Timing10sHow long a task to an agent the hand-over just started waits for its program to enable bracketed paste, retried every 100ms; no Enter follows the paste

Summary

By pairing persistent agent profiles (tui/agentinstances.go) with atomic todos.assign transitions (tui/todos_assign.go), AutoDoc turns task delegation from a 45-second context-gathering chore into a sub-second, crash-safe handoff. Once the task brief lands in the agent's terminal, the agent itself needs a fast, token-efficient way to search the Knowledge Base, inspect linked ADRs, and validate its writes—the exact subject of Chapter 12.


← Previous: Chapter 10: Todo Task Engine | Index | Next: Chapter 12: AI Agent Integration & CLI RPC →