Skip to main content

leghorn

ci discussions

What did this agent actually do?

That is the question leghorn exists to answer. A session tells you what it intended — the task it was given, its status, that it finished. Git tells you what landed. Only one of those two can be wrong, and it is never git.

So leghorn is a full-screen live dashboard you leave open on a second monitor while many Claude Code sessions work: every live session joined to its worktree and real git state, your GitHub CI and open PRs with failures pinned until they go green, and a commit feed across every repo, newest first. Every pane is there to close the gap between what an agent reported and what is actually in the tree.

leghorn watching a fleet: contested sessions, red CI, a session detail overlay, and the git toggle

The short ambient loop below is the same program, idling:

leghorn's ambient loop, sessions ticking quietly

 leghorn  20 sessions · 2 shared · 1 uncommitted · 3 ci red        sort:attention  filter:all  15:26:53
╭─ SESSIONS ───────────────────────────────────────────────╮ ╭─ COMMITS ──────────────────────────╮
│◉  leghorn-fea  my-mcp-server        Needs Input  72%     │ │   9m tools  fix/build-cwd          │
│●  session-a3   api-refactor         Idle         58%     │ │       fix(api): resolve paths agai…│
│●  session-d8   web-frontend  ~2 ↑1  Processing   50%     │ │  25m web-frontend  origin/ci/pub   │
╰──────────────────────────────────────────────────────────╯ │       Automate publishing on relea…│
╭─ GITHUB ─────────────────────────────────────────────────╮ │  29m api-refactor                  │
│ 17h ✗ my-mcp-server  Required PR Sections (fix/fields)   │ │       Add an in-program help panel │
│ 17h ✗ my-mcp-server  #593 Add field selection ← sections │ │  41m tools                         │
│ 17h ◍ tools          Graph Update (queued 17h)           │ │       Add a LOCAL MODELS panel     │
│ 23m ✓ web-frontend   ci (ci/npm-and-tap-publish)         │ │   1h api-refactor  origin/feat/rel │
│ 24m ✓ web-frontend   #18 Automate publishing  APPROVED   │ │       teach release_check to diff  │
╰──────────────────────────────────────────────────────────╯ ╰────────────────────────────────────╯
 q quit  r refresh  s sort  f filter  g git  tab pane  enter detail  ? help

Sessions that share a working tree are marked contested (◉) — two sessions in one checkout silently destroy each other's uncommitted work, and seeing it happen is the first step to not doing it. The GitHub pane ranks by what it costs to ignore: running first, then red (a failure must not scroll away), then stuck-in-queue, then everything else by freshness.

What each pane is for

Every pane answers one part of what did this agent actually do, and none of them takes the session's word for it.

SESSIONS — who is running, what they say they are doing, how much context they have burned, and the worktree each one is standing in. This is the only pane that reads the agent's own account of itself, and it is joined to real git state precisely so the account can be checked. A session reporting Idle in a tree with uncommitted changes is a different situation from one reporting Idle in a clean tree, and the session cannot tell you which it is.

GITHUB — the CI runs and open PRs the work is supposed to end in. An agent that says it finished and a build that is red are both true statements about the same change; this is where they meet.

COMMITS — what landed, across every repo, newest first. The plainest possible answer to the question: not a status, not a summary, the actual commit subjects in the order they happened.

Two files, stdlib only, Python 3.9+. macOS and Linux need nothing beyond the standard library; Windows needs windows-curses, which is the only thing curses is not already there for. Read-only by construction: it reads session transcripts, runs gh and read-only git plumbing, and never writes to a tree, a registry or a session. Every data source is optional — missing pieces degrade to a labelled gap, never an error.

Install

Homebrew (macOS and Linux):

brew install gmhoward9289-ops/tap/leghorn

npm (macOS and Linux only — use pipx on Windows):

npm install -g leghorn

pipx / pip:

pipx install leghorn

Debian and Ubuntu, from the signed apt repo — this also gets you apt upgrade:

curl -fsSL https://gmhoward9289-ops.github.io/leghorn/leghorn-archive-keyring.asc | sudo gpg --dearmor -o /usr/share/keyrings/leghorn-archive-keyring.gpg
echo "deb [signed-by=/usr/share/keyrings/leghorn-archive-keyring.gpg] https://gmhoward9289-ops.github.io/leghorn stable main" | sudo tee /etc/apt/sources.list.d/leghorn.list
sudo apt update
sudo apt install leghorn

Or grab leghorn_<version>_all.deb from the latest release and sudo apt install ./leghorn_<version>_all.deb.

What it needs

  • git — for the per-tree state and the commit feed.
  • gh (authenticated) — for the GITHUB pane. Unauthenticated, the pane says "cannot see github" rather than pretending nothing is happening; an empty feed and a feed that cannot see are different facts. Session status, context and burn are read from the JSONL transcripts Claude Code already writes under ~/.claude/projects (override: CLAUDE_PROJECTS_DIR) — no extra binary, and the same numbers on every platform. A session with no transcript yet degrades to a labelled gap.

Clones are discovered under ~/GitHub (override: LEGHORN_ROOT).

Usage

leghorn                  # three panes, refreshing every 5s
leghorn -i 2             # ...every 2s
leghorn --speed slow     # 5m session refresh, 6h gh sweep (also: ultra, fast, normal)
leghorn --no-github      # hide the GitHub pane (no gh calls at all)
leghorn --no-commits     # hide the commit feed; sessions and github go side by side
leghorn --github-interval 120   # slower gh sweeps

Keys: q quit · r refresh (including a gh sweep) · s/f cycle sort/filter · p cycle speed · c toggle commits · tab cycle panes · j/k move · enter detail · ? help — which explains what each screen and symbol means, not just the keys.

The data layer is also a command of its own:

python3 -m henhouse            # one table of sessions, for a hook or a pipe
python3 -m henhouse --github   # the CI/PR feed as plain text
python3 -m henhouse --json     # {"schema": "henhouse.session.v1", "rows": [...]}
python3 -m henhouse --json --legacy-json  # bare list (pre-v1 shape)

The transcript parsing library lives in the separate henhouse PyPI package for pytest-session-trace and other tools. Pin recorded sessions in CI with pytest-session-trace (pip install pytest-session-trace). This repo's henhouse.py is the live session table only — see docs/henhouse-ecosystem.md for how the names relate.

Name

The Leghorn is the chicken breed that spots everything first and is never quiet about it.

Questions or ideas?

Discussions

License

Apache-2.0

Release files for leghorn 0.4.16

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for leghorn 0.4.16
File Size Uploaded
leghorn-0.4.16.tar.gz 74.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for leghorn 0.4.16
File Interpreter ABI Platform
leghorn-0.4.16-py3-none-any.whl Python 3 none any Details

Total release size: 130.7 kB

Release files / leghorn-0.4.16.tar.gz

Download URL leghorn-0.4.16.tar.gz
Size 74.4 kB
Tags Source
SHA-256 checksum
How to use checksums
6e64f4eab256b83afdba55e03a4321e903392c2b84af552013946183acf4e108
BLAKE2b-256 checksum
How to use checksums
4dd37411bccdcc53c76f9b84d991718ac94ddffc931eabc2294f43d8ec9df2af
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / leghorn-0.4.16-py3-none-any.whl

Download URL leghorn-0.4.16-py3-none-any.whl
Size 56.3 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4c0bf5a074cbe4a7bba443565b31c9e935e1c595c8029c031048755aba26d28f
BLAKE2b-256 checksum
How to use checksums
dd5ea1c183d9a8407facb84910b16dc0fdd33d94bd7887e94152be19ee528c31
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.16 This release

2 release files

0.4.15

2 release files

0.4.14

2 release files

0.4.13

2 release files

0.4.12

2 release files

0.4.11

2 release files

0.4.10

2 release files

0.4.9

2 release files

0.4.8

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.3

2 release files

0.2

2 release files

0.1

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page