Skip to content

docs(spec): engine seam — carry herdr sessions, not only tmux - #109

Merged
frahlg merged 1 commit into
mainfrom
107-engine-seam
Aug 30, 2026
Merged

docs(spec): engine seam — carry herdr sessions, not only tmux#109
frahlg merged 1 commit into
mainfrom
107-engine-seam

Conversation

@frahlg

@frahlg frahlg commented Aug 30, 2026

Copy link
Copy Markdown
Member

Closes #107

Investigation and design spec for an Engine seam, so mir up --engine herdr can work without pretending. Doc only — no production code changed. cd go && go test ./... and cd web && npm test both green (167 web tests pass after npm ci in a fresh worktree).

Part 1 — what is coupled

Eight tmux couplings on the agent side, each cited with file:line and each restated as a capability that does not name a multiplexer: launch/--shell, the FrameWindows v2 snapshot, the ten-verb control allow-list, R3's hook push, D4's grouped sessions, G1's mirror and rw guests, mir doctor, and every FrameWindows consumer in go/ and web/.

Two of them are the real gates: isDefaultTmuxLaunch is byte-exact argv equality against {"tmux","new","-A","-s","main"}, and sessionFromLaunch is the one predicate that turns the snapshot, the push, and the control channel on or off together.

Part 2 — herdr, measured

herdr 0.8.2, installed into a scratch directory with HERDR_INSTALL_DIR and run under a throwaway HOME. The machine's own herdr config was never opened; the sandbox server was stopped and its state removed. Claims come from experiments, not from the docs:

  • Two clients share one focus. Client A sat still while client B pressed next_tab; A's own byte stream then contained tab 2's marker, and replaying A's capture shows A rendering tab 2. Repeated with workspaces, same result. There is no grouped-session analogue — named sessions are separate servers. D4 is unsupported.
  • terminal session observe is genuinely confined. Injected terminal.input, terminal.resize and terminal.scroll all had measurably zero effect (0 occurrences of the injected text in the pane). A secret marker printed in another pane while the observer ran: 0 hits. Output printed in its own pane after focus moved away: 2 hits. This is a better read-only primitive than G1's capture-pane + pipe-pane FIFO.
  • events.subscribe pushes layout, tab, pane and agent_status changes over the socket, replaying current state on subscribe. R3's 22 global hooks + wait-for + 1 s poll collapse to one open socket.
  • A small viewport is a crop, not a reflow whenever another client owns the geometry: a 40×12 controller left the pane at 113×43 with a UI client attached, and the rendered frame is cut at column 40 rather than wrapped.
  • Agent state is a heuristic. For Claude Code and Codex the authority is a screen manifest scraped from the pane buffer and updated from herdr.dev in the background.

§2.7 lists what was not verified — Linux, real agent detection, reconnect under loss, id stability across restart.

Part 3 — the seam

An Engine interface with seven methods plus a Caps struct, a per-engine capability table (supported / degraded / unsupported for tmux and herdr), and three enforcement points so nothing degrades quietly: mir doctor reports capabilities, mir up prints what it gives up, and a missing capability is an error naming the engine.

One hard refusal: on an engine without per-attach views, Miranda serves one interactive attach at a time. Letting two viewers fight is the bug D4 was written to kill.

FrameWindows stays one wire format — the tmux-shaped ids move behind the engine, a/b become optional, and agent state arrives as one optional st field that cannot break the v2 shape.

Eight PR-sized slices with acceptance criteria (E1 is a pure refactor that must land alone; E5, the refusal, gates everything after it), plus an explicit out-of-scope list.

Part 4 — the strategic note

What Miranda gains, four things it must not promise, and the honest risk: herdr already ships --remote over SSH, a client/server split and a versioned protocol — every piece of a remote layer except the relay and the identity model.

Five open questions for review at the end of the spec.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KeiotDVE94wEzvc7wcvm1y


Note

Low Risk
Documentation-only change; no runtime, auth, or data-path behavior is modified.

Overview
Adds issue #107 design spec (docs/superpowers/specs/2026-08-31-engine-seam-herdr-design.md) — investigation and architecture only, no implementation.

The doc maps eight tmux-specific agent couplings (launch, FrameWindows snapshot, control RPC, R3 hooks, D4 grouped sessions, G1 guests, mir doctor, consumers) to engine-neutral capabilities, with file:line citations into today’s code.

It documents herdr 0.8.2 sandbox experiments (shared server focus → D4 unsupported; confined terminal session observe; events.subscribe push; viewport crop vs reflow; heuristic agent state) and gaps left unverified.

