{"slug": "legbar-live-ai-agent-sessions-beside-github-ci-in-one-terminal", "title": "Legbar – live AI agent sessions beside GitHub CI, in one terminal", "summary": "Legbar, a new open-source terminal tool from developer gmhoward9289-ops, displays live AI agent sessions and GitHub CI status side-by-side in one screen, merging data from the roost and leghorn discovery layers to prevent discrepancies. The tool, installable via pipx, pip, npm, brew, winget, or apt, supports Python 3.9+ and works on macOS, Linux, and Windows, with features like --json output and LEGBAR_* environment variables for configuration.", "body_md": "One screen for the whole fleet: **live agent sessions beside GitHub CI**, drawn\nfrom a single discovery layer so the two panes can never disagree.\n\n`roost`\n\nanswers *what are the models doing*. `leghorn`\n\nanswers *what are the\nrepos doing*. Both are true at once and neither view contains the other — so\nwatching a fleet has meant watching two windows and joining them by eye.\nlegbar draws both lanes on one canvas.\n\n```\nlegbar  5 sessions | 1 cursor | 1 need input | 15 ci red | 125k held | 18:37:00\n\nSESSIONS                                                    CI / PRS\n--------                                                    --------\ncc heron-ops-3c FB5  ###-------  32% needsinput  dev        X  roost          ci\ncc swamp-ops-ad OP5  ###-------  25% working     dev        X  roost          #56 ci: skip winget~\ncc heron-ops-16 FB5  #---------  10% working     dev        X  copilot-money~ Tests\ncc claude-10    OP5  #---------   8% idle        Claude     >  leghorn        release\ncu c5468eb1     -                  - idle        dev        .  leghorn        #61 checks pending\n```\n\nThe short ambient loop below is the same program, idling — which is how it spends almost all of its time:\n\nBoth are real legbar, unmodified, reading a staged fleet — see\n[demo/](/gmhoward9289-ops/legbar/blob/main/demo) for how it is built and how to re-record. The second contested\nrow is the one worth looking at: a Claude session and a **Cursor agent** in the\nsame working copy. Cursor writes no session marker and no claim, so a dashboard\nreading only Claude's session directory cannot see that collision at all.\n\n**SESSIONS** — every live agent on the machine. Claude Code sessions are joined\nby pid against `~/.claude/sessions/<pid>.json`\n\n, with model, context burn, and\nstatus read from the session's own JSONL transcript. **Cursor agents appear\ntoo**, marked `cu`\n\n— Cursor writes no session marker and no claim, so a fleet\nview that only reads Claude's session directory is blind to every Cursor agent\nrunning beside it.\n\n**CI / PRS** — GitHub Actions runs and open pull requests across every clone,\nwith failures pinned so a red build cannot scroll away.\n\n```\npipx install legbar\n```\n\nPython 3.9+, standard library only. Works on macOS, Linux and Windows.\n\nlegbar also publishes to a few other channels, picked automatically off the same release:\n\n```\npip install legbar                          # if you'd rather skip pipx\nnpm install -g legbar                        # Node's on the box already anyway\nbrew install gmhoward9289-ops/tap/legbar     # macOS / Linux\nwinget install gmhoward9289-ops.legbar       # Windows\n```\n\nDebian and Ubuntu can add the signed apt repo instead of a one-shot `.deb`\n\n:\n\n```\ncurl -fsSL https://gmhoward9289-ops.github.io/legbar/legbar-archive-keyring.asc \\\n  | sudo gpg --dearmor -o /usr/share/keyrings/legbar-archive-keyring.gpg\necho \"deb [signed-by=/usr/share/keyrings/legbar-archive-keyring.gpg] \\\n  https://gmhoward9289-ops.github.io/legbar stable main\" \\\n  | sudo tee /etc/apt/sources.list.d/legbar.list\nsudo apt update && sudo apt install legbar\n```\n\nWindows without a package manager: grab the frozen `.exe`\n\nzip from the\n[latest release](https://github.com/gmhoward9289-ops/legbar/releases/latest).\n\n```\nlegbar              # the full-screen view\nlegbar --once       # render one frame and exit (pipes, CI, screenshots)\nlegbar --json       # the joined state, for piping somewhere else\nlegbar --no-git     # skip git probing if it is ever slow\nlegbar --no-ci      # skip the gh sweep (offline, or when it is slow)\n```\n\nIn the full-screen view: `q`\n\nquit, `g`\n\ntoggle git probing, `r`\n\nrefresh now.\n\nEvery override is `LEGBAR_*`\n\n. The older `roost`\n\n/ `leghorn`\n\n/ `ccwork`\n\nvariable\nnames are still honoured, so an existing install keeps whatever it had\nconfigured; the new name wins when both are set.\n\n| Variable | Default | What it points at |\n|---|---|---|\n`LEGBAR_REPOS_ROOT` |\n`~/GitHub` |\nwhere the clones live |\n`LEGBAR_SESSIONS_DIR` |\n`~/.claude/sessions` |\nlive-session markers |\n`LEGBAR_PROJECTS_DIR` |\n`~/.claude/projects` |\nsession transcripts |\n`LEGBAR_CURSOR_HOME` |\n`~/.cursor` |\nCursor's agent transcripts |\n`LEGBAR_CURSOR_MAX_IDLE_SECS` |\n`86400` |\nhow far back a Cursor agent counts as live |\n`LEGBAR_BACKENDS` |\n`claude,cursor` |\nwhich discovery lanes run at all |\n\n**Cursor liveness is inferred, not probed.** A Claude row means *this process\nexists* (`os.kill(pid, 0)`\n\n). A Cursor row means *this transcript moved\nrecently* — Cursor writes no pid to join against. That is a weaker signal and\nit is labelled as one; `pid`\n\nis `None`\n\nfor Cursor rows rather than invented.\n\n**Cursor's project slugs are lossy.** The slug joins path parts with `-`\n\n, and\n`-`\n\nis legal inside a directory name, so `c-Users-me-dev-heron-ops`\n\nreads\nequally as `dev/heron/ops`\n\nand `dev/heron-ops`\n\n. legbar resolves each segment\nlongest-first against what actually exists on disk. A slug that resolves\nnowhere — another machine's checkout, a deleted clone — falls back to the\nnaive split rather than raising.\n\nBlock-drawing characters mojibake in the Windows console, so the context bars,\nthe pane rules and the status glyphs are all plain ASCII. Same constraint\n`roost`\n\n's sparklines and `leghorn`\n\n's tables are built around.\n\n```\n       ,__\n     _(o  \\__\n    /        \\\n   |  ======  |\n   |  ======  |\n    \\  ====  /\n     \\______/\n      ||  ||\n      ^^  ^^\n```\n\nlegbar reads transcripts and registries, and runs `git`\n\nand `gh`\n\nin read-only\nmodes. It never writes to a repo.\n\n—[roost](https://github.com/gmhoward9289-ops/roost)`top`\n\nfor Claude Code: per-session context burn, models, and the subagents a session spawned.— the repo lane on its own: sessions joined to worktrees and real git state, CI, and a commit feed.[leghorn](https://github.com/gmhoward9289-ops/leghorn)**legbar**— both lanes on one screen, over one discovery layer.\n\n`henhouse.py`\n\nis that discovery layer: sessions, transcripts, git, GitHub, and\nCursor. It is a working CLI in its own right (`python henhouse.py`\n\n).\n\nMIT", "url": "https://wpnews.pro/news/legbar-live-ai-agent-sessions-beside-github-ci-in-one-terminal", "canonical_source": "https://github.com/gmhoward9289-ops/legbar", "published_at": "2026-08-16 22:06:14+00:00", "updated_at": "2026-08-16 22:40:59.313103+00:00", "lang": "en", "topics": ["developer-tools", "ai-agents", "ai-tools"], "entities": ["gmhoward9289-ops", "Legbar", "roost", "leghorn", "Claude", "Cursor", "GitHub Actions"], "alternates": {"html": "https://wpnews.pro/news/legbar-live-ai-agent-sessions-beside-github-ci-in-one-terminal", "markdown": "https://wpnews.pro/news/legbar-live-ai-agent-sessions-beside-github-ci-in-one-terminal.md", "text": "https://wpnews.pro/news/legbar-live-ai-agent-sessions-beside-github-ci-in-one-terminal.txt", "jsonld": "https://wpnews.pro/news/legbar-live-ai-agent-sessions-beside-github-ci-in-one-terminal.jsonld"}}