Skip to content

Adopt herdr as the session/TUI backend (remove tmux); yeschef becomes an orchestration layer#29

Merged
jakemassoth merged 2 commits into
mainfrom
herdr-tui
Jul 21, 2026
Merged

Adopt herdr as the session/TUI backend (remove tmux); yeschef becomes an orchestration layer#29
jakemassoth merged 2 commits into
mainfrom
herdr-tui

Conversation

@jakemassoth

@jakemassoth jakemassoth commented Jul 21, 2026

Copy link
Copy Markdown
Owner

What & why

Adopt herdr (an "agent multiplexer") as yeschef's session/TUI backend and remove the tmux backend entirely. yeschef becomes a thin orchestration layer: it keeps the git project model, the head-chef/line-cook doctrine, the prompt-file mechanism, and its CLI; herdr owns session management, the TUI, live agent-status detection, send/peek, restart, and attach. yeschef tui now just launches/attaches herdr's native UI.

This started as an investigation (docs/herdr-investigation.md, first commit) and — after the go-ahead — became the full migration. The herdr socket-API JSON contract was validated end-to-end against a throwaway server before any backend code was written.

Per the adopt decision, SQLite is kept as the durable ticket ledger (now storing herdr's workspace_id/pane_id). The "drop SQLite" idea remains a possible future step, out of scope here.

What changed

Backend (src/backend/)

  • TmuxBackendHerdrBackend: a herdr-shaped seam (ensure_server / create_workspace / run_in_pane / read_pane / list_workspaces / close_workspace / set_display_status / stop_server / attach).
  • Real impl shells out to herdr --session yeschef … (arm's-length CLI, exactly like tmux/git — never linked, which keeps herdr's AGPL at arm's length) and parses JSON with serde. Starts the headless server detached (setsid) so agents outlive the one-shot CLI. GitBackend unchanged — herdr has no project/git model.
  • Mock impl models workspaces/panes in memory for unit tests.

Orchestration (src/commands/orchestrate.rs)

  • spawn: git worktree → herdr workspace rooted at it → launch agent into the root pane → register the herdr ids (workspace rolled back on failure).
  • sendpane run; peekpane read; status joins the registry with herdr workspace list (STATE = herdr's live detected status, else gone); killworkspace close; tui/attachherdr --session yeschef.
  • restart bounces the herdr server — herdr restores workspaces and resumes supported agents natively (no more claude --continue special-case).
  • ticket status-set persists to SQLite and best-effort pushes display-only pane metadata; herdr detects live agent status itself.

State (src/store.rs): branches stores herdr workspace_id/pane_id instead of the tmux window name. SQLite retained.

Isolation: a named --session (override YESCHEF_HERDR_SESSION) isolates the brigade — the analog of the old private -L socket. tmux.conf deleted; check_host_deps checks git + herdr.

Flake: herdr (built from its pinned flake) is baked onto yeschef's PATH and added to the devShell + e2e runtimeInputs, replacing tmux; kept out of checks so nix flake check stays a from-source build.

Tests: e2e suite rewritten to drive a real herdr server per test, isolated by a unique session + a short XDG_CONFIG_HOME (herdr's sun_path socket limit), torn down on Drop. Dropped the tmux-specific window-reindex test.

Docs: DEVELOPMENT.md / AGENTS.md / README.md rewritten for herdr; docs/herdr-investigation.md annotated with what was implemented; obsolete tmux demo tapes/gifs removed.

Verification

  • nix flake checkall pass: fmt (rustfmt), nixfmt, lint (clippy -D warnings -D clippy::pedantic), test (55 unit tests).
  • e2e suite → 19/19 pass against a real herdr server (cargo test --test e2e -- --ignored).
  • Manual contract validation against herdr 0.7.4; server isolation verified (no leaked test servers).
  • No rebase needed — branch is on the current origin/main tip.

Notes / follow-ups

  • Licensing: herdr is AGPL-3.0-or-later + commercial. yeschef only invokes the herdr CLI (arm's-length) and the flake bakes the binary onto PATH — worth a deliberate signoff before distributing builds. See the investigation doc's Risks.
  • A fresh yeschef tui demo recording of herdr's UI is a nice follow-up (old tmux tapes were removed).

Evaluate replacing yeschef's tmux TUI/session layer with herdr
(github.com/ogulcancelik/herdr), an "agent multiplexer".

- docs/herdr-investigation.md: capability mapping (herdr cleanly subsumes the
  whole TmuxBackend, and improves on status detection, restart-with-resume, and
  worktree creation), an honest "can we drop SQLite?" assessment (the ticket
  registry is subsumable; the project registry + merged/gone branch
  classification are not), a phased migration plan, and risks (AGPL/commercial
  licensing is the big one — arm's-length CLI invocation only, human signoff
  before distributing).
- flake.nix/flake.lock: add herdr as a flake input and re-expose it as
  packages.herdr + apps.herdr so `nix run .#herdr` works. Built from herdr's own
  pinned flake (no `follows`); kept out of checks/devShell so the normal loop
  never compiles it. Verified: builds to herdr-0.7.4; `nix flake check` passes.

No yeschef sources touched; nothing links or depends on herdr yet.
yeschef is now a thin orchestration layer on top of herdr (the agent
multiplexer). The tmux backend is gone; herdr owns session management, the TUI,
live agent-status detection, send/peek, restart, and attach. yeschef keeps its
git project model, the ticket doctrine, the prompt-file mechanism, and — per the
adopt decision — SQLite as the durable ticket ledger.

Backend
- Replace the `TmuxBackend` trait with `HerdrBackend` (backend/mod.rs): a
  herdr-shaped seam — ensure_server/create_workspace/run_in_pane/read_pane/
  list_workspaces/close_workspace/set_display_status/attach + server lifecycle.
- Real impl (backend/real.rs) shells out to `herdr --session yeschef …` (arm's
  length, like tmux/git — never linked) and parses its JSON with serde. Starts
  the headless server detached (setsid) so agents outlive the one-shot CLI.
  `GitBackend` is unchanged (herdr has no project/git model).
- Mock impl (backend/mock.rs) models workspaces/panes in memory.

Orchestration (commands/orchestrate.rs)
- spawn: git worktree (as before) → herdr workspace at the worktree → launch the
  agent into its root pane → register the herdr ids; workspace rolled back on
  launch/register failure.
- send → pane run; peek → pane read; status joins the registry with
  `herdr workspace list` (STATE = herdr's live status, else gone); tui/attach →
  `herdr --session yeschef` (its native UI); kill → workspace close.
- restart bounces the herdr server: herdr restores workspaces and resumes
  supported agents natively (no more `claude --continue` special-case).
- ticket status-set persists to SQLite and best-effort pushes display-only pane
  metadata; herdr detects live agent status on its own.

State (store.rs): the `branches` table stores herdr `workspace_id`/`pane_id`
instead of the tmux window name. SQLite retained.

Isolation: a named `--session` (override `YESCHEF_HERDR_SESSION`) isolates the
brigade — the analog of the old private `-L` socket. tmux.conf deleted.

Flake: herdr (built from its pinned flake) is baked onto yeschef's PATH and in
the devShell + e2e runtimeInputs, replacing tmux; kept out of `checks` so
`nix flake check` stays from-source. `check_host_deps` now checks git + herdr.

Tests: e2e suite rewritten to drive a real herdr server per test, isolated by a
unique session + a short `XDG_CONFIG_HOME` (sun_path limit), torn down on Drop.

Verified: nix flake check (fmt, nixfmt, pedantic clippy, 55 unit tests) all
pass; e2e 19/19 pass against a real herdr server.

Docs: DEVELOPMENT.md/AGENTS.md/README.md rewritten for herdr; the investigation
doc is annotated with what was implemented. Obsolete tmux demo tapes removed.
@jakemassoth jakemassoth changed the title Investigate herdr as yeschef's TUI/session layer + make it runnable via the flake Adopt herdr as the session/TUI backend (remove tmux); yeschef becomes an orchestration layer Jul 21, 2026
@jakemassoth
jakemassoth merged commit 582fd70 into main Jul 21, 2026
2 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.

1 participant