Skip to content

feat: hand-drawn GitHub badges (library + MCP)#116

Merged
Ben Severn (benzsevern) merged 17 commits into
mainfrom
spec/github-badge-rendering
May 28, 2026
Merged

feat: hand-drawn GitHub badges (library + MCP)#116
Ben Severn (benzsevern) merged 17 commits into
mainfrom
spec/github-badge-rendering

Conversation

@benzsevern
Copy link
Copy Markdown
Collaborator

Adds a hand-drawn GitHub badge capability — both as a new library
component and as three MCP tools.

What's new

Library:

  • Badge component (src/components/Badge.tsx) — intrinsic-SVG, brand-aware
    via resolveBrand(props.brand) in the body (per the documented
    brand-without-context pattern for chart bodies). Optional hand-drawn icon
    glyph, five tone variants, sketchy Rough.js pill outline.
  • Icon stroke paths + tone palette + isBadgeTone / isBadgeIcon predicates
    in src/core/badgeIcons.ts.
  • Exports from both goldenchart entries.

MCP (goldenchart-mcp):

  • mcp/src/githubClient.ts — injectable fetch, 5-min TTL cache, in-flight
    promise dedup, optional GITHUB_TOKEN auth, typed GithubFetchError.
  • render-badge — literal label/value, no network.
  • render-github-badge — single GitHub metric (stars/forks/open-issues/
    release/license/last-commit/contributors/language/workflow), fetched with
    cache + dedup.
  • render-github-badge-row — N metrics composed into one SVG row, single
    HTTP roundtrip per unique endpoint, dedupes @font-face blocks.

Carry-forward:

  • New compare scenes in mcp/scripts/compare-agent-surface.mjs produce
    before/after renders under comparisons/ (no live network).

Verification

  • Library: npm run typecheck ✅ / npm run build ✅ / npm run check:bundle
    ✅ (47 KB gzipped, no font leak).
  • MCP: npx tsc --noEmit ✅ / filtered vitest 12/12 ✅.
  • CI runs the full vitest suite (local Windows OOMs on it per CLAUDE.md).

Out of scope

  • variant: 'shields' mode on Badge.
  • <BadgeRow> library component.
  • Remote SVG logo glyphs.
  • GitLab / Bitbucket clients.

Spec: docs/superpowers/specs/2026-05-28-github-badge-rendering-design.md
Plan: docs/superpowers/plans/2026-05-28-github-badge-rendering.md

Ben Severn (benzsevern) and others added 16 commits May 28, 2026 10:11
New design doc for hand-drawn Badge component, plus three MCP tools
(render-badge, render-github-badge, render-github-badge-row) backed by
an injectable GitHub client with TTL caching and optional GITHUB_TOKEN
auth.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Pin server-render path to goldenchart/server (not goldenchart).
- Drop useBrand() branch; always resolveBrand(props.brand) in body.
- Define RepoSummary/ReleaseSummary/WorkflowStatus shapes.
- Pin width constants, height (26), icon authoring contract (16x16, stroke-only).
- Clarify tone source: success/warn/danger fixed; neutral/info brand-derived.
- Add in-flight promise map for request dedup; document single-token-per-instance.
- Pin TTL precedence (option > env > default).
- Pin workflow label fallback order.
- Add mcp force-recopy step + LF-snapshot note to verification gates.
- Document bundle fallback if check:bundle fails.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
11 tasks: icons + tone table, Badge component (TDD), library exports,
GitHub client (cache + in-flight dedup + typed errors), MCP refresh,
three new MCP tools (badge / github-badge / github-badge-row), registry
wiring, compare carry-forward, full verification + PR.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- Add badgeIcons.test.ts to Task 1 Files header.
- Drop the .replace gimmick on tag glyph; define once cleanly.
- Fix (seed ?? 0) + i precedence in renderIcon.
- Math.ceil width in Badge so row regex never sees floats.
- Replace __client arg seam with module-level __setGithubClientForTests
  (SDK input validator might strip unknown args).
- Drop width: 0 lie; parse intrinsic width via shared parseSvgWidth helper.
- Add explicit 12.3k value assertion for stars test.
- Show full updated import block for Task 7 tests.
- Inline the <style>-dedup logic in row tool (was advisory).
- Pin Task 9 to mcp/src/tools.ts (spec wording was loose).
- PowerShell-correct chaining (semicolons) in Tasks 5 and 11.
- Replace bash heredoc with PS here-string + --body-file in Task 11.
- gh pr checks --watch for green verification.
- Task 5 prelude: verify src/core/text.ts does not import assets/fonts.
- Document workflow_id name-vs-id GitHub API caveat.
- Task 10: instructions for finding artifact path from prior carry-forward commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
tsup's sideEffects:false stripped re-exported tagged-string arrays
because Badge.tsx only consumed BADGE_ICON_PATHS / BADGE_TONE_COLORS.
Add isBadgeTone / isBadgeIcon type predicates that reference both arrays
at runtime so they survive into dist/. MCP tools (Task 6+) build Zod
enums from these arrays.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… workflow runs

Two findings from the whole-branch review:
- render-badge handler now wraps renderToSVGString in try/catch and returns
  isError:true with kind:'unexpected', matching the structured-error contract
  used by render-github-badge and render-github-badge-row.
- getWorkflowStatus's 'no runs' path was pairing kind:'not-found' with HTTP
  200 (the request succeeded, the list was empty). Use 404 as the sentinel so
  the structured error doesn't read 'not-found' with a 2xx status.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
let xOff = 0;
const inners = parts.map((svg, i) => {
let inner = svg.replace(/^<svg[^>]*>/, '').replace(/<\/svg>$/, '');
if (i > 0) inner = inner.replace(/<style\b[^>]*>[\s\S]*?<\/style>/g, '');
Comment thread mcp/src/badgeTools.ts
const widths = parts.map(parseSvgWidth);
const inners = parts.map((svg, i) => {
let inner = svg.replace(/^<svg[^>]*>/, '').replace(/<\/svg>$/, '');
if (i > 0) inner = inner.replace(/<style\b[^>]*>[\s\S]*?<\/style>/g, '');
@benzsevern Ben Severn (benzsevern) merged commit 4fe3c9d into main May 28, 2026
4 of 5 checks passed
@benzsevern Ben Severn (benzsevern) deleted the spec/github-badge-rendering branch May 28, 2026 15:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants