plugins/lisa-cursor/skills/lisa-github-read-issue/SKILL.md
Fetches the full scope of a GitHub Issue — metadata, body sections, all comments, native sub-issue parent and children, linked PRs, related issues parsed from `Blocks/Blocked by/Relates to/Duplicates/Cloned from` lines, and any cross-repo references. Produces a consolidated context bundle that downstream agents consume so they never act on an issue in isolation. The GitHub counterpart of lisa-jira-read-ticket.
npx skillsauth add codyswanngt/lisa lisa-github-read-issueInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
Security scan pending...
This skill is queued for security scanning. Results will appear when the scan completes.
Fetch the full scope of the issue AND its related graph. Downstream agents must never act on an issue in isolation — always call this skill first so they see blockers, sibling sub-issues, linked PRs, and historical comments.
This skill is the GitHub counterpart of lisa-jira-read-ticket. The output bundle structure mirrors the JIRA bundle so vendor-neutral consumers can parse either with minimal branching.
Repository name for scoped comments and logs: basename $(git rev-parse --show-toplevel).
Confirm gh auth status succeeds.
Parse $ARGUMENTS. Accept either:
<org>/<repo>#<number> token, ORhttps://github.com/<org>/<repo>/issues/<number> URL.If $ARGUMENTS is just #<number> or <number>, resolve <org>/<repo> from .lisa.config.json (github.org / github.repo).
If the input doesn't parse cleanly, stop and report. Do NOT guess.
gh issue view <number> --repo <org>/<repo> --json number,title,body,state,stateReason,author,assignees,labels,milestone,createdAt,updatedAt,closedAt,url,comments,reactionGroups,projectItems
Extract and preserve:
number, title, state (open/closed), stateReason (completed/not_planned/reopened/null)author (immutable original reporter), assigneestype:<...> (issue type), status:<...> (workflow status), priority:<...>, component:<...>, points:<...>, fix-version:<...>, claude-triaged-<repo>, plus any free-form labelsmilestone (name + url)createdAt, updatedAt, closedAturl (canonical issue URL)Walk the markdown body and capture each top-level ## section by name. Standard sections (per lisa-github-write-issue Phase 3):
Context / Business ValueTechnical ApproachAcceptance Criteria (preserve the Gherkin code-fence verbatim)Out of ScopeTarget Backend EnvironmentBranch Plan (derived output per derived-branch-plan — parsed so callers can compare it against a recomputation, never so they can use it as the base branch)Sign-in RequiredRepositorySource ArtifactsSource PrecedenceLinksRelationship SearchValidation Journey (preserve verbatim — pass through to verifier agents)Open QuestionsCurrent ProductAny other ## section: capture under extra_sections so callers can see PRDs that adopt non-standard sections.
Fetch ALL comments. Do not truncate. The comments field from gh issue view --json comments includes author, body, createdAt for each. Flag comments that contain:
[<repo>]If pagination matters (issues with hundreds of comments), use gh api repos/<org>/<repo>/issues/<number>/comments --paginate to get the full set.
GitHub native sub-issues are exposed via GraphQL:
query($org:String!,$repo:String!,$number:Int!){
repository(owner:$org,name:$repo){
issue(number:$number){
id
parent { number title state url repository { nameWithOwner } }
subIssues(first: 100) {
nodes {
number title state url
repository { nameWithOwner }
labels(first: 50) { nodes { name } }
assignees(first: 5) { nodes { login } }
}
}
}
}
}
gh api graphql -f query='<above>' -F org=<org> -F repo=<repo> -F number=<number>
Capture:
type: and status:), assignees.If the GraphQL parent / subIssues fields aren't available (older GHES), fall back to parsing Parent: #<n> text in the body and recording sub-issue text references — note "GraphQL sub-issues unavailable" in the bundle so callers know parent-link is text-based.
The body's ## Links section encodes typed relationships. Parse:
| Pattern (case-insensitive) | Link type |
|----------------------------|-----------|
| Blocks #<n> or Blocks <org>/<repo>#<n> | blocks |
| Blocked by #<n> or Blocked by <org>/<repo>#<n> | is blocked by |
| Relates to #<n> or Relates to <org>/<repo>#<n> | relates to |
| Duplicates #<n> or Duplicates <org>/<repo>#<n> | duplicates |
| Cloned from #<n> or Cloned from <org>/<repo>#<n> | clones |
| Resolves #<n> or Closes #<n> or Fixes #<n> (PR refs) | remote-link to PR |
For each parsed reference, fetch the linked issue/PR:
gh issue view <link-number> --repo <link-org>/<link-repo> --json number,title,state,labels,assignees,url
gh pr view <link-number> --repo <link-org>/<link-repo> --json number,title,state,reviewDecision,merged,mergedAt,url,reviewRequests,reviews,comments
For each linked issue, capture: number, title, state, type (from labels), status (from labels), assignees, url.
For each linked PR, capture: number, title, state, mergedAt, reviewDecision, unresolved review comments, url.
Special handling for is blocked by: include the linked issue's PR refs (parse Resolves lines in its body) and fetch each PR's state, so the agent knows whether the blocker is actually shipped.
If the primary issue has a parent sub-issue (i.e., is a Story / Task / Sub-task / Improvement under an Epic):
subIssues query against the parent. Filter out the primary issue itself.status:in-progress with an assignee different from the primary issue's assignee, flag prominently so the caller can avoid duplicate work.If the primary issue IS an Epic, capture all children via Phase 3's subIssues traversal (already done).
GitHub's native closingIssuesReferences and timeline give the canonical PR↔Issue relationship. The same timeline read also exposes label events, which are Lisa's GitHub-native transition history. Keep this as one GraphQL read path; do not add a second REST timeline fetch.
query='query($org:String!,$repo:String!,$number:Int!,$cursor:String){
repository(owner:$org,name:$repo){
issue(number:$number){
closedByPullRequestsReferences(first:50){
nodes{number title state merged mergedAt url repository{nameWithOwner}}
}
timelineItems(
first:100
after:$cursor
itemTypes:[CROSS_REFERENCED_EVENT,LABELED_EVENT,UNLABELED_EVENT]
){
pageInfo{hasNextPage endCursor}
nodes{
...on CrossReferencedEvent{
createdAt
actor{login}
source{...on PullRequest{number title state url repository{nameWithOwner}}}
}
...on LabeledEvent{
createdAt
actor{login}
label{name}
}
...on UnlabeledEvent{
createdAt
actor{login}
label{name}
}
}
}
}
}
}'
cursor=null
while :; do
if [ "$cursor" = null ]; then
page=$(gh api graphql -f query="$query" -F org=<org> -F repo=<repo> -F number=<number>)
else
page=$(gh api graphql -f query="$query" -F org=<org> -F repo=<repo> -F number=<number> -f cursor="$cursor")
fi
printf '%s\n' "$page"
has_next=$(printf '%s\n' "$page" | jq -r '.data.repository.issue.timelineItems.pageInfo.hasNextPage')
cursor=$(printf '%s\n' "$page" | jq -r '.data.repository.issue.timelineItems.pageInfo.endCursor')
[ "$has_next" = true ] || break
done
Capture:
CrossReferencedEvent behavior for PR linkage; widening the query must not change that consumer shape.LabeledEvent and UnlabeledEvent entries with event kind, label name, actor login, and createdAt. Preserve oldest→newest order across all pages. Status labels (status:*) are the GitHub transition history that downstream rejection detection consumes, but keep non-status label events too so callers can audit the full label stream.Pagination is mandatory. timelineItems(first:100) silently truncates busy issues unless pageInfo.hasNextPage / endCursor is followed. If a page fetch fails, record label-event history as unknown with the error and continue assembling the bundle; a history read failure must never block the build.
For each PR, fetch unresolved review comments via gh pr view <num> --repo <org>/<repo> --json reviews,reviewThreads.
Produce a single structured output that the caller can pass verbatim to downstream agents. Use this format:
# Issue Context: <org>/<repo>#<number>
## Primary Issue
- Ref: <org>/<repo>#<number>
- URL: <url>
- Type: <type from `type:` label>
- Status: <status from `status:` label>
- State: <open|closed> (<stateReason>)
- Priority: <priority from `priority:` label>
- Author: <login>
- Assignees: <list>
- Parent: <parent-ref> — <parent-title> (or "None")
- Milestone: <name> (or "None")
- Labels: <comma-separated raw labels>
- Components: <list from `component:` labels>
- Story points: <n from `points:` label> (or "None")
- Fix version: <from `fix-version:` label or milestone>
- Created: <ISO> | Updated: <ISO> | Closed: <ISO or "—">
### Body sections
#### Context / Business Value
<verbatim>
#### Technical Approach
<verbatim>
#### Acceptance Criteria
<verbatim, including the gherkin fence>
#### Validation Journey
<verbatim or "None">
#### Out of Scope
<verbatim>
#### Source Artifacts / Source Precedence / Links / Relationship Search / Repository / Sign-in Required / Target Backend Environment / Open Questions / Current Product
<each verbatim, omit those not present>
### Comments (<count>)
<chronological comments with author + ISO timestamp + body. Flagged items called out.>
## Sub-issue graph
### Parent
<parent block: ref, title, state, url, type label> (or "None — this is an Epic / unparented")
### Sub-issues (children, <count>)
- <ref> — <type> — <status> — <state> — <title>
- <one-paragraph body summary>
- <FLAG: in progress by other assignee> if applicable
## Linked Issues (parsed from body `## Links`)
### Blocks (<count>)
<per-issue block>
### Is Blocked By (<count>)
<per-issue block; include shipped/not-shipped state of any linked PRs>
### Relates To (<count>)
<per-issue block>
### Duplicates / Clones
<per-issue block>
## Linked Pull Requests
### Native (closedByPullRequestsReferences + cross-references)
- <pr-ref> — <state> — <title> — <reviewDecision>
<body summary + unresolved review comments>
### Body-referenced (`Resolves #<n>`)
<per-PR block>
## Label-Event History
- Status: <known|unknown>
- Events:
- <ISO> — <labeled|unlabeled> — <label-name> — <actor-login>
- ...
## Sibling Sub-issues (other children of the same parent, <count>)
- <ref> — <type> — <status> — <assignee> — <title> **[FLAG: in progress by other assignee]**
## Summary for Downstream
- Full graph fetched: <issue-count>
- Blockers still open: <list>
- Related in-flight work: <list>
- Relevant PRs: <list with state>
## casings, missing optional sections) but strict enough that downstream skills can rely on the named sections being present when they exist.development
Prepare a machine — a fresh laptop or a throwaway container — to run coding agents, before any repository exists. Detects which of Lisa's supported agents (Claude Code, Codex, Cursor, OpenCode, Antigravity, Copilot) are already installed, asks which credential manager the machine uses (Bitwarden, 1Password, Doppler, Vault, AWS, or none), and installs only what is missing, each by its vendor's own preferred method. Idempotent, headless by default, and emits a Dockerfile for a spin-up/spin-down environment. Run it on a new machine, in a container, or before cloning anything.
tools
Provision and verify a remote execution environment for a host project — Codex Cloud today, other remote surfaces as they are added. Generates a repository-owned setup script that installs the declared toolchain, materializes secrets through lisa-secrets-access, and runs the project's own hook. Provisions by API where one exists, by driving the vendor console where one does not, and by emitting exact config otherwise — then proves the result with the same read-back regardless of which tier did the work. Use before dispatching any work with executionEnv.
tools
Bring a developer's machine in line with the toolchain the project declares. Reports every tool in remoteEnv.tools that is missing, outdated, or unpinned for this platform, and installs the missing ones into ~/.local/bin from the same pinned, checksummed entries the remote surfaces use — but only when asked. Same manifest, same pins, same installers as lisa-setup-remote-env; what differs is consent and that the pin is a floor rather than an equality. Run it on a fresh checkout, after a manifest change, or when a tool fails at the moment of use.
tools
Route one unit of work to a remote execution surface. Reads the executionEnv parameter (local by default, codex-cloud or claude-web today), verifies the environment is provisioned and bound to this repository, submits a thin skill invocation, records the task identifier to .lisa/remote-dispatch.json, and exits without polling. Routing only — the remote runs the identical skill from the identical repository. Composable and inline: other skills invoke it via the Skill tool rather than users calling it directly.