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:
- The Shell Terminal Panel (
terminalView): General-purpose interactive shells (bash,zsh,fish) for running builds, tests, and Git commands. - The Dedicated Agent Panel (
agentView,SPC g): Long-lived CLI coding agents, each started from an agent profile, identified by a persistentcodenameand 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:
- name: the display label, for example
Claude Code; - codename: its routing identity, derived from the name when left empty (lower-case letters or digits, separated by hyphens);
- command: the command line that starts the agent, run through
/bin/sh -c, for exampleclaude --model opusorcodex.{root}and{workspace}in it become the workspace's root folder and name, each quoted for the shell.
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):
- Display Labels May Repeat: You can rename
"Claude Code"to"Claude (Sonnet 4.5)"at any time without breaking existing task assignments or running tabs. - Persistent
codenameIdentity: When a profile is first saved without an explicitcodename, AutoDoc derives a lowercase, hyphen-separated slug from the name (allocating deterministic numeric suffixes on collision) and persists it once. - Incarnation Tracking (
AgentRef): Every running agent PTY is stamped with a monotonic incarnation token (agent-1,agent-2, …) viaagentIncarnation.Add(1). If a profile is deleted while its PTY is still running, the running instance is retained as anOrphanentry inAgentEntries()and keeps itscodenamereserved until the process exits and cleanup completes (awaitInstanceRetirement).
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.
- Adding Tabs (
+):- In the Terminal Panel, clicking
+(or selecting New from the strip menu≡) spawns a fresh login shell in the active workspace's root directory. - In the Agent Panel, clicking
+opens a menu of all configured agent profiles (addRowsintui/agenttabs.go), badging currently running profiles with▶. Selecting a running agent switches to its tab; selecting a stopped profile spawns it in a new tab named by itscodename.
- In the Terminal Panel, clicking
- The Strip Menu's Rows:
- Go to › — Jump directly to any open tab by label.
- Restart / Close — In the Agent Panel, Restart (
restartAgent) starts a stopped agent or prompts for confirmation (&Yes, restart it) before terminating a running agent and respawning its updated command in a fresh tab. Close (closeAgent) stops the process and removes the tab. - Profiles… — Opens the Agent profiles… dialog to add, edit, or set the default agent.
- Resume — Sends the tab's program a SIGCONT, waking one that a suspend stopped.
Ctrl+Zitself never reaches a program here;panel.resume(the command) andautodoc.agents.resume(Lua) do the same. - Theme and font… — The terminals' look is set independently of the editor's prose font.
- Maximize / Restore —
F11does the same; Restore returns the panel to its saved percentage geometry.
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:
- Press
Ctrl+Tto switch the PTY into Normal Mode. - Navigate history using standard Vim motions (
h,j,k,l,gg,G,Ctrl+U,Ctrl+D), search scrollback with/,n, andN, or select and yank text withvandy. - Press
Ctrl+Tagain (ori) to return to live PTY input mode, or pressEscwhile 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):
Step-by-Step Handoff Execution
- Open the Todos Panel (
SPC x) and Select a Task: Move the cursor to any task in an active bucket (Open,In progress,Deferred, orCompleted) within a claimed, writable store. - Press
A(Shift+A,App.todoAssign):- AutoDoc queries
Core.AgentEntries()and filters them viaassignable()—excluding any instance currently shutting down (Closing) and any stoppedOrphanwhose profile was removed. - It opens the Agent Assign Picker (
agentAssignPicker), displaying each agent's display name,codename, and live state (runningorstopped), alongside a live right-hand preview pane showing the exact command andautodoc:<codename>assignee string.
- AutoDoc queries
- Choose the Target Agent and Enter Optional Instructions:
- Press
Enteron an agent (for example,Claude Code (claude)). - AutoDoc opens the Instructions prompt (
todoAssign). Type a custom directive (single line; newlines are rejected byErrAgentTask) or pressEnteron an empty line to use the default instruction:"Task assigned to you."(PressingEsccancels before any store write occurs.)
- Press
- Atomic Store Mutation (
todos.assign):- AutoDoc records a
TicketWorkspaceguard (ws: t.c.Ticket(nil, TicketWorkspace)) and invokestodos.assign(at, id, rev, "autodoc:<codename>", instruction). - Inside the daemon (
core/todo),todos.assignverifies the task's SHA-256revtoken. If the task is currentlyopen, Decision D1 atomically transitions its status toin-progress, stampsstatus_changedandupdated, moves the Markdown file into.todo-list/in-progress/, and commits the SQLite journal row. - In the Todos Panel,
followTaskautomatically switches the active tab to In progress and places the selection cursor on the moved task.
- AutoDoc records a
- PTY Spawn/Focus and Bracketed Paste Delivery (
Core.HandTask):- Once
todos.assignsucceeds and theTicketWorkspaceguard confirms the user has not switched workspaces mid-flight,handOverconstructs aTaskRef{Title, Path, ID}using the post-move file path inin-progress/and callsCore.HandTask(AgentRef{Codename}, ref, instruction, done). - If the chosen agent is stopped, AutoDoc prompts: "Start <Agent Name> to hand over this task?" Upon confirmation,
startInstanceopens theagentdrawer, writes the workspace's agent guide (writeAgentGuide: AGENTS.md, CLAUDE.md andbin/autodoc), spawns the PTY in AutoDoc's own folder for the workspace (<state dir>/agent/<workspace>), not the workspace root, and selects its tab. HandTaskformats 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 agentHandTaskjust started is tried again everyagentReadyPoll(100ms) for up toagentReadyWait(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_ROOTADRs.
- Once
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:
- Assignee Namespace Isolation: When you assign a task via
Ain AutoDoc's Todos Panel, theassigneefield is always prefixed withautodoc:<codename>(for example,autodoc:claudeorautodoc:gemini). An assignee written by another tool keeps that tool's own form (for exampleagent:<name>), and AutoDoc never delivers to it. - Durable Record vs. Best-Effort Terminal Delivery: The
todos.assignwrite in.todo-list/is the durable record of ownership;HandTaskis a best-effort UI delivery side effect. If you decline to start a stopped agent (ErrAgentCancelled), or if you switch workspaces before the RPC write returns, the task remains durably assigned toautodoc:<codename>in.todo-list/in-progress/and AutoDoc displays an actionable toast:"todos: assigned to autodoc:claude, but not delivered (you didn't start it): start the agent, then A on the task to deliver it again". PressingAa second time re-delivers the payload cleanly.
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 →