← Back to Mast · Docs · Overview Updated Apr 24, 2026 · v1.1
Documentation

Using Mast

Mast sits in your menu bar and shows every git repo on your machine — branches, upstream, dirty state, open PRs, live dev-server ports — plus the full git loop and a one-click handoff to Claude Code / Codex / Cursor. This doc walks through the parts.

Who this is for. Developers who already live in their terminal with lsof, git, and docker. Mast doesn't replace those tools — it correlates them into one row per repo.

Install

Recommended: Homebrew.

brew install --cask leonhoulier/mast/mast

Installs the signed, notarized Mast.app from the leonhoulier/mast-releases public repo.

Alternatively, download the .dmg directly from the latest release, open it, and drag Mast to Applications.

The mast companion CLI is not yet bundled into the DMG. For now, build it from the source repo: npm run build:cli && npm link.

Requirements

  • macOS 12 Monterey or later
  • Apple Silicon or Intel (universal binary)
  • ~187 MB disk, ~135 MB RAM idle

First scan

On launch, Mast performs its first scan. You'll see Waiting for first scan… for one to three seconds, then rows appear.

Scans run on a per-scanner cadence between 5 s and 30 s while the popover is open. Intervals are 5× longer when it's hidden, and scanning pauses entirely on sleep or lid-close — resumes on wake. Press R to force an immediate rescan.

The popover

The popover is 380×600. Top to bottom: header (status dot, app name, gear + info icons), search bar, Local header with repo count and refresh button, scrollable list of repos. One row per repo. No tabs.

Each row shows:

  • Status dot (gray / green / yellow / red, see FAQ)
  • Repo name with open-PR count badge when available
  • Branch → upstream, time since last commit
  • Dirty count (if any)
  • Sparkles icon → open in your AI agent
  • Primary action pill — Open :<port> when a dev server is listening, Start otherwise
  • Chevron to expand the row

Tabs were removed in v0.8. The old Ports / Repos / System tabs are gone — the Repos view is the whole popover. Ports still scan in the background and surface as Open :<port> pills on the row that owns them. System scanners (Docker, Homebrew, launchctl) still run but don't render UI in v1.1.

Row actions

Click a row's chevron to expand it. The expanded panel is grouped into three labeled sections: Git, Open, Info. Which verbs appear depends on repo state — a clean repo on its upstream shows fewer buttons than a dirty one with unpushed commits.

VerbSectionWhat it does
Open :<port>header pillOpens http://localhost:<port> in your default browser. Appears when a listening port correlates to this repo's cwd.
Startheader pillRuns npm / bun / pnpm / yarn run dev (fallback start) in a new Terminal at the repo. Flips to Open :<port> once the server binds.
Sparklesheader iconOpens the repo in your configured AI agent. See Open in AI agent.
StashGitgit stash push -u with a Mast-prefixed label. Recover with git stash pop.
CommitGitOpens an inline message editor (Enter submits, Escape cancels). Runs git commit -am "<msg>".
Push ↑NGitArm-fire. First click shows Confirm? Push ↑N, second click within 3s runs git push.
Pull ↓NGitAppears when behind. Arm-fire if the working tree is dirty (would otherwise fail).
FetchGitRead-only sync. No confirm.
UndoGitArm-fire. git reset --soft HEAD~1 — rewrites local history, keeps the diff staged. Only appears when ahead of upstream.
AmendGitArm-fire. git commit --amend --no-edit. Only appears when there are staged changes with no unstaged.
DiscardGit (danger)Arm-fire. git reset --hard HEAD && git clean -fd. On failure, git's stderr shows inline.
Create PRGitOpens github.com/<owner>/<repo>/compare/<base>...<branch>?expand=1 — PR form pre-opened. Appears when ahead of upstream + the remote is on GitHub.
Open in <Agent>OpenFull "Open in Claude Code / Codex / Cursor" pill. See Open in AI agent.
IDEOpenOpen the repo in your configured editor (VS Code, Cursor, Sublime, Zed, vim, etc. — whitelist-enforced).
FinderOpenReveal the repo folder in Finder.
GitHubOpenOpen the repo on github.com (when a GitHub remote is set).
Recent commitsInfoCollapsible preview of the last 5 commits via git log --pretty=format:%h%x09%s. Lazy-loaded on expand, cached 30s. Hash links to GitHub when available.