It specifies a future Engine interface + Caps, a tmux vs herdr capability matrix, no silent degradation (doctor, startup/HELLO, point-of-use errors), single interactive attach when PerAttachView is false, --engine selection/bootstrap rules, unchanged FrameWindows v2 with optional st, and E1–E8 delivery slices plus strategic risks and five review questions.

Reviewed by Cursor Bugbot for commit 9b43c09. Bugbot is set up for automated code reviews on this repo. Configure here.

Investigation and design for an Engine seam, so `mir up --engine herdr`
can work without pretending. Doc only; no production code.

Part 1 maps the eight tmux couplings on the agent side with file:line —
launch/--shell, the FrameWindows v2 snapshot, the ten-verb control
allow-list, R3's hook push, D4's grouped sessions, G1's mirror and rw
guests, doctor's checks, and every FrameWindows consumer — and states
each one's capability without naming a multiplexer.

Part 2 reports herdr 0.8.2 as measured in a contained sandbox, not as
read: two clients share one focus (a second viewer's tab and workspace
switches dragged the first viewer's screen), `terminal session observe`
is a genuinely confined output-only pane stream (injected input, resize
and scroll all had zero effect; a marker printed in another pane never
reached it), `events.subscribe` pushes layout and agent-state changes
with no hooks to install, and a small viewport is a crop rather than a
reflow whenever another client owns the geometry.

Part 3 specifies the Engine interface, a per-engine capability table,
and the refusals that keep degradation visible — including serving one
interactive attach at a time on an engine without per-attach views.
Part 4 is the strategic read, including the risk that herdr ships its
own remote layer.

Closes #107

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KeiotDVE94wEzvc7wcvm1y
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Aug 30, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-08-30T13:47:23.638256Z 9b43c09 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b43c0949d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +577 to +579
Order E1 → E2 → E3 → E4 → E5 → E6 → E7 → E8. E1 is pure refactor and must
land alone. E5 gates every later slice, because until the refusal exists a
herdr machine can be corrupted by a second viewer.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Gate herdr enablement on the attach refusal

Reorder the slices or keep the herdr engine inaccessible until E5 lands. In the specified order, E3 makes --engine herdr launchable and E4 adds focus-changing controls, while the second-attach refusal is deferred to E5; if these PR-sized slices are deployed independently, two Miranda clients can therefore share the server-global focus and disturb the first session—the exact corruption this paragraph says E5 prevents.

Useful? React with 👍 / 👎.

Comment on lines +529 to +532
- **Config isolation:** set `HERDR_SOCKET_PATH` explicitly under the Miranda
state dir rather than inheriting `$HOME/.config/herdr` — it avoids the
`sun_path` overflow measured in §2.0 and keeps Miranda's server out of the
user's own herdr session.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Connect to the user's existing herdr server

Do not unconditionally move HERDR_SOCKET_PATH into Miranda's state directory for the advertised existing-setup flow. The document establishes that the socket selects the herdr server/session, so this isolation starts or connects to a separate server with none of the user's existing workspaces, panes, or running agents; mir up --engine herdr would create a parallel empty setup rather than carry the session the user already has. Make isolation opt-in or provide an explicit way to select the existing socket.

Useful? React with 👍 / 👎.

Comment on lines +467 to +471
3. **The refusal.** A capability a feature needs and the engine lacks is an
error at the point of use with the engine named in it, never a quiet
no-op. `mir share --write` on an engine without `GuestWrite` says so and
exits non-zero. `runControl` refuses a view verb the engine cannot scope,
and the frame is answered with an error the strip renders.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Define a response path for rejected controls

Specify an agent-to-client response and its web handling before requiring the strip to render these errors. The current protocol makes FrameControl client-to-agent only (go/internal/noise/frame.go), RunAgentSession drops the result after dispatch, and the proposed Engine.Control returns only a local Go error; no defined frame carries that error back to web/src/app.js. Consequently, an unsupported herdr view verb would still look like a dead button rather than the promised visible refusal.

Useful? React with 👍 / 👎.

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved. Cursor Bugbot completed successfully with no findings that need human review, and no approval policy requires extra reviewers. No reviewers were assigned.

Open in Web View Automation 

Sent by Cursor Approval Agent: Pull Request Router and Approver

@frahlg
frahlg merged commit af461a2 into main Aug 30, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Engine seam: make Miranda carry herdr sessions, not only tmux

1 participant