# Maestro A terminal-session orchestrator for one machine. One daemon per host owns every interactive shell or agent (Claude Code, opencode, plain bash) running on it; clients — CLI, TUI, browser — attach over a plain HTTP + WebSocket API. tmux for persistence, WebSocket for transport. ## Architecture ``` maestro daemon tmux wrapper + session API + SPA on 127.0.0.1:7070 ├── GET / browser SPA, embedded (feature `web`) ├── GET/POST /api/sessions list / spawn ├── DELETE /api/sessions/:id kill ├── POST /api/sessions/:id/input type text into a session ├── POST /api/sessions/:id/prompt an agent reports its first prompt (#131) ├── GET /api/info hostname, version, home dir, spawn presets ├── GET /api/dirs directory listing (spawn autocomplete) ├── GET /api/recent-dirs spawn history ├── GET /api/gitroot enclosing repo of a path ├── WS /api/events Snapshot + session deltas └── WS /api/attach/:id raw PTY bytes maestro list/spawn/attach/kill/send CLI client maestro tui ratatui client browser loads the SPA from the daemon, same port ``` **No authentication layer, no registry, no peer-to-peer.** Whoever can reach the daemon's bind address can drive every session on the host — same trust model as tmux itself. The operator picks the perimeter: `127.0.0.1` for local-only, a WireGuard/LAN address to share with their own devices, never a public IP. Every config field has a default, so `~/.config/maestro/config.toml` is optional. ## Where the work is Gitea issues on [`naps62/maestro`](https://git.naps.pt/naps62/maestro), grouped into milestones. `.claude/linear.json` (legacy filename, `tracker: gitea`) wires `/yolo` and `/work` to that tracker — they pick from open, unassigned issues whose dependencies are all closed. `/blitz ` sweeps a whole milestone. Labels carry one value per axis: `area/*`, `type/*`, `difficulty/*`. `difficulty` drives model selection downstream, so it tracks the shape of the work, not its size. ## Repo layout Cargo workspace. NAP-245 unified the per-binary crates behind a single `crates/maestro/` umbrella that ships the `maestro` binary with feature gates (`cli` / `daemon` / `tui` / `web`, default = all four). ``` crates/ ├── maestro/ # umbrella binary `maestro` (cli + daemon + tui, feature-gated) (NAP-245) ├── maestro-protocol/ # shared wire types (NAP-211) ├── maestro-config/ # shared on-disk config schema (NAP-233) ├── maestro-cli/ # `maestro list/spawn/attach/kill` dispatch (NAP-216) ├── maestro-daemon/ # `maestro daemon` — tmux wrapper + HTTP/WS API + SPA (NAP-212, NAP-214) ├── maestro-tui/ # `maestro tui` — ratatui session manager (NAP-275 epic) ├── maestro-installer/ # `maestro-install` wizard: cargo install + systemd (NAP-225) └── maestro-e2e/ # cross-process integration tests (NAP-217) web/ # browser SPA (NAP-218), embedded by the daemon's `web` feature flake.nix # Nix flake: packages, checks, dev shell, `nix run .#dev` nix/ # Home Manager module (`services.maestro`) ``` See `docs/INSTALL.md` for end-user install instructions. `docs/WORKTREES.md` is the contract for session worktrees — placement, collisions, what blocks a kill, and what `--force` leaves behind. Read it before changing anything that creates or removes one. `docs/SIDEBAR.md` is the contract for session cards in the web and TUI sidebars — line layout, activity colours, duration format, state precedence. Read it before changing sidebar rendering. `docs/RESTART.md` is the contract for what clients do when the daemon restarts or is upgraded under them — the build stamp on `/api/info`, the status indicator's states, the blocking overlay, grace and poll timings. Read it before changing reconnect behaviour on either client. `nix run .#dev` (or `just dev`) brings up the whole local stack under process-compose: a debug daemon on 127.0.0.1:7071, then Vite on :5173 once the daemon answers `/api/info`. The SPA proxies `/api/*` back to the daemon, so only the UI is exposed on the network. The dev port is deliberately not the daemon's own default 7070 (`devDaemonPort` in `flake.nix`), so the stack never fights a real daemon on the same host. ## Conventions - **TDD by default.** Failing test first, then minimal impl. Commit test + impl together. - **Frequent commits.** One logical unit per commit; don't pile work up. - **Conventional commits with `maestro` scope.** Example: `feat(maestro): add Hello message round-trip test`. - **`cargo fmt` + `cargo clippy --all-targets -- -D warnings`** before every commit. - **Integration tests use real `tmux` and `git`.** Don't mock them. Isolate via temp `$HOME` and `TMUX_TMPDIR`.