Full git loop

v1.1 landed the complete git loop inline. You can drive a repo from dirty → committed → pushed → PR without ever opening a terminal. The arm-fire pattern protects all four destructive / history-rewriting actions (Push, Discard, Undo, Amend): first click arms, second click within 3 s fires, otherwise it disarms itself. Shared with the useArmFire hook, consistent behavior across every button.

Git operations run their real commands — no wrappers, no intermediate tooling. git push uses your normal credentials. git commit uses your .gitconfig identity. Failure surfaces git's own stderr inline.

Open in AI agent

New in v1.0: every repo row has a sparkles icon (compact) and an Open in <Agent> pill (expanded) that hands the repo to your configured AI coding agent. Three agents supported:

AgentKindHow it launches
Claude CodeTerminalRuns claude in a new Terminal window at the repo's cwd.
CodexTerminalRuns codex in a new Terminal window at the repo's cwd.
CursorGUILaunches Cursor.app with the repo folder open.

Pick the default in Settings → Default AI Agent, or during the third step of first-launch onboarding. The agent's binary must be on your PATH; if it isn't, Mast returns a clear error with a link to the agent's install docs — no silent spawn failures.

Security. The agent list is a Zod enum ('none' | 'claude-code' | 'codex' | 'cursor') with a matching binary allowlist in the main process as defense-in-depth. The renderer can't pivot "Open in AI agent" into arbitrary command execution. Adding a new agent takes one enum entry + one registry row + one allowlist line.

Keyboard shortcuts

ActionKeys
Open popover M
Focus search F
Navigate rows
Open row in IDE
Refresh now R
Dismiss popoveresc

GitHub integration

Connecting Mast to GitHub unlocks three things: open-PR counts per repo, CI status (pass / fail / pending), and the Create PR button in the expanded row. It's optional — without a token, those slots just stay empty.

Create a personal access token

Mast works with either GitHub token type. Pick based on how much scope you want to grant:

Token typeRecommended scopesWhere
Fine-grained (recommended) Repository access: All repositories or select. Permissions: Pull requests: Read, Contents: Read, Metadata: Read (auto-included). github.com/settings/personal-access-tokens/new
Classic repo (single scope covers private + public read access). No other scopes needed. github.com/settings/tokens/new

Add the token to Mast

Two ways:

  • GUI: Settings → GitHub → paste the token. Mast validates it immediately with a GET /user call and refuses invalid tokens before saving.
  • CLI: mast setup github — same wizard, same validation, writes to the same settings file.

How the token is stored. Once the app is signed with Developer ID (v1.1+ builds are), the token is encrypted on disk via Apple's safeStorage API (Keychain-backed). The renderer process never sees the raw string — IPC redacts the settings payload to githubTokenPresent: boolean before it crosses the bridge.

What Mast queries

For each auto-discovered repo with a GitHub remote, Mast periodically runs:

  • GET /repos/<owner>/<repo>/pulls?state=open — open PR list
  • GET /repos/<owner>/<repo>/commits/<sha>/check-runs — CI status for HEAD

Scan cadence matches the git scanner (5-30 s open, 5× slower hidden). Rate-limit aware: if GitHub returns 403 / 429, Mast backs off until the reset time and surfaces a quiet warning in Settings.

Revoking access

Either delete the token on GitHub (it stops working immediately but the stale record stays in Mast) OR clear it from Settings → GitHub → Remove token. Both are safe.

Companion CLI

The mast CLI renders the Repos list as ANSI and drives git actions from the terminal — same state store, same per-repo mutex as the GUI, no duplicated code.

Install

Not yet bundled in the DMG. Build from the private source repo:

git clone https://github.com/leonhoulier/mast.git
cd mast
npm install
npm run build:cli    # → dist/cli/mast.js
npm link             # puts `mast` on PATH

Default output

