--- name: run-dot-agent-deck description: Run, build, smoke-test, and screenshot the dot-agent-deck binary against an isolated sandbox. Use when asked to "run dot-agent-deck", "launch the TUI", "take a screenshot of the dashboard", "verify the CLI smoke", or "test a change locally" against the dot-agent-deck binary. --- # Run dot-agent-deck `dot-agent-deck` is a Rust TUI/CLI that orchestrates terminal agent sessions: a `ratatui` dashboard talking over Unix-socket protocols to a `portable-pty`-spawned daemon. Day-to-day driving lives in `.claude/skills/run-dot-agent-deck/driver.sh` — it shells out the binary against a fresh tempdir sandbox (so it does NOT attach to the developer's real daemon and render their actual workflow), captures the dashboard with tmux, and verifies clean shutdown. All paths are relative to the repo root. ## Why a sandbox `dot-agent-deck` binds Unix sockets and `flock`s lock files at user-global paths (`$XDG_RUNTIME_DIR/dot-agent-deck/*`, fallback `$HOME/.cache/dot-agent-deck/`). If you launch the TUI without redirecting these: - It attaches to your already-running daemon and shows your real Claude sessions in the dashboard (verified — it picked mine up). - Or it contends on your daemon's lock files and fails to start. - `hooks install` rewrites your shell rc files. The driver redirects every relevant env var (`DOT_AGENT_DECK_SOCKET`, `DOT_AGENT_DECK_ATTACH_SOCKET`, `DOT_AGENT_DECK_LOCK_DIR`, `DOT_AGENT_DECK_STATE_DIR`, `DOT_AGENT_DECK_CONFIG`, `DOT_AGENT_DECK_SESSION`, plus `HOME`, `XDG_RUNTIME_DIR`, `XDG_STATE_HOME`) into a fresh tempdir per run, so the smoke is hermetic. ## Prerequisites ```bash apt-get install -y tmux # already present on this container ``` Rust toolchain via `rustup` (cargo 1.95+ / rustc 1.95+ verified). No other system libraries needed — the binary statically links `vt100`, `portable-pty`, `crossterm`, etc. ## Build ```bash cargo build --release ``` Release build because the TUI's render path benefits — debug builds visibly stutter. Optimized build takes ~25 s clean, ~1 s incremental. ## Run (agent path) — driver.sh ```bash ./.claude/skills/run-dot-agent-deck/driver.sh all ``` Subcommands: - `cli` — non-interactive surface only: `--version`, `--help`, `init`, `validate`. ~0.1 s. Right for PRs that touch the CLI or config-loading code paths. - `tui` — launches the dashboard under tmux, waits for first paint, saves a `capture-pane` screenshot, drives the `Ctrl+C` → `Enter` quit dialog, verifies the tmux session ends cleanly. ~1.5 s. - `all` — both, in order. Default. Output of a clean run: ``` == CLI smoke == dot-agent-deck 0.25.0 Created ./.dot-agent-deck.toml Config is valid. init + validate OK in sandbox project == TUI smoke == screenshot saved to /tmp/dad-screenshot.txt (40 lines) TUI exited cleanly OK ``` The screenshot lands at `/tmp/dad-screenshot.txt` (override with `DAD_SCREENSHOT=...`). A clean sandbox shows: ``` No active sessions. Press Ctrl+n to create a pane. ... [Back to Pane Ctrl+D] [New Pane Ctrl+N] [Close Ctrl+W] [Toggle Layout Ctrl+T] [Help ?] [Quit Ctrl+C] [Filter /] [Rename r] [Generate g] [Scheduled Tasks s] ``` The bottom rows are the persistent button bar (it replaced the old `Ctrl+n: new Ctrl+w: close …` status-bar legend), and it is mode-aware: the capture above is command mode, so the first button reads `[Back to Pane Ctrl+D]` and `[Close Ctrl+W]` is live. Inside a pane the first reads `[Command Mode Ctrl+D]` and `[Close Ctrl+W]` is dimmed, because `Ctrl+W` closes only from command mode. On a narrow terminal the bar wraps to more rows rather than dropping buttons. `No active sessions` is the signal that the sandbox is isolated — a non-isolated run would render whatever sessions your real daemon knows about. Override the binary path with `DAD_BIN=...` to smoke an alternate build (e.g. `target/debug/dot-agent-deck` for faster iteration). ## Run (human path) ```bash ./target/release/dot-agent-deck ``` Opens the dashboard against the user's REAL state — useful only as the developer running on a workstation with `hooks install`'d agent hooks. Useless headless. The driver above is the agent path. ## Test ```bash cargo test ``` ~1.5 minutes on this container; 800+ tests. Covers the daemon protocol, PTY orchestration, delegate dispatch, and F12 reattach paths — most PRs that touch internals are verified by `cargo test` alone, not by the driver. The driver is for the TUI/CLI surface and the screenshot artifact. Also gate before commit (per `CLAUDE.md` rules 2 and 5): ```bash cargo xtask affected-checks --run ``` It prints and runs what the change needs, stopping at the first failure. For a change with any Rust, build input or unmapped path in it, that is: ```bash cargo fmt --check cargo clippy --workspace --all-targets --features e2e,e2e-live -- -D warnings cargo test-fast ``` and for a change that is only mapped text (docs, skills, `changelog.d/`, `.github/`, PRDs, `CLAUDE.md` and the like), it is the xtask tests plus the root-package tests that read those files. Every clippy flag is load-bearing and CLAUDE.md rule 2 is the authority. `--all-targets --features e2e` per issue #407 and `e2e-live` per issue #502: without them the `tests/e2e_*.rs` files compile to empty crates (all of them without `e2e`, the real-agent ones without `e2e-live`), so clippy reports clean over code it never saw. `e2e-live` matters most of the four — it is the only thing in CI that type-checks the real-agent ones, because no test that reaches a real agent runs on a runner. `--workspace` per issue #436, or the `xtask/*` members are linted by no gate. ## Gotchas - **The dashboard renders YOUR sessions if you skip the sandbox.** The first time I launched the TUI without env-var overrides, it attached to my own running daemon and showed my live Claude pane inside its own pane. That's how I noticed the isolation problem. Always go through `driver.sh`. - **`Ctrl+C` doesn't quit — it opens a confirm dialog.** The dialog has `Stop / Cancel`. `Stop` is default-selected, so `Enter` confirms. The driver pauses 0.5 s between the two send-keys because the binary reads the dialog state synchronously between events; back-to-back sends drop one. - **Don't run two `driver.sh` invocations concurrently from the same shell.** Each gets its own tempdir, but they share `$$` (which seeds the tmux session name suffix in the script). Use separate shells if you need parallel smokes. - **Commands with embedded double quotes break `.dot-agent-deck.toml` basic strings silently** — the TOML parser returns an error and the role lookup falls through to "no respawn" with no visible signal in the TUI. Use TOML basic strings with `\"` escapes, or single-quote the TOML value if the shell command contains no `'`. The F12 e2e test in `tests/orchestration_delegate.rs` documents this. - **TUI may not exit cleanly under tmux smaller than ~24×80.** The Stop/Cancel dialog needs ~5 rows; on a tiny pane the dialog clips and the Enter doesn't land on the focused button. The driver uses 120×40. ## Troubleshooting | Symptom | Fix | |---|---| | `binary not found at .../target/release/dot-agent-deck` | `cargo build --release` first; driver intentionally does not auto-build (separates "build broke" from "binary broke"). | | `TUI did not render within 8s` | The dashboard's first frame depends on the daemon coming up. Increase the timeout, or run `target/release/dot-agent-deck` under `RUST_LOG=debug` outside the driver to see what's stuck. | | `TUI did not exit after Ctrl+C + Enter` | The Stop/Cancel dialog probably did not open — check the dumped `capture-pane`. If the dashboard is missing the bottom-row hotkey hint, the binary is in a broken state; rebuild. | | `Address already in use` from socket bind | A previous driver run left a stale socket. `rm -rf $XDG_RUNTIME_DIR/dot-agent-deck` if you set `XDG_RUNTIME_DIR` yourself; the driver's own tempdir gets cleaned by `trap`. | | `hooks install` modified my shell rc files | You ran `dot-agent-deck hooks install` without sandboxing. Restore from git or undo manually. The driver never runs `hooks install`. |