本文へ移動
cccskills
無料GitHub で公開

ticket-diagram

Attach a self-contained Excalidraw status diagram to a GitHub epic — read the epic + its sub-issue tree, render boxes-coloured-by-status with dependency arrows to a committed PNG that (a) renders on the GitHub mobile app and (b) has the editable Excalidraw scene embedded inside it, post it as a sticky comment, and round-trip human edits back in from a comment. Use when asked to "diagram an epic", "draw the ticket tree", "show the epic on mobile", "add a status graph to

インストール方法を見る

含まれるファイル(1)

  • SKILL.md10.2 KB

SKILL.md(原文)

インストールする前に、エージェントに与えられる指示の中身を確認できます。

Ticket diagram — an editable, mobile-legible status graph per epic

Turn a GitHub epic's sub-issue tree into a picture: boxes coloured by status, dependency arrows bound to the boxes, committed as a single PNG that renders in the issue/PR body on mobile and carries the editable Excalidraw scene embedded inside it — open that PNG in Excalidraw and you get the live scene to rearrange and hand back.

This is workstream #2 of the human-readable-tickets epic (#479) made concrete, tracked under epic #483. It reuses the sign-off / revision loop of #310 (the same loop ui-proposal and schema-review use): generate → post on the PR → iterate on feedback → approve.