$ mast
LOCAL                                          9 repos
  ● devdash              feat/v1.1-ai-and-git  1 dirty   :8765
  ● GA boss              main → origin/main · 2w  15 dirty
  ● leonhoulier-site     feat/LEO-8-india-tra  1 dirty   :3000
  ● watchatlas           main → origin/main · 1w  13 dirty
  ● Leonhoulier paperclip  main · 2w ago       clean

Verbs

CommandWhat it does
mastRepos list (default, matches the GUI).
mast overviewFull firehose: ports + processes + repos + services.
mast portsPort → process → repo chains.
mast processesProcesses grouped by project with memory.
mast servicesDocker, Homebrew, Launch Agents.
mast githubGitHub PRs and CI per repo.
mast watchLive-refresh every 10 s in place.
mast --jsonMachine-readable snapshot (pipe to jq).
mast stash <repo>git stash push -u
mast discard <repo> [--force]git reset --hard + git clean -fd--force skips the confirm prompt.
mast commit <repo> "message"Stages + commits. Stages all changes (git add -A) if nothing is staged.
mast push <repo>git push
mast log <repo> [-n N]Recent commits (default 10).
mast refreshForce an immediate git scan.
mast setupInteractive wizard (dev roots, editor, AI agent, GitHub token).
mast setup githubSet GitHub PAT only.
mast setup editor <name>Set default editor (whitelist).
mast configShow current settings (JSON).
mast config set K VSet a single config value.

Repo arguments accept an absolute path, a path relative to CWD, or a bare basename (e.g. mast stash devdash). Ambiguous bare names exit 2 with a list of matches.

MAST_SETTINGS=/custom/dir overrides the settings directory — the CLI and the app read the same JSON file, so GUI changes are visible in the CLI and vice versa.

Changelog

Condensed per-release history. Full notes: mast-releases on GitHub.

v1.1 — Full git loop + arm-fire everywhere 2026-04-23

  • New git actions inline: Pull, Fetch, Undo commit (soft-reset), Amend, Create PR (opens GitHub compare).
  • Arm-fire on Push: first-click confirm, second-click fires within 3 s. Matches Discard.
  • Discard migrated to the new shared useArmFire hook (no more inline setTimeout juggling).
  • Expanded row now groups actions into labeled sections: Git, Open, Info.
  • First-launch onboarding gains an AI-agent step (Claude Code / Codex / Cursor / None).

v1.0 — Open in AI Agent 2026-04-22

  • New Open in <Agent> button on every repo row. Three agents: Claude Code (Terminal), Codex (Terminal), Cursor (GUI). PATH preflight with install-doc fallback on missing binary.
  • Settings → Default AI Agent (Zod enum + binary allowlist as defense-in-depth).
  • Settings schema v5 → v6 migration: adds defaultAgent: 'none' to existing installs.

v0.9 — Installable CLI with git actions 2026-04-22

  • mast is now a standalone binary: npm run build:cli bundles to dist/cli/mast.js, npm link puts it on PATH.
  • New CLI git verbs: mast stash / discard / commit / push / log / refresh. All go through the same per-repo mutex as the GUI.
  • mast (no args) now prints the Repos list instead of the firehose — matches the GUI. Use mast overview for the old behavior.
  • Removed mast vps and mast setup vps * (ssh-vps scanner was unwired in v0.8).

v0.8 — Repos-only layout + Commit / Push inline 2026-04-22

  • Tab bar hidden. Popover is now a single scrollable Repos list. Ports still scan in the background and surface as Open :<port> pills; System scanners still run but don't render UI.
  • New Commit action with inline message editor, Push ↑N action on ahead repos.
  • Ahead/behind badge on repos with a GitHub remote is now clickable — opens the GitHub compare page.
  • Recent commits preview collapsible under each row (last 5 via git log, cached 30 s).
  • SSH VPS scanner unwired from the scheduler; no remote SSH processes spawn.

v0.6 — Start / Open pill, power-aware scanning 2026-04-22

  • Local repo rows get the Open :<port> / Start primary action pill.
  • Scanners pause on powerMonitor suspend / lid-close, resume on wake.
  • Minimum macOS 12 (Monterey). Drops Catalina + Big Sur.
  • LSUIElement=true — no dock icon flash, no cmd-tab entry.

