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
Miguel PalhasandClaude Fable 5 bff0eddc12 feat(maestro): graphite TUI default + five accent presets
Replaces the army-green dark/light palettes with neutral graphite and
adds ice-cyan, periwinkle, amber-phosphor, ember and orchid presets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-09-02 16:06:31 +01:00

12 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 systemd unit, refreshes it, 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 TUI, gated by Cargo features.
  2. 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.

Nix / NixOS

The repo is a flake. It exposes two packages and a Home Manager module:

nix run git+https://git.naps.pt/naps62/maestro -- list   # the maestro binary
nix build git+https://git.naps.pt/naps62/maestro#maestro-web

packages.maestro is the unified CLI + daemon + TUI binary, wrapped so tmux and git are on its PATH. packages.maestro-web embeds a prebuilt SPA bundle — the Nix build points MAESTRO_WEB_DIST at packages.webFrontend, so build.rs skips pnpm entirely and no network fetch happens mid-compile. Set that variable yourself to reuse a bundle built elsewhere; leave it unset and the build falls back to running pnpm install && pnpm build in web/.

Home Manager, with both services running as user units (same trust boundary as the tmux server they wrap):

{
  inputs.maestro.url = "git+https://git.naps.pt/naps62/maestro";

  # in your Home Manager configuration:
  imports = [ inputs.maestro.homeManagerModules.default ];

  services.maestro = {
    enable = true;      # installs the binary, runs `maestro daemon`
    web.enable = true;  # runs `maestro-web`
    settings = {
      daemon.bind_addr = "127.0.0.1:7070";
      web.bind_addr = "0.0.0.0:8081";
    };
  };
}

settings is written verbatim to ~/.config/maestro/config.toml in the schema below; every field has a default, so {} writes no file at all. There is no auth layer — bind the web UI to a LAN or VPN address only on a trusted segment, never a public IP.

services.maestro.daemon.enable = false installs the CLI and TUI without running a local daemon, for a host that only talks to another machine's.

The daemon unit carries the same KillMode=process as the wizard-written one, so systemctl --user restart maestro-daemon leaves the tmux server and every session alive.

Thin builds for single-role hosts

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

# Daemon-only host — no CLI or TUI:
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. A bare maestro opens the TUI too — the missing subcommand defaults to tui (#119), so maestro --daemon-url http://host:7070 works as well. Builds without the tui feature have no UI to open and print help instead (exit 0). Drop the tui feature to skip it on hosts that don't need the UI surface (--no-default-features --features cli,daemon).

It talks to the local maestro daemon over http://127.0.0.1:7070 by default. 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]
theme = "dark"              # see the theme list below
leader = "ctrl-a"            # one byte that escapes Insert mode
chord_timeout_ms = 1000      # how long to hold a partial chord like `ctrl-w`

[tui.keymap.normal]
"i"            = "EnterInsert"
"s"            = "OpenSpawnModal"
"x"            = "KillHighlighted"
"r"            = "RenameHighlighted"
"?"            = "ShowHelp"
"ctrl-w h"     = "FocusSidebar"
"enter"        = "AttachHighlighted"
"pageup"       = "ScrollPanePageUp"
"pagedown"     = "ScrollPanePageDown"

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

theme selects the complete TUI palette. dark is the default: Maestro's graphite palette, near-neutral chrome where the activity colours are the only hue on screen; light is its light peer; ansi uses the terminal's named ANSI colours for terminals without truecolour. Five house presets recolour the graphite base with an accent, and the remaining presets adapt well-known editor themes — in both groups individual colours are lifted or darkened where they would fall short of the WCAG AA contrast floors the palette tests assert:

name based on
ice-cyan graphite base, signal-cyan accent
periwinkle indigo base, blue-violet accent
amber-phosphor warm graphite, CRT-amber accent
ember warm graphite, orange-red accent
orchid violet base, muted violet accent
solarized-dark Solarized Dark
solarized-light Solarized Light
catppuccin Catppuccin Mocha
github-dark GitHub Dark
github-light GitHub Light
tokyo-night Tokyo Night
gruvbox Gruvbox Dark
nord Nord
dracula Dracula

An unknown name is rejected as an [tui].theme configuration error.

The full action vocabulary is the Action enum in crates/maestro-tui/src/action.rs.

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 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. There is no authentication layer: anyone who can reach the bind address (of either the daemon or maestro-web) can drive every session on the host. Pick 127.0.0.1 for local-only, a WireGuard/LAN address for one-segment access, and never a public IP — the network perimeter is the only boundary Maestro has.

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-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-start the unit. 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.

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                  # foreground; or wire your own service manager

Every setting has a default, so ~/.config/maestro/config.toml is optional — create it only to change the bind address, spawn presets, or TUI keymap. (Worktrees live inside their base repos at <repo>/worktrees/<branch>; set [daemon].worktree_root only to override that.)

Non-Linux hosts

The wizard works on macOS for the cargo install part. 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.