Why Excalidraw + a PNG? Mermaid is disqualified: on the GitHub mobile app a ```mermaid block shows raw code + a perpetual "Loading" spinner (confirmed on #479). A committed PNG renders everywhere, including mobile, with no stall. The scene is embedded in the PNG (Excalidraw's own "Embed scene" format), so the image is also the editable source — no separate verbose .excalidraw file in the repo.

Artifacts (what gets committed)

Per diagram, in writeups/diagrams/:

  • <slug>.graph.json — the small, diffable semantic source (nodes + status + edges). This is the human-auditable record; git blame/diffs of what the epic is live here.
  • <slug>.png — the render + embedded editable scene in one file. Shows in the issue body on mobile; open it in Excalidraw to edit.

The loose <slug>.excalidraw is not committed (it's gitignored) — the scene rides inside the PNG. Pass --excalidraw to the generator only if you want a loose copy locally.

The pipeline (two halves)

  YOU (over the GitHub MCP)            the GENERATOR (deterministic, offline)
  ────────────────────────            ──────────────────────────────────────
  read epic + get_sub_issues   ──▶    scripts/ticket-excalidraw.mjs <graph.json>
  build the graph JSON                  → writeups/diagrams/<slug>.graph.json   (semantic source)
                                        → writeups/diagrams/<slug>.png          (render + scene embedded)

The split matters: the agent does the GitHub I/O; the script does the graph→artifacts step (no network at render time, byte-stable output → minimal diffs).

1 · Read the epic → build the graph JSON

For epic #NN: issue_read (get) the epic, then issue_read (get_sub_issues). For each child read its title, state (open/closed), labels (status:*), and any Blocked-by: #x, #y line in the body. Then build:

{
  "epic": 479,
  "slug": "make-tickets-human-readable",
  "title": "Make tickets human-readable",
  "feedbackUrl": "https://github.com/FriendlyInternet/nuxt-crouton/pull/487",
  "nodes": [{ "id": 454, "title": "Schemas + config", "status": "done" }],
  "edges": [{ "from": 454, "to": 455 }],
  "goal": { "label": "library-catalog.pmcp.dev" }
}
  • status per node — closed → done · label status:in-progress → in_progress · status:blocked → blocked · otherwise pending.
  • edges — Blocked-by: #x on child C ⇒ edge { "from": x, "to": C } (arrow points from blocker to dependent; the generator lays blockers above dependents).
  • goal (optional) — add it when the epic's acceptance is a concrete artifact (e.g. a preview URL). Every terminal node wires into it; it's coloured violet.
  • ref (optional, per node) — top-line label override (e.g. "W2") for nodes that aren't real issues, like an epic's workstreams before it's decomposed. Defaults to #<id>.
  • feedbackUrl (optional) — makes the diagram's footer a clickable "💬 Comment or send edits" link; pass the PR URL. Defaults to the epic issue URL.
  • slug — kebab-case; drives the filenames. Reuse the same slug every regeneration so the diff stays small and the sticky keeps pointing at the same files.

2 · Generate

node scripts/ticket-excalidraw.mjs /tmp/<slug>.graph.json --out-dir writeups/diagrams

Writes <slug>.graph.json + <slug>.png (PNG via the shared renderer .claude/skills/ui-proposal/render.mjs, headless Chromium — same as schema-review; the scene is then embedded into the PNG). Then commit both with /commit, referencing (#NN).

3 · Post the sticky comment & iterate (the #310 loop)

Post the PNG as a single sticky comment on the epic's PR, marked with an HTML anchor, and make the image a link that opens the scene in Excalidraw:

<!-- ticket-diagram:make-tickets-human-readable -->
### 🗺️ Epic diagram — Make tickets human-readable
![epic diagram](https://raw.githubusercontent.com/FriendlyInternet/nuxt-crouton/<branch>/writeups/diagrams/make-tickets-human-readable.png)

**✏️ To edit:** download this PNG and **open it in Excalidraw** — the scene is embedded, so it
opens live; drag boxes (arrows follow), then **export it (Embed scene ON) and attach the PNG to a
comment here**. I'll pull your edits back in.

_Revisions:_
- r1: initial

Reference the PNG by its raw.githubusercontent.com URL on the branch so it renders on mobile. The human reviews on the diff: they inline-comment, or they edit the scene and attach the exported PNG to a comment. Both are change requests. Ignore bot/self comments (user.type === 'Bot').

Approval = a comment containing approve/lgtm. (A 👍 reaction or a label does not resume the pipeline — only issue_comment triggers resume-on-comment.yml, #572.) On approval, mark the PR ready / merge per the epic flow.

4 · Round-trip a human edit back IN

When a human attaches an edited, scene-embedded PNG (or a .excalidraw) to a comment, grab its URL and run the importer — it decodes the scene, re-renders the PNG from that scene (so boxes they moved stay moved), re-embeds the scene, and writes the committed PNG:

node scripts/ticket-excalidraw-import.mjs <attachment-url-or-path> --slug <slug> --out-dir writeups/diagrams

Commit the PNG and refresh the sticky (append - rN: <what changed>). Pair this with subscribe_pr_activity: a comment with an attached PNG → run the importer → commit → done.

5 · Keep it current (it's a live view, not a one-shot)

When the epic's children change — a new sub-issue, a child closes, a Blocked-by edge changes — rebuild the graph JSON and regenerate. Same slug ⇒ the PNG updates in place and graph.json's diff shows exactly what moved semantically. (Regenerating from graph.json re-lays-out the boxes; if a human has hand-arranged the scene, prefer the importer in §4 to preserve their layout.)

Status palette

statuscolourmeaning
done🟩 greenchild issue closed
in_progress🟦 bluestatus:in-progress label
blocked🟥 redstatus:blocked label
pending🟨 yellowopen, not started
goal🟪 violetthe epic's concrete acceptance artifact

Files

  • scripts/ticket-excalidraw.mjs — CLI: graph JSON → .graph.json + scene-embedded .png.
  • scripts/ticket-excalidraw-import.mjs — CLI: an edited (scene-embedded) PNG / .excalidraw → re-rendered, re-embedded .png (the round-trip IN).
  • scripts/lib/excalidraw.mjs — pure emitters: layout() (layered DAG), toExcalidraw() (bound arrows + bound text + chrome), toSvg()/toHtml() (graph render), sceneToSvg()/sceneToHtml() (faithful render of an edited scene). No dependencies.
  • scripts/lib/excalidraw-png.mjs — dependency-free PNG metadata codec: extractScene() / embedScene() (Excalidraw's "Embed scene" tEXt format; Node zlib + manual chunk parsing).

Gotchas

  • The PNG is both the render and the editable source (scene embedded). Never put a client-rendered diagram (Mermaid/widget) in a GitHub body — it must be a committed image so it shows on mobile.
  • Editing = open the PNG in Excalidraw, not a #url= deep link — that needed a hosted .excalidraw, which we no longer commit. (If you want one-tap deep-link editing back, run the generator with --excalidraw, commit the loose file, and link https://excalidraw.com/#url=<raw url>.)
  • One-tap mobile editing = the hosted ticket-editor Worker (workers/ticket-editor, epic #483). Link …/?slug=<slug>&branch=<branch>&issue=<NN> — pass &issue=<NN> so each Save posts a new comment on issue NN with that edit's diagram (a timeline of versions, not just silent nuxt-harness[bot] commits). Requires the loose <slug>.excalidraw committed (generate with --excalidraw), since the editor reads it.
  • Pin a diagram image you want to stay put to its commit, not the branch. A raw.githubusercontent.com/<repo>/<branch>/…png URL re-renders whenever the file is later edited (so a "proposal" comment's picture drifts); …/<commit-sha>/…png is immutable and frozen. Post the proposal/sticky image pinned to the commit that produced it so the timeline reads correctly (the editor's per-save comments already do this).
  • Round-trip needs "Embed scene" ON in Excalidraw's export, or the importer can't find the scene (it errors clearly).
  • Reuse the slug across regenerations, or you'll orphan the old PNG and the sticky image link.
  • If the epic has no sub-issues yet, diagram its workstreams as ref-labelled nodes (e.g. W1…W5).

レビュー

まだレビューはありません。使ってみた感想をお寄せください。

同じリポジトリのスキル

概要と使いどころ

a11y

無料

Accessibility review for Vue surfaces — the code-cleaning analog of /code-review and /simplify, pointed at WCAG/ARIA. Reviews just your diff (or a package/file), rates findings by severity, and either comments inline on the PR (--comment) or applies the safe fixes for you (--fix). Steers the depth-aware `a11y` subagent. Use when asked to "check accessibility", "a11y this", "audit ARIA/keyboard", or run /a11y.

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月13日 更新

ask-human

無料

Emit a blocking question the owner can read in ~10 seconds and answer in one reply — the scannable, recommendation-first handoff every agent posts when it hits a fork it can't own. Leads with the one decision + a recommendation, carries the 🤖 provenance header, doubles as the

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月13日 更新

audit

無料

Audit packages for documentation completeness, detect drift between code and docs, and maintain documentation quality across the monorepo. Use when checking package docs, running audits, or reviewing documentation health.

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月13日 更新

Author a placeable layout block that looks right at ANY pane size. The one hard rule — size to the PANE with container queries (@container), never the viewport — plus list/form playbooks and the sizing contract (minWidth etc.) the viability metric reads. Use when adding/converting a croutonLayoutBlocks block, or when a block overflows/breaks in a narrow pane.

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月13日 更新

When a bug or regression is reported, the FIRST step — before fixing — is to research how and when it was introduced (git archaeology), then record that finding on the tracking issue/PR. Use the moment a bug, error, broken build, or "this used to work" is reported, before writing a fix. Produces a first-bad-commit (or "not a code regression") note you paste onto the issue.

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月13日 更新

commit

無料

Smart, granular git commits following monorepo conventions. Analyzes changes, filters to session-relevant files, groups by intent, and uses conventional commit format. Use when committing code changes.

日本語の概要は準備中です。原文の説明を表示しています。

FriendlyInternet/nuxt-crouton102026年10月13日 更新

FriendlyInternet のスキルをすべて見る

このスキルの問題を報告する