Privacy & data

Everything runs locally. Mast does not phone home, does not collect telemetry, does not have an account system.

  • Ports + processes come from lsof, ps, launchctl.
  • Git data comes from shelling out to git in each repo.
  • GitHub PR + CI data, if enabled, uses a personal access token encrypted on disk via Apple's safeStorage. The renderer never reads the raw token — IPC redacts it to githubTokenPresent: boolean. See GitHub integration for how to create and revoke tokens.
  • AI agents launch via execFile with an enforced binary allowlist. Mast passes only the repo path; what you do inside the agent is between you and the agent.
  • Marketing site (usemast.sh) uses Google Analytics 4 with Consent Mode v2 — only if you accept the banner. Read the full usemast.sh privacy policy.

FAQ

Why not just use Activity Monitor?

Activity Monitor sees processes. It doesn't see ports, repos, PRs, or the AI agent you'd want to hand the repo off to. It can't tell you that the server on :4100 has drifted from the branch you thought you were on, or that you've got 3 unpushed commits while you're still refactoring.

Does Mast require root?

No. Everything Mast reads is readable by your user.

Will it drain my battery?

Scans are cheap and infrequent. When the popover is hidden, intervals stretch 5×. Power-aware pause suspends all scanners on sleep / lid-close and resumes them on wake, so there's no timer backlog firing at once.

How do I configure which directories get scanned for repos?

Settings → Repos → Scan roots. Default roots are ~/Developer, ~/Projects, ~/Code, ~/src, ~/repos, ~/work, ~/dev. Accepts globs.

What AI agents can I use with "Open in <Agent>"?

v1.1 ships with Claude Code, Codex, and Cursor. Adding a new one is intentionally cheap (one enum entry + one binary on the allowlist) — if you want a different agent supported, open an issue with the CLI name and install doc URL.

Can Mast commit and push for me?

Yes. Expand a dirty repo → Commit (inline message editor) → Push ↑N. Both use your normal git credentials. Push is arm-fire (click twice within 3 s to fire). If you're ahead of a GitHub remote, Create PR appears and opens the compare page with the form pre-opened.

Can I run Mast on Linux?

Not yet. The menu bar app is macOS-only. The CLI is node-based and should run anywhere node does, but it hasn't been tested outside macOS.

Troubleshooting

Popover is stuck on "Waiting for first scan…"

Quit Mast, relaunch. If it persists, check ~/Library/Logs/Mast/main.log — the most common cause is a missing lsof binary in your PATH.

"Open in <Agent>" shows "<agent> not found"

The agent's CLI binary isn't on Mast's PATH. Two common fixes:

  • Install the agent. The error popover links to the agent's install docs. For Claude Code: curl -fsSL https://claude.ai/install.sh | sh. For Codex: npm install -g @openai/codex. For Cursor: install Cursor.app first.
  • Confirm PATH. Open Terminal and run which claude / which codex. If it works there but Mast still complains, the binary is in a shell-rc-only PATH (~/.zshrc, ~/.bashrc) that isn't exposed to GUI-launched apps. Symlink it into /usr/local/bin or /opt/homebrew/bin.

GitHub PR counts aren't showing up

Three checks:

  • Settings → GitHub confirms a token is set (shows next to "Connected").
  • The repo has a GitHub remote (git remote -v shows github.com).
  • You haven't hit the GitHub rate limit — Mast surfaces a quiet warning in Settings if you have. Wait until the reset or swap to a fine-grained token for a higher ceiling.

Commit / Push / Pull failed with "git: command not found"

Mast shells out to git. It inherits PATH from the user's launch environment. If git --version fails in a fresh Terminal, install git (Xcode Command Line Tools: xcode-select --install) and relaunch Mast.

Push failed with "Permission denied (publickey)"

Mast doesn't manage credentials — it uses yours. The most common fix is SSH-agent not having your key loaded. Run ssh-add --apple-use-keychain ~/.ssh/id_ed25519 (or your key path) and retry.

Still stuck? Open an issue at github.com/leonhoulier/mast/issues with the contents of ~/Library/Logs/Mast/main.log.