Files
patterm/AGENTS.md
Harry Bayliss 3622c41fd0 Land staged session/MCP/chrome work + sidebar clear-J fix
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.
2026-05-14 19:09:35 +01:00

4.7 KiB

Agent Guide

Project Overview

patterm is a Go terminal orchestration TUI. It runs as one foreground process that owns:

  • the host TUI chrome
  • child PTYs
  • headless libghostty-vt emulators for rendered-grid snapshots
  • the in-process MCP server
  • per-project scratchpads and command-preset trust state

There is no daemon or attach/detach model. Closing the patterm process tears down every child process it spawned.

Core packages:

  • cmd/patterm: main binary, including mcp-stdio and debug-harness subcommands.
  • internal/app: TUI/session state, palette, child lifecycle, rendering, MCP tool host.
  • internal/pty: thin wrapper around github.com/creack/pty.
  • internal/vt: libghostty-vt backed emulator wrapper.
  • internal/mcp: JSON-RPC MCP socket server and tool surface.
  • internal/preset: XDG-loaded agent/process presets.
  • internal/trust: per-project command-preset trust grants.
  • internal/harness: black-box PTY/MCP test harness.

Build Prerequisites

The normal build depends on the vendored libghostty-vt static library and headers under third_party/libghostty-vt/install.

If that install tree is missing, run:

make deps

This fetches the pinned Ghostty commit and builds libghostty-vt with Zig. The Makefile currently requires zig on PATH with a compatible version.

Common checks:

go test ./...
go build -o ./bin/patterm ./cmd/patterm

Harness Testing

The harness is the preferred way to test patterm end-to-end without a human watching a terminal.

It starts a real patterm child process in a PTY, feeds its output through the same internal/vt emulator used for child panes, and talks to the child patterm process over its per-PID MCP Unix socket. Scenarios are JSON files under:

internal/harness/scenarios/

Useful harness commands:

go test ./internal/harness/...
go test -race ./internal/harness/...
go test -count=10 ./internal/harness/...

Run one scenario through the CLI:

go build -o ./bin/patterm ./cmd/patterm
./bin/patterm debug-harness --scenario internal/harness/scenarios/spawn_process_via_palette.json

Harness scenarios create hermetic XDG/config/data/runtime directories, write scenario-local presets and fake scripts, and set PATTERM_HARNESS=1. They must not read or write the user's real patterm config.

Failure artifacts are written under:

internal/harness/.artifacts/

That directory is gitignored. Artifacts include rendered grid text, raw PTY bytes, serialized VT state, MCP snapshots, the resolved environment, and an annotated scenario.

Harness Environment Notes

The harness and patterm MCP server create Unix sockets and spawn PTYs. In restricted sandboxes this can fail with errors such as:

listen unix ... setsockopt: operation not permitted

When that happens, rerun the harness tests or debug-harness command in an environment that permits Unix sockets and PTYs.

When testing a specific binary, set:

PATTERM_BIN=/absolute/path/to/patterm go test ./internal/harness/...

Without PATTERM_BIN, harness tests build the current checkout once into a temp location and test that binary.

Changelog

User-visible changes go in CHANGELOG.md (Keep-a-Changelog format). When finishing work that affects users — new MCP tools, palette behavior, preset shapes, host chrome, anything observable — add a bullet under [Unreleased] in the appropriate Added / Changed / Fixed / Removed section. The TODO file is scratch space, not history; the changelog is the record.

When a TODO.md item is actioned (bug fixed, behavior changed, feature shipped), the resolution belongs in CHANGELOG.md — not as a "done" entry left in TODO.md. Workflow:

  1. Land the code change.
  2. Add a [Unreleased] bullet in CHANGELOG.md describing what the user will now experience differently.
  3. Remove the corresponding item from TODO.md (don't tick it off and leave it behind — TODO.md only lists outstanding work).

If a TODO item turns out to be a non-issue or gets dropped without a code change, just delete it from TODO.md; no changelog entry is needed.

Development Notes

  • Prefer existing package boundaries. MCP protocol shapes live in internal/mcp; runtime behavior usually belongs in internal/app.
  • Keep terminal rendering changes covered by focused app tests or a harness scenario.
  • Do not let child PTY output own host chrome. The app owns tab bar, sidebar, status line, and palette.
  • Command-preset trust must be seeded before starting patterm in tests because the app opens the trust store during startup.
  • If a scenario needs external CLIs such as claude, codex, or opencode, gate it behind an explicit opt-in environment variable. CI scenarios should use fake scripts/presets.