← All entries
Web app

Board Explorer

Search, filter and slice a GitHub Projects v2 board — GitHub's own filter vocabulary made clickable, over Table / By Assignee / Timeline views.

Web app projects-v2searchtimelineboardreactcsvgraphql

◎ What it solves

A Projects v2 board can only be sliced the way its own UI allows, and any view of it is locked behind a token. This makes the board queryable, sliceable three ways, and shareable as a link.

⚠ Limitations & Risks

Every catalog entry must acknowledge at least one limitation or risk.

What it solves

A board is good at being a board. It is bad at being asked questions.

The columns are a fixed way of looking at the work, and anything cutting across them — which open items have no assignee and slip past this sprint, what does this person actually carry, what has dates and what is guesswork — either isn’t expressible or means scrolling and counting. There is no timeline. There is no export. And because reading Projects v2 requires a token, the view you worked out cannot be handed to anyone; you can describe it, or screenshot it, but you can’t send it.

Two things change that. The board is mirrored to public JSON by a scheduled job that holds the token, so no viewer needs one. And the whole view — query plus which of the three slices you’re on — lives in the URL, so “the thing I’m looking at” becomes a link. The query language is deliberately GitHub’s own vocabulary rather than an invented one, made clickable: every chip you press rewrites the same query string, which stays the single source of truth.

A board’s fixed columns versus a query, three views and a shareable link

Before: a board shows fixed columns, cross-cutting questions cannot be expressed, and the view cannot be shared because reading the board requires a token. After: a single GitHub-style query string drives Table, By assignee and Timeline views, and the whole state is a copyable link.

BEFORE — fixed columns onlyTodoIn progressDone“open, unassigned, slipping past this sprint?”⚠ not a question the board can be asked🔒 and the view needs a token to seeAFTER — one query, three views, one linkis:open no:assignee sprint:26.4GitHub’s own vocabulary — every chip rewrites this one stringTableBy assigneeTimeline🔗 copy this view⬇ CSV of exactly these rows

The board isn’t replaced — it’s mirrored to public JSON so no viewer needs a token, and the query plus the active view live in the URL. That is what turns “the thing I’m looking at” into something you can send someone.

What it does

Makes a Projects v2 board answerable. Three views over the same filtered set:

The interesting part is the query language: GitHub’s own filter vocabulary, made clickable. assignee: / author: / label: / milestone: / repo: / type: / reason: plus any board field by name, is:open|closed|merged|issue|pr|draft, no: / has:, - negation, comma-OR, repeated-qualifier-AND, quoting, and date comparisons like updated:>@today-7d. Clicking any chip anywhere rewrites the one query string — a single source of truth, no parallel filter object.

Also: / to focus search (like GitHub), a copyable link that encodes the full view state in the URL hash, and CSV export of exactly the filtered rows with every board field.

Where the data comes from

board-explorer.yml mirrors the board to JSON on the board-explorer/data branch every 6 hours (and on demand), using PROJECT_TOKEN_FOR_BOARD_READS. The app then only ever reads public JSON: commit-SHA raw URL → branch path → bundled public/data/ snapshot.

The generator talks GraphQL directly rather than using gh project item-list, which cannot return state, merged, label colours, avatars, milestone, timestamps or sub-issue progress. It is field-agnostic — fields are discovered via fields(first: 60), so adding a board column needs no code change in either the generator or the SPA.

Run it locally

cd board-explorer
npm install
npm run dev

# Offline: regenerate from a canned GraphQL bundle, and exercise the query grammar.
python3 board-explorer/scripts/test_generate.py
node board-explorer/scripts/test_search.ts