From 52f78d9fe39cd20afca4c05b83dd4b63400aceb1 Mon Sep 17 00:00:00 2001 From: Dominik Seemann Date: Wed, 6 May 2026 17:55:42 +0200 Subject: [PATCH] feat(claude): add /ticket and /ticket-list commands for GitHub Issues (Step 3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adapt the Notion onboarding prompt — originally Jira/MCP-oriented — to this project's actual issue tracker (GitHub at salestech-group/MiroFish) using the gh CLI. Slash commands (.claude/commands/): - /ticket : fetch a GitHub issue via gh, self-assign, try to add an in-progress label (skips silently if the label doesn't exist), and snapshot the issue (frontmatter + body) to .ticket/.md so later planning steps can read the description without refetching. - /ticket-list: interactive overview of issues; asks for filters (open/closed, status, assignee, milestone, labels) and runs a single gh issue list with the answers, rendering a compact markdown table. Workspace: - .ticket/repo.md declares the target repo (GitHub equivalent of the Jira "board.md" referenced in the prompt). - .gitignore: ignore .ticket/* except repo.md and .gitkeep so cached ticket markdowns stay local. Settings: - Allow-list gh issue view/list/edit/comment, gh repo view, gh pr view/list, gh auth status to avoid permission prompts. Documentation: .claude/onboarding/step3_planning/01_ticket_sync.md --- .claude/commands/ticket-list.md | 62 +++++++++++++++ .claude/commands/ticket.md | 68 ++++++++++++++++ .../step3_planning/01_ticket_sync.md | 77 +++++++++++++++++++ .claude/settings.json | 10 ++- .gitignore | 5 ++ .ticket/.gitkeep | 0 .ticket/repo.md | 8 ++ 7 files changed, 229 insertions(+), 1 deletion(-) create mode 100644 .claude/commands/ticket-list.md create mode 100644 .claude/commands/ticket.md create mode 100644 .claude/onboarding/step3_planning/01_ticket_sync.md create mode 100644 .ticket/.gitkeep create mode 100644 .ticket/repo.md diff --git a/.claude/commands/ticket-list.md b/.claude/commands/ticket-list.md new file mode 100644 index 00000000..242064ed --- /dev/null +++ b/.claude/commands/ticket-list.md @@ -0,0 +1,62 @@ +--- +description: List GitHub issues for this project with selectable filters +argument-hint: (no args — interactive) +--- + +# /ticket-list — Show GitHub issues for this project + +You are running the `/ticket-list` slash command. The user wants an overview of issues for the current project's GitHub repo so they can decide what to pick up next. + +## Repository + +Read the target repo from `.ticket/repo.md` (look for the `Repo (owner/name)` line). If the file does not exist, ask the user for the `owner/name` slug, write it to `.ticket/repo.md`, then continue. + +Set `REPO` to that value (e.g., `salestech-group/MiroFish`). + +## Filters — ask the user first + +Before running anything, ask which subset of issues to list. Offer these toggles (the user can answer in plain language; default any unanswered to "no"): + +1. **Include closed?** (default: no — open only) +2. **Status filter:** + - "todo" / "no assignee" — only issues that nobody is working on yet + - "in-progress" — only issues with the `in-progress` label or a self-assignee + - "all open" — no status filter +3. **Assigned to me only?** (default: no) +4. **Milestone / sprint:** the user can name a milestone, or skip +5. **Label filter:** optional comma-separated labels to require + +Wait for the user's answers before running `gh`. + +## Run the query + +Build a single `gh issue list` invocation from the answers. Useful flags: + +```bash +gh issue list --repo "$REPO" \ + --state open # or "all" / "closed" + --assignee "@me" # if "assigned to me only" + --label "in-progress" # if status=in-progress + --label "," # if user gave label filter + --milestone "" # if user named one + --limit 50 \ + --json number,title,state,labels,assignees,milestone,updatedAt,url +``` + +For "todo / no assignee" issues, GitHub doesn't expose a `--no-assignee` flag — list open issues without `--assignee` and **filter the JSON locally** to keep only items where `.assignees == []`. + +## Output + +Render a compact table (markdown) ordered by `updatedAt` desc: + +| # | Title | Labels | Assignees | Milestone | Updated | + +Truncate titles to ~70 chars; show `—` for empty fields. End with a one-line hint: *"Pick one: `/ticket ` to start work."* + +If there are no results, say so plainly and suggest relaxing a filter. + +## Constraints + +- Use `gh` exclusively. Do not call the REST API directly. +- Be conservative with output size — cap at 50 rows by default. +- Don't refetch on every minor question; ask once, then run once. diff --git a/.claude/commands/ticket.md b/.claude/commands/ticket.md new file mode 100644 index 00000000..d7f0ab0c --- /dev/null +++ b/.claude/commands/ticket.md @@ -0,0 +1,68 @@ +--- +description: Pull a GitHub issue into the local ticket workspace and mark it as in-progress +argument-hint: +--- + +# /ticket — Start work on a GitHub issue + +You are running the `/ticket` slash command. The user has typed: + +``` +/ticket $ARGUMENTS +``` + +Goal: pick up the GitHub issue identified by `$ARGUMENTS`, transition it to "in progress", and snapshot it as a markdown file under `.ticket/` so later steps (planning, implementation) can read its description without making more API calls. + +## Repository + +Read the target repo from `.ticket/repo.md` (look for the `Repo (owner/name)` line). If the file does not exist, ask the user for the `owner/name` slug, write it to `.ticket/repo.md`, then continue. + +Set `REPO` to that value (e.g., `salestech-group/MiroFish`) and use it explicitly in every `gh` command via `--repo "$REPO"`. + +## Steps + +1. **Validate input.** `$ARGUMENTS` must be a non-empty issue number (or a string GitHub will accept). If empty, ask the user for the issue number and stop. + +2. **Fetch the issue.** + ```bash + gh issue view "$ARGUMENTS" --repo "$REPO" \ + --json number,title,state,url,labels,assignees,milestone,author,createdAt,updatedAt,body + ``` + If this fails, surface the error and stop. Common causes: wrong number, no access, network. + +3. **Mark as in-progress.** GitHub Issues has no built-in "in progress" state. Approximate it: + - Self-assign: `gh issue edit "$ARGUMENTS" --repo "$REPO" --add-assignee @me` + - Try to add the `in-progress` label. If the label does not exist, do not create it — just continue without it. (`gh issue edit ... --add-label in-progress 2>/dev/null || true`) + - If the user indicates the project uses a different label or a GitHub Project with a status field, follow that instead. + +4. **Snapshot to `.ticket/.md`.** Write a markdown file with this structure (replace fields from the JSON above): + + ```markdown + --- + number: + title: + state: <state> + url: <url> + author: <author.login> + assignees: <comma-separated logins, "—" if none> + labels: <comma-separated names, "—" if none> + milestone: <milestone.title or "—"> + createdAt: <createdAt> + updatedAt: <updatedAt> + workingSince: <today YYYY-MM-DD> + --- + + # #<number> — <title> + + <body verbatim from the issue> + ``` + + This description is consumed by later planning steps — keep it intact. + +5. **Confirm to the user.** One short summary: ticket number, title, current state, what was changed (assignee, label), and the path to the snapshot. Don't dump the whole body back to the terminal. + +## Constraints + +- Use `gh` exclusively for GitHub. Do not call the REST API directly. +- Do not commit `.ticket/<number>.md` — the directory is gitignored except for `repo.md` / `.gitkeep`. +- Be quiet on success. Be loud on failure (state what failed and the next action). diff --git a/.claude/onboarding/step3_planning/01_ticket_sync.md b/.claude/onboarding/step3_planning/01_ticket_sync.md new file mode 100644 index 00000000..d7937d9e --- /dev/null +++ b/.claude/onboarding/step3_planning/01_ticket_sync.md @@ -0,0 +1,77 @@ +# Step 3 — Ticket Sync (GitHub Issues + gh CLI) + +## Date: 2026-05-06 + +## Tooling Decision (vs. the original Notion prompt) +The Notion prompt is Jira/MCP-oriented. For this project we use: + +- **Issue tracker:** GitHub Issues at https://github.com/salestech-group/MiroFish +- **Transport:** the `gh` CLI (already installed and authenticated as + `dseemann`). +- **No Atlassian MCP usage in these commands** — `gh` is faster, scoped + by token, and matches the rest of the team's Git workflow. + +Equivalences vs. the prompt: +- *"board.md"* → `.ticket/repo.md` (stores `owner/name`). +- *"IN ARBEIT" transition* → GitHub doesn't have a built-in + in-progress state; we approximate it with self-assignment + an + `in-progress` label (graceful fallback if the label doesn't exist). + +## What Was Created + +### `.ticket/` +- Directory created. Most contents are gitignored — only `repo.md` and + `.gitkeep` are tracked, so the local cache of in-progress tickets + stays out of the repo. +- `.ticket/repo.md` — declares `salestech-group/MiroFish` as the + target repo. +- `.gitignore` — added `.ticket/*` with negations for `repo.md` and + `.gitkeep`. + +### `.claude/commands/ticket.md` +Slash command: `/ticket <issue-number>` +- Reads the repo from `.ticket/repo.md`. +- `gh issue view --json …` to fetch the issue. +- Self-assigns (`gh issue edit --add-assignee @me`). +- Tries to add the `in-progress` label; silently skips if the label + doesn't exist on the repo. +- Snapshots the issue (frontmatter + full body) to `.ticket/<n>.md` so + later planning / implementation steps have the description without + re-fetching. + +### `.claude/commands/ticket-list.md` +Slash command: `/ticket-list` (interactive) +- Reads the repo from `.ticket/repo.md`. +- Asks the user for filters before running anything: + - include closed + - status (todo / in-progress / all open) + - assigned to me only + - milestone + - labels +- Builds a single `gh issue list` invocation from the answers. +- For "no assignee" filtering, post-processes the JSON locally because + `gh` has no `--no-assignee` flag. +- Renders a compact markdown table; ends with a hint to use + `/ticket <n>` to start work. + +### `.claude/settings.json` +- Allow-listed `gh issue view/list/edit/comment`, `gh repo view`, + `gh pr view/list`, `gh auth status` so the slash commands run + without permission prompts. + +## Verification +- `gh issue list --repo salestech-group/MiroFish --state open` returned + the open issue list (issue #1 currently open). +- `settings.json` parses as valid JSON. +- `gh auth status` confirmed (token: `ghp_…`, scopes incl. `repo`). + +## Limitations / Notes +- "In progress" semantics on GitHub Issues is convention-driven. If + the team adopts a GitHub Project (v2) with a Status field, update + the `/ticket` command to call `gh project item-edit …` instead of + the label/assignee approximation. +- Atlassian MCP setup from Step 0 is unused here. Leave it configured + for any cross-project Jira lookups. + +## Next +- Step 4: Planning (MANDATORY) — `/plan` command, persistence, hooks. diff --git a/.claude/settings.json b/.claude/settings.json index a9a1d7e2..91fe347d 100644 --- a/.claude/settings.json +++ b/.claude/settings.json @@ -22,7 +22,15 @@ "Bash(uv run:*)", "Bash(uv sync:*)", "Bash(docker compose:*)", - "Bash(docker-compose:*)" + "Bash(docker-compose:*)", + "Bash(gh issue view:*)", + "Bash(gh issue list:*)", + "Bash(gh issue edit:*)", + "Bash(gh issue comment:*)", + "Bash(gh repo view:*)", + "Bash(gh pr view:*)", + "Bash(gh pr list:*)", + "Bash(gh auth status:*)" ], "deny": [ "Read(*/.env*)", diff --git a/.gitignore b/.gitignore index 8a65db5c..62a40477 100644 --- a/.gitignore +++ b/.gitignore @@ -49,6 +49,11 @@ htmlcov/ .claude/.credentials.json .codegraph/ +# Ticket workspace — local cache of in-progress tickets +.ticket/* +!.ticket/repo.md +!.ticket/.gitkeep + # 文档与测试程序 mydoc/ mytest/ diff --git a/.ticket/.gitkeep b/.ticket/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/.ticket/repo.md b/.ticket/repo.md new file mode 100644 index 00000000..b6a3b69c --- /dev/null +++ b/.ticket/repo.md @@ -0,0 +1,8 @@ +# GitHub Issue Tracker for this Project + +**Repo (owner/name):** `salestech-group/MiroFish` +**URL:** https://github.com/salestech-group/MiroFish + +This file is the equivalent of "board.md" for the GitHub-based ticket +flow: it tells `/ticket` and `/ticket-list` which repository to query. +Update if the project moves.