This repository has been archived on 2026-10-08. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
maestro/docs/INSTALL.md
T
naps62-yoloandClaude Opus 4.8 b6833ede43 refactor(maestro): drop allow_inbound policy gate, keep JWT session binding (NAP-339)
The peer (T2) attach path had a per-pair access-control layer
(`[daemon.policy].allow_inbound`): a target-side allow-list of daemon ids
permitted to broker-attach, enforced inside JWT verification, hot-reloadable via
SIGHUP / `POST /api/policy/reload`, with a `maestro policy` CLI. On a flat-trust
perimeter (the operator's VPN/firewall is the boundary for which hosts connect)
that granularity is unused, and deny-by-default made it config friction —
cross-daemon attach silently failed until every peer was listed.

Remove the allow-list; keep the registry-minted pair-attach JWT and ALL its
binding checks (iss=registry, aud=target, sid=session, exp). The firewall gates
host->port reachability; it does not stop a reachable host from attaching to a
session it wasn't handed or replaying a token elsewhere — that's the JWT's job
and it stays. Only the `sub in allow_inbound` check is dropped.

Removed: DaemonPolicySection / [daemon.policy].allow_inbound (config + daemon),
policy.rs (SIGHUP listener + GET/POST /api/policy), the `maestro policy` CLI,
PairAttachVerifier's allow-list field/reload/snapshot + JwtError::NotAllowed,
and the e2e broker_rejects_when_target_doesnt_allow_inbound test. The NAP-265
pre-upgrade-502 path stays covered by broker_attach_returns_502_on_perimeter_mismatch.

Also dropped the unit's ExecReload=kill -HUP: with no SIGHUP handler left,
default SIGHUP disposition is terminate, so wiring `systemctl reload` to it would
kill the daemon. Re-introducing a per-pair gate later is a verify-time change.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 07:07:55 +00:00

9.4 KiB

Installing Maestro

The repo is private, so grab install.sh while signed in to gitea, then run it:

  1. Open https://git.naps.pt/naps62/maestro/src/branch/main/install.sh, click Raw, save as install.sh. Or from any existing clone:
    git show origin/main:install.sh > install.sh
    
  2. Run it:
    chmod +x install.sh && ./install.sh
    

The bootstrap script builds maestro-installer into a temp directory, runs the wizard, and cleans up — only the unified maestro binary ends up persisted in ~/.cargo/bin.

Updating is the same command. Re-running ./install.sh detects an existing [daemon] section in ~/.config/maestro/config.toml and an existing systemd unit, skips the configure prompt, refreshes the unit, and runs systemctl --user restart maestro instead of start. No --update flag needed. The restart keeps your sessions: the unit sets KillMode=process, so systemd signals only the daemon — the tmux server (and every session) survives, and the new daemon re-adopts them on start. A unit written before this default lacks the line; re-run ./install.sh to refresh it.

Inside the script, cargo install --git https://git.naps.pt/naps62/maestro … uses your already-configured git credentials for this host (HTTPS helper or SSH agent). If only SSH is set up:

MAESTRO_REPO_URL=ssh://git@git.naps.pt/naps62/maestro ./install.sh

Pass flags through to the wizard after ./install.sh:

./install.sh --yes --no-systemd

The wizard:

  1. Runs cargo install for the unified maestro crate (pinned to the committed Cargo.lock via --locked). The same binary hosts the CLI, the per-host daemon (maestro daemon), and the always-on registry (maestro registry), gated by Cargo features.
  2. Optionally runs maestro daemon configure to populate ~/.config/maestro/config.toml (one shared TOML for the CLI, daemon, registry, and web).
  3. On systemd hosts, optionally writes a user unit at ~/.config/systemd/user/maestro.service, reloads systemd, and offers to enable + start it.

The binary lands in ~/.cargo/bin/maestro — make sure that's on your $PATH.

Thin builds for single-role hosts

The default install pulls in everything (cli + daemon + registry + tui). Single-role hosts can opt out of unused dependencies:

# Registry server — no tmux/PTY/jwt-verifier code:
cargo install --git https://git.naps.pt/naps62/maestro \
  --no-default-features --features registry --locked maestro

# Daemon-only host — no embedded web assets, no registry HTTP surface:
cargo install --git https://git.naps.pt/naps62/maestro \
  --no-default-features --features daemon --locked maestro

# CLI-only client (no local daemon, no TUI):
cargo install --git https://git.naps.pt/naps62/maestro \
  --no-default-features --features cli --locked maestro

The wizard always installs the default-feature build.

The terminal UI: maestro tui

maestro tui is the keyboard-and-mouse driven terminal UI client. It ships in the default feature set, so a vanilla cargo install maestro builds it. Drop the tui feature to skip it on hosts that don't need the UI surface (--no-default-features --features cli,daemon).

It talks only to the local maestro daemon over http://127.0.0.1:7070 by default; peer daemons reach you transparently via the catalog mirror. Override the daemon URL with --daemon-url or $MAESTRO_DAEMON_URL.

The [tui] section in ~/.config/maestro/config.toml (or whatever path you pass via the global --config flag) controls the keymap. Shipped defaults cover every v1 action — only override what you want to change:

[tui]
leader = "ctrl-a"            # one byte that escapes Insert mode
chord_timeout_ms = 1000      # how long to hold a partial chord like `g`

[tui.keymap.normal]
"i"            = "EnterInsert"
"s"            = "OpenSpawnModal"
"x"            = "KillHighlighted"
"?"            = "ShowHelp"
"ctrl-t"       = "NewTab"
"g t"          = "NextTab"
"ctrl-w h"     = "FocusSidebar"
"enter"        = "AttachHighlighted"

[tui.keymap.insert]
# (leader is added automatically as LeaveInsert; only override here when you
# want extra Insert-mode bindings)

The full action vocabulary lives in docs/superpowers/specs/2026-05-28-maestro-tui-design.md §3.8.

Adding the browser UI (optional)

maestro-web is a separate binary that serves the SPA bundle and reverse- proxies API calls to a co-located maestro daemon.

Interactive install (default path). The wizard now offers it as an optional step right after the daemon flow:

Optional: install the browser UI (`maestro-web`)?
Install maestro-web? [Y/n]

Press Y and it cargo installs maestro-web, drops a ~/.config/systemd/user/maestro-web.service unit (ordered after maestro.service), reloads systemd, and offers to enable + start it. Re-runs of ./install.sh detect the existing unit and refresh + restart silently.

Pass --no-web to skip the prompt entirely (headless hosts), or --yes with --no-web for non-interactive daemon-only installs. (Bare --yes without --no-web skips the web step too — opt in by re-running once interactively.)

Frontend build prerequisite. maestro-web embeds the SPA bundle at compile time, so before running the installer:

pnpm -C web install --frozen-lockfile
pnpm -C web build

Or just web from a workspace checkout.

Defaults. bind_addr = 127.0.0.1:8080, daemon_url = http://127.0.0.1:7070. The [web] section of ~/.config/maestro/config.toml overrides both — see crates/maestro-web/README.md.

Trust model. Anyone who can reach the bind address can use it. Pick 127.0.0.1 for local-only, a WireGuard/LAN address for one-segment access, never a public IP without adding auth first.

Headless hosts (servers, dev VMs) skip the prompt with --no-web. Hosts where you want browser access answer yes — both binaries end up in ~/.cargo/bin.

Flags

Flag Purpose
--git <url> Install from a different git repo (default: this one).
--branch <name> Pin a branch with --git.
--path <dir> Install from a local workspace checkout (--path + -p maestro).
--no-locked Drop --locked from cargo install (resolves a fresh dep tree).
--exec-start <path> Override the systemd unit's ExecStart (default ~/.cargo/bin/maestro daemon).
--no-systemd Skip the systemd step even if detected.
--no-configure Skip the maestro daemon configure step.
--no-web Skip the optional maestro-web install step.
--web-exec-start <path> Override the web unit's ExecStart (default ~/.cargo/bin/maestro-web).
-y, --yes Non-interactive: install binaries + drop systemd unit + reload + enable, but don't auto-run configure or auto-start the unit (those need real config). Also skips the web step unless an existing maestro-web.service is being refreshed.

Where tmux sockets land

maestro daemon defaults TMUX_TMPDIR to $XDG_RUNTIME_DIR (= /run/user/$UID) so a plain tmux ls in your shell — which typically uses the same env var — sees maestro-managed sessions. Override in ~/.config/maestro/config.toml:

[daemon]
tmux_tmpdir = "/tmp"

Pick /tmp if the daemon must outlive your login session and you can't run loginctl enable-linger (the runtime dir is wiped on logout, taking the tmux sockets with it). The env var MAESTRO_DAEMON_TMUX_TMPDIR takes precedence over the file.

Peer attach trust model

There is no per-peer allow-list. The operator's network perimeter (VPN/firewall) is the trust boundary for which hosts can connect; every daemon reachable on the perimeter may broker-attach to any other. Attach is still authenticated: the registry mints a short-lived, pair-scoped JWT bound to the target daemon and the specific session (iss/aud/sid/exp), which the target verifies — so a reachable host still can't attach to a session it wasn't handed, or replay a token elsewhere. (NAP-339 dropped the earlier [daemon.policy].allow_inbound gate; re-introducing a per-pair allow-list later is a verify-time change.)

What the systemd unit looks like

The wizard writes a user unit (systemctl --user), since maestro daemon runs per-user and uses tmux sockets under $XDG_RUNTIME_DIR. Body:

[Unit]
Description=Maestro per-host daemon
Documentation=https://git.naps.pt/naps62/maestro
After=network-online.target

[Service]
Type=simple
ExecStart=%h/.cargo/bin/maestro daemon
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5

[Install]
WantedBy=default.target

Check status / logs:

systemctl --user status maestro
journalctl --user -u maestro -f

Running the wizard without the bootstrap script

If you'd rather skip the script:

cargo install --git https://git.naps.pt/naps62/maestro maestro-installer
maestro-install

This leaves maestro-installer permanently in ~/.cargo/bin — the bootstrap script avoids that by installing to a scratch dir.

Fully manual install (no wizard)

cargo install --git https://git.naps.pt/naps62/maestro --locked maestro
maestro daemon configure
maestro daemon                  # foreground; or wire your own service manager

Non-Linux hosts

The wizard works on macOS for the cargo install + maestro daemon configure parts. The systemd step is automatically skipped (probe of /run/systemd/system). launchd integration is not yet supported — start maestro daemon from your shell or your own service manager.