-
Validate N. Parse the positional argument. Reject if missing, non-integer, <= 0, or > 8 — ask the user rather than silently capping. Never default to a value the user did not provide.
-
Resolve the current GitHub user: USER=$(gh api user -q .login). Use that login as the assignee filter and never hardcode a username.
-
Fetch open curation issues assigned to the user.
gh issue list \
--assignee @me \
--state open \
--label curation \
--json number,title,assignees,body,createdAt \
--limit 100
The --label curation filter is what restricts to "new disease curation requests" — issues filed by /claim-disease carry the curation,enhancement labels and the title pattern Curate <label> (<MONDO_ID>). If a contributor opens curation issues with a different label, document it in this skill rather than relaxing the filter.
-
Filter to sole-assignee issues. Drop any issue whose assignees array has more than one entry. The user explicitly wants solo work — an issue assigned to both alice and bob is a team task, even if the current user is alice. Do this filter in jq, not by hand:
jq '[.[] | select((.assignees | length) == 1)]'
-
Filter out issues with an existing PR. For each remaining issue number ISSUE_NUM, check the authoritative GitHub linkage on the issue itself:
gh issue view "${ISSUE_NUM}" --json closedByPullRequestsReferences \
-q '.closedByPullRequestsReferences | length'
Skip the issue if the count is non-zero. A merged PR usually means the issue should already be closed, but stale links happen — be conservative.
Do NOT use gh pr list --search "closes #${ISSUE_NUM}" as a forward check. GitHub's free-text search matches the literal string #${ISSUE_NUM} anywhere in PR body or commits, including unrelated occurrences like ORPHA:${ISSUE_NUM}. This produced a false positive in production on issue #2704 (Orphanet ID ORPHA:2704 in PR #1992's body matched #2704). closedByPullRequestsReferences is structured GitHub linkage and avoids the trap.
If closedByPullRequestsReferences is rejected as an unknown field by the local gh version, upgrade gh rather than falling back to the lossy text search.
-
Sort and pick. Sort the survivors by number ascending (oldest issue first — that's the conventional FIFO for a curation queue) and take the first N. If fewer than N survive, do not pad — report the shortfall in the final report.
-
Extract the disease label and MONDO ID from each title. Issue titles follow Curate <label> (<MONDO_ID>). Parse with a regex; if a title does not match (e.g. an old hand-filed issue), skip it and note it in the final report rather than passing a garbled label to /curate.
-
Run duplicate preflight for each picked issue. Before dispatch, verify the
disease is still absent from the latest upstream KB and is not already
covered by another PR or issue:
git fetch origin main
git grep -n -i -e "<MONDO_ID>" -e "<label>" origin/main -- kb/disorders || true
gh pr list --repo monarch-initiative/dismech --state all \
--search "\"<MONDO_ID>\" OR \"<label>\"" \
--json number,title,state,url,headRefName --limit 100
gh issue list --repo monarch-initiative/dismech --state all \
--search "\"<MONDO_ID>\" OR \"<label>\"" \
--json number,title,state,url,labels --limit 100
The current issue itself is expected in the issue search results. Skip the
candidate if the KB, another PR, or another issue already covers the same
disorder, and report the skip.
-
Dispatch /curate in parallel. In a single message, launch N Agent tool calls — one per disease — using subagent_type: general-purpose so each agent has full tool access (Tools: *). claude works too on harnesses that register it as a catch-all type, but general-purpose is the canonical name across harnesses; prefer it for portability. Each agent's prompt MUST:
-
State the disease label and MONDO ID verbatim.
-
State that the duplicate preflight against latest KB, all PRs, and all
issues has already been performed, and tell the agent to repeat it before
writing files if its worktree is created later from stale refs.
-
Quote any deep-research provider hints from the issue body (e.g. "using falcon", "using deep-research"). Default to falcon when none are mentioned.
-
Reference the GitHub issue number so the agent links the resulting PR back to it.
-
Instruct the agent to consult the initiate-new-disorder-creation skill for the full curation workflow (this is what /curate does — sub-agents cannot invoke slash commands directly, so this skill must be named in the prompt).
-
Tell the agent to decide what the concept should be before curating: a kb/disorders/ Disease, a kb/groupings/ Grouping, a has_subtypes entry on an existing disease, or out of scope. A disorder entry needs one reasonably conserved pathograph; a union of distinct diseases is a grouping. If it turns out to be a grouping or out of scope, the right output is to record that in the stub's entry_type with the reasoning in notes — that is a completed curation, not a failed one. See docs/curation-stubs.md.
-
Tell the agent the curation PR should delete the disease's stub (stubs/<Name>.yaml) alongside adding the KB entry, and carry Closes #<issue> so merging releases the claim. Forgetting the stub does not fail anything — stubs are informative, and a periodic just tidy-stubs --apply sweeps stale ones.
-
MUST tell the agent to create a git worktree of its own and cd into it, then root every Read/Edit/Write/Bash file operation in the worktree's path — never in the parent checkout's path. Never give the agent the parent checkout's absolute path as its working directory. In a real production incident, two of three agents took an absolute parent path from the prompt () and wrote plus dozens of files into the parent checkout instead of their own worktree — branches were left empty and recovery required surgery. The agent prompt should include something like:
-
Report. After all agents finish, list: