`PairAttachVerifier` now stores `allow_inbound` behind `Arc<RwLock<_>>` so clones share the same set. Two triggers re-read the unified config file and swap it atomically: - SIGHUP — `systemctl --user reload maestrod`, or any `kill -HUP`. The installer's user unit now sets `ExecReload=/bin/kill -HUP $MAINPID`. - `POST /api/policy/reload` — used by `maestro policy reload`. The CLI reads `[daemon].bind_addr` from the unified config (default 7070) and POSTs to `http://127.0.0.1:<port>`. No PID lookup required. Also adds `maestro policy show [--json]` and `GET /api/policy` for "did my edit get picked up?" debugging. A broken mid-edit config logs an error and leaves the previously-effective list in place rather than locking everyone out. In-flight attaches keep their existing connection — revocation requires killing the session, as spec'd. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
6.9 KiB
Installing Maestro
The repo is private, so grab install.sh while signed in to gitea, then run it:
- 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 - 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 maestrod and maestro end 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 maestrod instead of start. No --update
flag needed.
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:
- Runs
cargo installformaestro-daemonandmaestro-cli(pinned to the committedCargo.lockvia--locked). - Optionally runs
maestrod configureto populate~/.config/maestro/config.toml(one shared TOML formaestrod,maestro-registry, and themaestroCLI). - On systemd hosts, optionally writes a user unit at
~/.config/systemd/user/maestrod.service, reloads systemd, and offers to enable + start it.
Both binaries land in ~/.cargo/bin — make sure that's on your $PATH.
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 maestrod.
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
maestrod.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 <crate>). |
--no-locked |
Drop --locked from cargo install (resolves a fresh dep tree). |
--exec-start <path> |
Override the systemd unit's ExecStart (default ~/.cargo/bin/maestrod). |
--no-systemd |
Skip the systemd step even if detected. |
--no-configure |
Skip the maestrod 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
maestrod 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.
Hot-reloading policy
[daemon.policy].allow_inbound (the list of peer daemons allowed to broker-
attach into this one) can be changed without restarting maestrod — restarting
would kill every live session. Two ways to apply an edit:
maestro policy reload # POSTs to the local daemon's /api/policy/reload
maestro policy show # prints the current effective list
kill -HUP <maestrod-pid> # equivalent; what `systemctl --user reload` does
Only newly-arriving attach attempts see the change — sessions already attached stay attached. To boot a live attacher out, kill the session.
What the systemd unit looks like
The wizard writes a user unit (systemctl --user), since maestrod runs
per-user and uses tmux sockets under $XDG_RUNTIME_DIR. Body:
[Unit]
Description=Maestro per-host daemon (maestrod)
Documentation=https://git.naps.pt/naps62/maestro
After=network-online.target
[Service]
Type=simple
ExecStart=%h/.cargo/bin/maestrod
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
Check status / logs:
systemctl --user status maestrod
journalctl --user -u maestrod -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-daemon
cargo install --git https://git.naps.pt/naps62/maestro --locked maestro-cli
maestrod configure
maestrod # foreground; or wire your own service manager
Non-Linux hosts
The wizard works on macOS for the cargo install + maestrod configure parts.
The systemd step is automatically skipped (probe of /run/systemd/system).
launchd integration is not yet supported — start maestrod from your shell or
your own service manager.