Your Beads issues deserve a parade, not a spreadsheet.
Mardi Gras (mg) is a terminal UI for Beads, the issue tracker built for coding agents. It reads the same issues your agents write and shows them as a parade: what's rolling, what's lined up, what's stalled, and what's already past the stand. When something changes, the parade reshuffles in front of you.
One static binary. No daemon, no config file. Run mg in a Beads project and you're watching.
Every issue is on the route somewhere:
● Rolling in progress
♪ Lined Up open, and nothing is in its way
⊘ Stalled waiting on something that isn't done yet
✓ Past the Stand closed, folded away until you press c
The route is honest. A stalled row names what it's waiting on. Children nest under their parents. Overdue work says so, in red. The header keeps a running tally and a progress bar, and the footer tells you where the data came from and how fresh it is.
Blocked is computed from dependency edges, not from a status field somebody forgot to update. blocks and conditional-blocks count by default; widen that with --block-types if your project uses others.
Beads gives agents a durable memory of the work. bd list is fine for an agent. For a human doing morning triage, it's a wall of text.
The usual fix is a web dashboard or a kanban port. Mardi Gras takes a different view: work is motion. Things move, wait, get stuck, and pass. A parade shows that. Columns don't.
And if you're going to stare at your tasks every day, they should at least make you smile.
Homebrew (macOS and Linux)
brew install matt-wright86/homebrew-tap/mardi-grasGo
go install github.com/matt-wright86/mardi-gras/cmd/mg@latestMake sure
~/go/binis on yourPATHahead of/usr/bin. macOS ships a/usr/bin/mg(micro-emacs) that will shadow the binary otherwise.
Binaries for Linux, macOS, and Windows on amd64 and arm64 are on the Releases page.
From source
git clone https://github.com/quietpublish/mardi-gras.git
cd mardi-gras
make build # → ./mgYou need a Beads project. With bd on your PATH, mg talks to it directly. Without it, mg falls back to reading .beads/issues.jsonl.
cd your-project
mg| Key | What happens |
|---|---|
j / k |
Move along the route |
enter |
Open the detail pane for the selected issue |
/ |
Filter: free text, plus type:bug, priority:high, label:backend |
f |
Focus mode: your work and the top priorities, nothing else |
c |
Fold or unfold Past the Stand |
: or ctrl+k |
Command palette, with everything mg can do |
? |
Help overlay, paged by section |
q |
Leave the parade |
Press ? for the rest. The full keybinding reference lists every shortcut across the parade, detail pane, orchestrator panel, and overlays.
The detail pane renders an issue's description, design notes, and acceptance criteria as real markdown. It shows dependencies in both directions, an epic's progress through its children, comments and the timeline, how old the issue is, and when work on it started. With an orchestrator attached it also suggests a formula for the work and, on Gas Town, draws the molecule DAG with the critical path picked out.
Writes go through the bd CLI, so anything mg changes is exactly what an agent would see.
1claims the issue (assigns it to you, in progress),2sets it open,3closes it;!@#$set priority.Ncreates an issue,eedits it,radds a comment,yassigns it,tlabels it,llinks a dependency.bcopies a branch name for the issue;Bcreates and checks out that branch.spacebuilds a multi-selection; the status and priority keys then apply to all of it.3on a single issue closes it and claims the next ready issue in one step.Dopens abd doctoroverlay when something about the workspace looks off.
a starts an AI coding agent on the selected issue. Claude Code, Cursor, and OpenAI Codex are supported; mg picks the first one on your PATH, or you choose with --agent.
Inside tmux, the agent opens in a split pane beside the parade and mg remembers which pane belongs to which issue, so a again takes you back to it instead of starting a second one. A stops it.
M opens the Codex transcript in place of the detail pane; enter starts a session on the selected issue and K stops it. mg speaks Codex's app-server protocol directly (codex 0.115 or newer), streams messages, commands, and patches as they happen, and surfaces exec and patch approvals as a modal you answer without leaving the parade. r sends a follow-up prompt into the running session.
See the agent integration guide for runtime detection, tmux dispatch, and Codex specifics.
When an orchestrator is present, mg becomes a control surface for it. ctrl+g opens the panel: agent roster with live states, convoys, mail, cost dashboard, velocity, activity feed, and a problems view (p) that flags stalled agents, backoff loops, and zombie sessions. a slings the issue to an agent instead of opening a local one, s picks a formula first, n nudges the agent already on it, and C builds a convoy from an epic or a multi-selection.
Two backends are supported:
- Gas Town (
gt), the default. Everything goes through thegtCLI. - Gas City (
gc), an orchestration-builder SDK from the same org. mg speaks its Supervisor HTTP API. Roster, mail, formulas, sling, assign, nudge, decommission, and convoys work; a few Gas Town-specific views don't, and mg hides those rather than failing.
mg picks a backend from evidence on the machine:
MG_GC_APIis set → Gas City. You named it.- Any Gas Town evidence, a
GT_*env var orgtonPATH→ Gas Town. - No Gas Town evidence but Gas City evidence,
gconPATHor acity.tomlup the tree → Gas City. - Nothing conclusive → Gas Town.
MG_GC_API=auto discovers the running supervisor; MG_GC_CITY pins which city to drive. The Gas Town guide and Gas City guide cover each feature set, and the Gas City guide includes the capability matrix.
Jev is TypeSafe AI's System One model. It answers typed questions about a JSON snapshot (yes or no, pick one, a point on a scale) with a calibrated confidence, in well under a second. Set MG_JEV_API_KEY and mg uses it as a fast judge in places that are otherwise hand-written heuristics:
- Duplicate check on create. Submitting
Nasks whether the new issue is the same work as an existing one with an overlapping title. A strong match opens a dialog: jump to the existing issue, create anyway, or create and mark it a duplicate. - Focus order. Focus mode (
f) orders the ready list by how soon each issue should start and whether it can start now. A verdict without confidence never jumps the queue. - Formula choice. With an orchestrator, the FORMULA suggestion and the
spicker rank the formulas actually installed. - Codex approval advice. The approval modal shows Jev's risk reading of each command or patch. A static deny-list runs first and no verdict can soften it. Neither answers for you; there is no auto-approve.
Nothing is sent until you set the key, and with Jev off, slow, or down every feature reads exactly as it does without it. For an issue, what leaves the machine is a redacted snapshot (title, type, status, priority, labels, ages in days, and the start of the description), never people, notes, timestamps, or dependency IDs, with token-shaped strings scrubbed. Verdicts are cached per snapshot, so judging a 200-issue backlog costs about a fifth of a cent once. MG_JEV_URL points mg at a self-hosted, API-compatible server instead. The Jev guide covers each feature, exactly what is sent, cost, and what happens when Jev misbehaves.
mg # auto-detect the Beads project you're in
mg --path ~/proj/.beads/issues.jsonl # read a specific JSONL file
mg --block-types blocks,discovered-from # which dependency types count as blockers
mg --exclude-type epic,chore # hide issue types from the parade
mg --exclude-label gt:agent # hide issues carrying a label
mg --theme light # auto | dark | light
mg --agent codex # claude | cursor | codex
mg --agent-cmd ~/bin/agent-launcher # launch through a wrapper instead of the binary
mg --cmd-timeout 60 # seconds; scales every external command (default 30)
mg --no-animations # calm header, no confetti; good over SSH
mg --no-jev # skip the Jev judge even with MG_JEV_API_KEY set
mg --status # tmux status-line summary, then exit
mg --versionEvery option has an environment variable so you can set it once: MG_BLOCK_TYPES, MG_THEME, MG_AGENT_RUNTIME, MG_AGENT_CMD, MG_CMD_TIMEOUT, MG_NO_ANIMATIONS=1. MG_EVENTS=off keeps plain polling even when the bd events journal is on, and MG_BD_SERVE follows it through a running bd serve (see Live updates). MG_DEBUG=1 writes mg-debug.log in the current directory. MG_GC_API and MG_GC_CITY select the Gas City backend, as above. MG_JEV_API_KEY turns on the Jev judge, and MG_JEV=off is the same as --no-jev.
mg polls. No file watchers, no daemon, no background service.
- With
bdonPATH, it runsbd list --jsonevery 5 seconds and checks the source's health every 15. - Reading JSONL directly, it checks the file's modification time every 1.2 seconds.
Edits from agents, scripts, and bd commands all show up on the next tick. Your selection, filter, and fold state survive the refresh. Every issue that changed gets a ◈ mark for 30 seconds, whether its status, title, labels, dependencies or comments moved.
Faster with the bd events journal. bd 1.2.1+ can keep an ordered journal of every change made through bd. When a workspace has it on, mg checks the journal instead of reloading on a timer, and reloads only when something changed. While things are changing it checks every 2 seconds, so edits land in about two; after a quiet minute it relaxes to every 5, and an idle mg runs bd list twice a minute instead of twelve times, for less work than plain polling. The footer shows (cli ∿ live), and E opens Recent changes: what happened, to which issue, and who did it. Each issue's ACTIVITY section lists its own. Turn it on per workspace:
bd config set events-journal trueKnow what that does before you run it: it edits .beads/config.yaml (a tracked file), and from then on every bd command in that workspace, agents' included, writes a journal record. mg never turns it on for you. bd list keeps running every 30 seconds as a safety net for writes the journal can't see, such as bd dolt pull or programs using the beads Go library. If mg spots one, the footer adds partial and it falls back to the 5-second poll until things are quiet again. Under Gas Town or Gas City mg doesn't use the journal at all and keeps the 5-second poll, since orchestrator writes can bypass it. MG_EVENTS=off keeps plain polling.
Faster still with bd serve. bd 1.3.0's bd serve (a preview, for workspaces in Dolt server mode) streams the journal over HTTP. Point mg at it and, while the journal is on, mg listens to that stream instead of starting a bd process for every check. Changes usually land within a second, and an idle mg runs nothing but the 30-second bd list:
bd serve --addr 127.0.0.1:8181 # a fixed port; the default is a random one
MG_BD_SERVE=http://127.0.0.1:8181 mgIf the stream drops, mg goes back to checking through bd and reconnects on its own. If the server turns mg away (it wants a token, or serves a different workspace), mg says so once and stays on bd for the session. bd serve reads the journal setting when it starts, so restart it after turning the journal on.
mg's background reads (bd list, journal checks, detail fetches) run with BD_DISABLE_METRICS=1, so its polling isn't counted as bd usage; the writes it makes for you keep your own bd metrics setting.
mg ships a dark theme and a light one, and picks by asking the terminal for its background color. If your terminal doesn't answer, or you just want to be explicit, --theme light or MG_THEME=light settles it.
Status line. A compact, color-coded count of rolling, lined up, stalled, and closed issues:
set -g status-right "#(mg --status)"
set -g status-right "#(mg --status --path ~/myproject/.beads/issues.jsonl)" # a specific projectPopup. The whole parade on one key, sized to the terminal, in the current pane's directory:
bind m display-popup -E -w 80% -h 75% -d "#{pane_current_path}" "mg"Bubble Tea v2 for the Elm architecture, Lip Gloss v2 for the purple, gold, and green, Bubbles v2 for the viewports, and Glamour for the markdown. Single binary, no runtime dependencies, cross-compiled by GoReleaser.
The architecture overview explains how the pieces fit, including the driver seam that keeps orchestrators pluggable.
It is a lens on Beads. Beads stays the source of truth; mg never keeps state of its own, and everything it writes goes through bd.
It is not a project management system, not a kanban board, and not a sync layer. If you want those, Beads has an ecosystem. This is the part that makes you smile at 9am.
- Joy over minimalism
- Motion over columns
- Zero configuration
- Human-first visuals
- Beads remains the brain
The route is laid and the floats are rolling, but there's room for more krewes. CONTRIBUTING.md covers setup, the fake Gas Town and Gas City backends for local development, and conventions. Bug reports and PRs welcome.
Let the good tasks roll. ⚜

