Migrate runtime adapter from Zellij → tmux
Problem
The backend runtime is currently hardwired to Zellij. The daemon imports and instantiates zellij.Runtime directly with no abstraction layer:
backend/internal/daemon/daemon.go:16 — imports adapters/runtime/zellij
backend/internal/daemon/daemon.go:99 — creates runtimeAdapter := zellij.New(zellij.Options{...})
backend/internal/daemon/daemon.go:89-96 — zellij-specific socket dir handling (DefaultSocketDir(), ZELLIJ_SOCKET_DIR)
backend/internal/daemon/lifecycle_wiring.go:13 — imports zellij package
backend/internal/daemon/lifecycle_wiring.go:65 — startSession takes runtime *zellij.Runtime (concrete type, not interface)
backend/internal/daemon/lifecycle_wiring.go:130 — comments reference zellij.Runtime.SendMessage
The ports.Runtime interface (backend/internal/ports/outbound.go:79) only requires Create, Destroy, IsAlive — the contract is clean, but the wiring bypasses it by depending on the concrete zellij.Runtime type.
Goal
Replace Zellij with tmux as the terminal multiplexer runtime. This:
- Removes a hard dependency on Zellij (less common install base than tmux)
- Eliminates the macOS socket-path-length workaround (
DefaultSocketDir)
- Aligns with the upstream fork (aoagents/ReverbCode) which already completed this migration in #404
Scope
- New adapter:
backend/internal/adapters/runtime/tmux/ implementing ports.Runtime — tmux equivalents of Create (new-session), Destroy (kill-session), IsAlive (list-sessions), plus Attach/Stream/SendMessage.
- Abstract the wiring: Introduce a
runtimeselect (or similar) layer so daemon.go and lifecycle_wiring.go depend on ports.Runtime, not the concrete type. startSession should take ports.Runtime (or runtimeselect.Runtime), not *zellij.Runtime.
- Remove zellij-specific code: socket dir handling,
DefaultSocketDir(), zellij config/kdl handling, min-version checks (minMajor/minMinor/minPatch).
- Update tests: All
zellij_test.go references, fake runner patterns, etc.
- Docs: Update any references to zellij in docs/ and comments.
Reference
ReverbCode PR #404 "Zellij to Tmux and some other fixes" is a complete prior implementation of this exact migration. The tmux adapter there (backend/internal/adapters/runtime/tmux/tmux.go) can be used as the blueprint.
Migrate runtime adapter from Zellij → tmux
Problem
The backend runtime is currently hardwired to Zellij. The daemon imports and instantiates
zellij.Runtimedirectly with no abstraction layer:backend/internal/daemon/daemon.go:16— importsadapters/runtime/zellijbackend/internal/daemon/daemon.go:99— createsruntimeAdapter := zellij.New(zellij.Options{...})backend/internal/daemon/daemon.go:89-96— zellij-specific socket dir handling (DefaultSocketDir(),ZELLIJ_SOCKET_DIR)backend/internal/daemon/lifecycle_wiring.go:13— importszellijpackagebackend/internal/daemon/lifecycle_wiring.go:65—startSessiontakesruntime *zellij.Runtime(concrete type, not interface)backend/internal/daemon/lifecycle_wiring.go:130— comments referencezellij.Runtime.SendMessageThe
ports.Runtimeinterface (backend/internal/ports/outbound.go:79) only requiresCreate,Destroy,IsAlive— the contract is clean, but the wiring bypasses it by depending on the concretezellij.Runtimetype.Goal
Replace Zellij with tmux as the terminal multiplexer runtime. This:
DefaultSocketDir)Scope
backend/internal/adapters/runtime/tmux/implementingports.Runtime— tmux equivalents ofCreate(new-session),Destroy(kill-session),IsAlive(list-sessions), plusAttach/Stream/SendMessage.runtimeselect(or similar) layer sodaemon.goandlifecycle_wiring.godepend onports.Runtime, not the concrete type.startSessionshould takeports.Runtime(orruntimeselect.Runtime), not*zellij.Runtime.DefaultSocketDir(), zellij config/kdl handling, min-version checks (minMajor/minMinor/minPatch).zellij_test.goreferences, fake runner patterns, etc.Reference
ReverbCode PR #404 "Zellij to Tmux and some other fixes" is a complete prior implementation of this exact migration. The tmux adapter there (
backend/internal/adapters/runtime/tmux/tmux.go) can be used as the blueprint.