Gh
Skill andresd/jot-skills/gh
GitHub-only and Linear-only Claude Code skills that port the jot CLI loop — capture brain-dumps into well-formed tracker issues, decide what to work on next, and keep the backlog tidy. Each skill is a single SKILL.md invoked from inside Claude Code.
npx -y skills add andresd/jot-skills --skill ghAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Capture, triage, and plan work on GitHub issues from natural language, across one or many repos. Auto-triggers on phrases like "capture this:", "what should I work on next", "what's on my plate today", "tidy the backlog", "find duplicate issues", "all <X> bugs to @<user>", and explicit `/jot-gh <cmd>`, `jot:`, or `jot-gh:` prefixes. Use when the user wants to turn brain-dump text into a well-formed GitHub issue, decide what to work on next, run dedup/stale passes, or bulk-edit issues by natural-language intent. Requires the `gh` CLI authenticated via `gh auth login`.
SKILL.md
15.8 KB, as published. Nobody here has run it
jot-gh
A GitHub-only port of the jot CLI loop: capture brain-dumps into well-formed issues, decide what to work on next, and keep the backlog tidy — all through gh calls. No tracker abstraction (GitHub only), no licensing, no persistent SQLite. Auth is whatever gh auth status already provides.
When to invoke
Explicit (always invoke):
/jot-gh <command>— slash formjot: <command>orjot-gh: <command>— prefix form
Auto-invoke (use judgment, prefer explicit when unsure):
- "capture this: ..." / "capture: ..." / "log this: ..."
- "what should I work on (next)?" / "what's next?"
- "what's on my plate today?" / "what am I doing today?"
- "tidy the backlog" / "find duplicate issues" / "find stale issues"
- "(re)assign all <X> bugs to @<user>"
- "make all <X> issues P0/P1/P2/P3"
- "what does the backlog say about <topic>?"
Do NOT invoke for:
- General GitHub questions unrelated to issue triage ("what's the API for X?", "how do I fork?")
- Pull request review or code review (that belongs to other skills)
- Anything that does not touch the issue lifecycle (issues, labels, assignees, comments)
Prerequisites
Before any command, verify gh is authed:
gh auth status
If the exit code is non-zero, stop and tell the user:
Run
gh auth loginfirst. jot-gh uses yourghcredentials directly and does not store its own auth.
Also ensure jq is available for parsing gh --json output (command -v jq — error clearly if missing).
Repo resolution
Most commands operate on one repo at a time. To pick:
- If the user passed
--repo OWNER/REPO, use that. - Otherwise, run
gh repo view --json nameWithOwner -q .nameWithOwnerfrom the current directory — if it returns a repo, use it. - Otherwise, ask the user which repo via
AskUserQuestion. Offer the 3 most-recent repos fromgh repo list --json nameWithOwner --limit 10 -q '.[].nameWithOwner'as options.
Multi-repo flows (next by default, ask if no repo context): use gh search issues with --owner @me or assignee filters. Each issue carries its repo in the result; treat writes per-repo. Do not run tidy, assign, or reprioritize cross-repo — those are single-repo only.
Memory file: .github/jot.md
If .github/jot.md exists in the target repo, load it before any LLM-y step (extraction, ranking, dedup decision). It holds repo-specific rules: glossary, priority defaults, label conventions, "all bugs filed by @alice are P1", "anything tagged regression is P0", etc.
Read it via:
gh api "repos/OWNER/REPO/contents/.github/jot.md" --jq .content 2>/dev/null | base64 -d
Cap at ~4KB. If larger, take the first 4KB and tell the user the file was truncated.
Apply memory rules when:
- Extracting structured fields in
capture(priority, labels) - Ranking issues in
next - Deciding dedup similarity in
captureandtidy
If memory rules conflict with the user's explicit request in this turn, the user wins.
Cache: ~/.cache/jot-gh/
Cache recent issue digests at ~/.cache/jot-gh/<owner>__<repo>.json so next/tidy don't re-fetch 500 issues per invocation.
- TTL: 10 minutes. Compare file
mtimeto now; if older, refetch. - Bypass: any command with
--no-cache. - Miss path:
gh issue list --repo OWNER/REPO --state open --limit 200 --json number,title,labels,assignees,updatedAt,body,url→ write to cache file. - Cache is not load-bearing. Safe to delete at any time. Never treat a cached value as authoritative for writes — re-fetch before
gh issue edit.
Action log: ~/.cache/jot-gh/actions.jsonl
Every successful write appends one JSON line:
{"ts":"2026-05-20T10:00:00Z","cmd":"capture","repo":"andresd/jot","action":"created","number":42,"url":"https://github.com/andresd/jot/issues/42","inverse":{"op":"close","number":42}}
- Keep only the last 100 lines (trim head on each append).
- Used exclusively by
undo. - Skip the log for previews, dry-runs, and read-only commands.
Commands
capture <text>
Natural-language brain-dump → well-formed issue, with dedup check first.
Flow:
- Resolve repo. Load
.github/jot.mdif present. - Pull existing labels once:
gh label list --repo OWNER/REPO --json name --limit 100. - Extract 3–5 keywords from
<text>(noun phrases, key verbs). - Dedup search:
gh search issues --repo OWNER/REPO --state open --json number,title,body,url --limit 10 -- "<keywords joined with OR>" - Score top 5 candidates for semantic similarity vs.
<text>. If best score reads as "likely duplicate" (same bug/feature, not just same topic), surface that. - Extract structured fields, constrained by the existing-labels list and memory rules:
- title: concise, imperative for actions ("Fix login redirect loop"), declarative for observations ("Search returns 500 on empty query").
- body: original text, then a blank line, then
_Captured via jot-gh on YYYY-MM-DD._ - labels: pick zero-or-more from the existing labels. Always include exactly one of
P0|P1|P2|P3(defaultP2unless memory rules say otherwise). Include exactly one ofbug|feature|chore|docsif clear from text. - assignee: only if
<text>explicitly names a person via@handle.
- Preview via
AskUserQuestion:Create issue(default)Comment on dup #N(only if a dup was found)Edit fields firstCancel
- On
Create issue:
Append to action log withgh issue create --repo OWNER/REPO --title "..." --body "..." --label "P2,bug" --assignee @meinverse: {op: "close", number: <new_number>}. - On
Comment on dup #N:
Log withgh issue comment <N> --repo OWNER/REPO --body "<captured text>\n\n_Linked via jot-gh dedup._"inverse: {op: "delete_comment", number: <N>, comment_id: <id>}. - On
Edit fields first: ask which field (title/body/labels/assignee), update, re-prompt.
Do not invent labels that don't already exist on the repo. If the repo is missing P0..P3, tell the user and offer to create them (one-shot: gh label create P0 --color B60205 etc.).
next [--for @user] [--scope <filter>] [-n N] [--commit] [--repo OWNER/REPO]
Top-N ranked open issues with a one-line rationale per item. Defaults: --for @me, n=5, multi-repo.
Flow:
- List candidates:
# multi-repo (default) gh search issues --assignee @me --state open --json repository,number,title,labels,updatedAt,body,url --limit 100 # single-repo when --repo passed gh issue list --repo OWNER/REPO --assignee @me --state open --limit 100 --json number,title,labels,updatedAt,body,url - For each distinct repo in the results, load
.github/jot.md(cache the load per turn). - Rank by, in order:
- Priority label:
P0 > P1 > P2 > P3 > (none) jot-todaylabel present (boost)- Age (newer wins for
P0/P1, older wins forP2/P3) - Memory-rule hints
- Priority label:
- Output a numbered list. Each line:
[OWNER/REPO#N]prefix, title, priority badge, one-sentence rationale, then URL on the next line. - If
--commit: confirm via a singleAskUserQuestion(Commit these N to today / Cancel), then for each chosen item:
Log each.gh issue edit <N> --repo OWNER/REPO --add-label jot-todayinverse: {op: "remove_label", label: "jot-today", number: <N>}.
tidy [--repo OWNER/REPO]
Interactive backlog hygiene. Single-repo only (multi-repo tidy is too noisy).
Flow:
- Resolve repo.
- Fetch all open issues:
gh issue list --repo OWNER/REPO --state open --limit 500 --json number,title,labels,assignees,updatedAt,body,url. - Run four passes:
- dup — cluster by title+body similarity. Report any cluster of 2+, recommending the oldest as canonical and the rest to close-with-link.
- stale —
updatedAt > 30 days agoand not in an open milestone. Recommend close with comment, or labelstale. - stale-assignment — has assignee, no comment or edit in last 14 days. Recommend unassign and ping.
- missing-priority — no
P0|P1|P2|P3label. RecommendP2as default (or memory-rule default).
- Output a single numbered list (text mode — not
AskUserQuestion; tidy routinely produces 20+ findings):1. [dup] #42 looks like dup of #38 — close #42 with link? 2. [stale] #15 — no activity since 2026-04-12 (38d). Close with comment? 3. [stale-asn] #71 — @bob assigned 22d ago, no movement. Unassign? 4. [priority] #88 — missing P-label. Add P2? ... - Prompt the user in plain text:
Apply which? Reply with numbers (e.g.
1,3,5),all, orcancel. - Apply each accepted finding via the appropriate
gh issue edit/gh issue close/gh issue comment. Log every write.
ask <question> [--repo OWNER/REPO]
NL Q&A over the backlog with #N citations. Read-only.
Flow:
- Resolve repo (or stay multi-repo if none given).
- Search both open and closed:
gh search issues --repo OWNER/REPO --state all --json number,title,body,state,labels,closedAt,url --limit 30 -- "<keywords>" - Answer in 2–4 sentences. Cite each referenced issue as
[#42](URL)(markdown link). - No writes. No action log.
assign <NL intent> [--repo OWNER/REPO]
Bulk reassignment by natural language. Single-repo only.
Example intents:
- "all open auth bugs to @alice"
- "@bob's open issues to @carol"
- "everything labeled regression to @me"
Flow:
- Parse the intent into
{ label?, assignee_old?, assignee_new, state? }. If parsing is uncertain, ask viaAskUserQuestionwith the best-guess filter. - List candidates:
gh issue list --repo OWNER/REPO --state open --label "<label>" --assignee "<old_or_*>" --limit 200 --json number,title,assignees,url - Show the numbered candidate list (text mode).
- Prompt:
Reassign these to @<new>? Reply with numbers,
all, orcancel. Numbers SKIPPED will keep their current assignee. - For each chosen item, use TOCTOU best-effort:
- Re-read the issue (fresh, no cache).
- If
<new>is already assigned, skip with a note. - Else:
gh issue edit <N> --repo OWNER/REPO --add-assignee <new>(and--remove-assignee <old>if specified). - On HTTP 422/409 (concurrent edit), warn and continue.
- Log each.
inverse: {op: "set_assignees", number: <N>, assignees: [<prev list>]}.
reprioritize <NL intent> [--repo OWNER/REPO]
Bulk priority change by natural language. Single-repo only.
Example intents:
- "all launch-blocker label → P0"
- "all P3 bugs older than 90 days → close as stale" (this overlaps with
tidy; route totidyif the intent is hygiene, not promotion) - "@alice's open issues to P1"
Same flow as assign, but operating on P0|P1|P2|P3 labels:
- For each accepted item:
gh issue edit <N> --repo OWNER/REPO --remove-label "<old P>" --add-label "<new P>". - Log with
inverse: {op: "swap_label", number: <N>, from: <new>, to: <old>}.
status [--team] [--repo OWNER/REPO]
Default (no --team): list issues with jot-today label assigned to @me, across repos. Show priority and repo.
gh search issues --assignee @me --label jot-today --state open --json repository,number,title,labels,url
--team: list jot-today issues in the target repo across all assignees, grouped by assignee.
gh issue list --repo OWNER/REPO --label jot-today --state open --limit 100 --json number,title,assignees,labels,url
No writes.
clear-plan [--repo OWNER/REPO]
Remove jot-today from all issues currently labeled with it for @me.
Flow:
- List:
gh search issues --assignee @me --label jot-today --state open --json repository,number,url - Show count and titles. Confirm via
AskUserQuestion:Clear N items / Cancel. - For each:
gh issue edit <N> --repo OWNER/REPO --remove-label jot-today. Log.
undo
Reverse the most recent action within 24 hours.
Flow:
- Read
~/.cache/jot-gh/actions.jsonl(tail). - Find the most recent entry where
ts > now - 24h. If none, tell the user no recent action is reversible. - Show the action and its planned inverse via
AskUserQuestion:Undo / Cancel. - Re-read the affected issue's current state (no cache). If state has changed in a way that makes the inverse meaningless (e.g. issue already closed, label already gone), abort with a clear explanation rather than forcing it.
- Apply the inverse:
created #N→gh issue close <N> --comment "Reverted by jot-gh undo"closed #N→gh issue reopen <N>add_label X #N→gh issue edit <N> --remove-label Xremove_label X #N→gh issue edit <N> --add-label Xswap_label from=A to=B #N→gh issue edit <N> --add-label A --remove-label Badd_assignee U #N→gh issue edit <N> --remove-assignee Uset_assignees [list] #N→gh issue edit <N> --add-assignee <list...>after clearing currentcommented #N (cmt_id)→gh api -X DELETE "repos/OWNER/REPO/issues/comments/<id>"
- On success, remove the entry from the log. Do not chain undos — one
undoreverses one action.
help
Print one line per command above. No gh calls. No log.
Output conventions
- Cross-repo listings: always prefix items with
[OWNER/REPO#N]. Single-repo listings: prefix with#N. - Every write reports the resulting URL on the next line (fetch via
gh issue view <n> --repo OWNER/REPO --json url -q .urlif not already known). - No emoji in skill output unless the user uses emoji first.
gherrors surface verbatim — do not swallow them. Ifghexits non-zero on a write, stop the batch and report which item failed.
Confirmation patterns
- Single write (
capturecreate, single-itemassign,undo,--commit):AskUserQuestionwith Confirm / Edit / Cancel. - Multi-write (
tidy, bulkassign, bulkreprioritize,clear-plan): numbered text list, free-text reply (1,3,5/all/cancel).AskUserQuestiononly fits 4 options, so it does not scale here. - Read-only (
status,ask,nextwithout--commit): no confirmation.
Rate limits
gh handles auth and rate-limit retry on its own. Avoid hand-built pagination loops — use --limit and let gh paginate internally. If a write batch encounters a rate-limit error, stop, report progress so far, and tell the user to retry after the reset window shown in the error.
Anti-patterns
- Don't call the REST API via
curl/gh apiunlessgh issue/gh search/gh label/gh repocannot express the operation.ghhandles auth, retries, and pagination. - Don't batch writes without showing a preview first, even when the user said "go ahead" earlier in the turn — previews are cheap insurance against an LLM misparse.
- Don't invent labels that aren't already on the repo. If a needed label is missing, ask before creating it.
- Don't write to closed issues unless the user explicitly named the issue.
- Don't store any auth, tokens, or secrets.
ghis the source of truth. - Don't treat the cache as authoritative for writes — always re-fetch the issue before
gh issue edit. - Don't run
tidy,assign, orreprioritizecross-repo. They are single-repo by design. - Don't chain undos. One
undoreverses one action; if the user wants more, they invokeundoagain.