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

128 lines
4.7 KiB
Markdown

# 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:
```sh
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:
```sh
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:
```text
internal/harness/scenarios/
```
Useful harness commands:
```sh
go test ./internal/harness/...
go test -race ./internal/harness/...
go test -count=10 ./internal/harness/...
```
Run one scenario through the CLI:
```sh
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:
```text
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:
```text
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:
```sh
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.