Add a `lifecycle` help topic spelling out that the caller owns the
processes it spawns and should `close_process` when a sub-agent or
spawned child is no longer needed. The `spawn_agent` and `spawn_process`
descriptions advertised via `tools/list` now restate the same duty
inline (with a pointer to `help('lifecycle')`), so vendor TUIs see the
expectation at the moment they reach for the tool. The `spawning` topic
and `topics` index cross-reference the new content.
Bundles two already-staged improvements that fall in the same area:
- OnChildSpawned primes the snapshot-replay budget for new panes so
diff-based vendor TUIs come up clean without a manual Ctrl+W/Ctrl+S
refresh.
- TODO drops the three items now actioned (prompt-injection preface,
agent cleanup duty, opencode→claude view corruption) and keeps the
unicode `<?>` entry with the investigation notes.
This batches the in-flight [Unreleased] block from CHANGELOG.md into a
single commit. Highlights:
- Real MCP protocol layer (initialize / tools/list / tools/call) so
vendor MCP clients can complete the handshake against the per-PID
socket. Legacy direct-dispatch preserved for the harness.
- New mcp_injection kinds — cli_override for codex, config_env for
opencode — joining the existing env-var and config_file paths so
patterm can slot into more agents without touching their real
config or auth.
- Ctrl+A/D and Ctrl+W/S focus navigation across tabs and intra-tab
process lists, recognised in legacy / kitty CSI u / xterm
modifyOtherKeys encodings.
- Palette macros (sw / k / sp ) and reordering so open sessions
surface above spawn-new entries.
- Two-row tab bar, sidebar/tabbar/status chrome cache, viewport-wipe
on agent spawn, CR-terminated orchestrator injections, and split-
Enter PTY writes so paste-detecting TUIs see Enter as a key event.
Also fixes the bug logged in TODO: claude's Ctrl+O tool-call expansion
emits CSI 0 J, which the viewport renderer was forwarding verbatim —
wiping the sidebar to the right of the cursor and leaving the chrome
cache convinced nothing had changed. CSI 0 J and CSI 1 J are now
translated into per-row ECH sequences clamped to the viewport, same
as CSI 2 J and CSI K already were.
Agent guides (CLAUDE.md / AGENTS.md) now spell out the
TODO->CHANGELOG workflow so completed items land in the changelog
rather than as ticked entries left behind in TODO.
Module renamed github.com/harrybrwn/patterm → github.com/hjbdev/patterm
across imports.
Chrome:
- Palette redrawn with rounded box-drawing borders, accent left-bar
for the selected item, dim hints, and a separator-aware footer.
- Tab bar grew from 1 row to 3: labels with breathing room, a dim
argv subtitle truncated to each tab's width, and an accent thick
underline for the focused tab with a faint divider extending across
the rest of the host width. Layout, viewport-renderer, and screen-
renderer tests updated for the new mainTop.
- Sidebar reuses the same palette: accent section headers, `▎`
selection marker, `●`/`○` status glyphs, dim previews.
- Shared SGR constants moved into internal/app/style.go.
Palette input:
- Adjacent duplicate arrow events (legacy `\x1b[B` + kitty
`\x1b[57353u` for one keypress, or two of the same form) are now
collapsed via peekArrowEvent + chunk-level dedupe in processStdin.
- On open, push `\x1b[>0u` onto the host's kitty keyboard stack so
palette input is in plain legacy mode regardless of what the child
pushed (codex/ratatui pushes its own flags which had been leaking
to the host). Popped on close.
Tab-switch repaint (repaintFocused):
- Use the emulator's SerializeVT bytes (with SGR / cursor / DECSTBM
/ tabstops) instead of plain text, fed through the per-focused
viewport renderer so the shifter translates row positions.
- Prelude resets host SGR / DECOM / DECSTBM (pinned to viewport) /
cursor visibility before the replay, so leftover modes from the
previously-focused child don't distort the new snapshot.
- Re-emit the saved cursor as a child-space CUP after the
serialized bytes so the host cursor lands at the emulator's
actual position (overriding DECSTBM's home side-effect and the
tabstop-setup CHA sequences) AND the renderer's vr.row/vr.col
get re-synced via trackCSI.
- cursorShifter now carries childRows and rewrites empty
`\x1b[r` to `\x1b[<mainTop>;<mainBottom>r` (host coords) — the
default (1,1) shifted to (4,4) was producing a one-row scrolling
region that scroll-exploded the replay.
- After the snapshot lands, nudge the focused child with a one-row
PTY winsize toggle so the kernel emits SIGWINCH and ratatui-style
TUIs throw away their diff state and emit a fresh frame.
Codex still renders incorrectly after a focus switch; see TODO.md
"Switch-back render divergence" for the deep investigation handoff.
Rename list_children/read_output/kill/send_message_to to their SPEC §7
process_id-shaped names; drop report_to_parent (direction inferred by
send_message) and policy_check (replaced by per-project trust gating).
Add the SPEC's missing tools: start_process, restart_process,
close_process, rename_process, select_process, get_process_status,
get_project_status, get_process_raw_output, search_output,
get_process_ports, whoami, help.
Process model now distinguishes agent/terminal/command kinds with
opaque p_<6hex> IDs. Command entries are session-persistent so they
survive PTY exit and can be Restart'd. Status enum gains starting and
stopped. screen_version, port detection, and bracketed-paste send_input
land alongside.
Trust gating (internal/trust) replaces the regex policy: command-preset
spawns return needs_trust on first use; the user confirms in a
status-line modal and the grant persists to
\$XDG_DATA_HOME/patterm/projects/<key>/trust.json.
Tests cover send_message direction inference (parent↔child, sibling
rejection, nil caller paths) and trust grant persistence across reopen.