plugins/lisa-copilot/skills/github-validate-issue/SKILL.md
Validates a proposed GitHub Issue spec (or an existing issue) against the organizational quality gates without writing anything. Returns a structured PASS/FAIL report per gate with concrete remediation. The GitHub counterpart of lisa:jira-validate-ticket — same gate definitions, translated to the GitHub Issues data model. Single source of truth for what makes a valid GitHub Issue. Both the write path (github-write-issue runs it pre-write) and the dry-run path (github-to-tracker runs it during PRD intake) call this skill.
npx skillsauth add codyswanngt/lisa github-validate-issueInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Run all organizational quality gates against an issue spec OR an existing issue. This skill is read-only — it never writes to GitHub. The output is a structured report consumed by callers (lisa:github-write-issue for pre-write gating, lisa:github-to-tracker for PRD dry-run, lisa:github-verify for post-write checks).
$ARGUMENTS is one of:
org/repo#<number> or https://github.com/<org>/<repo>/issues/<number>): fetch it and validate the live state. Use this for post-write checks.Specs are passed as a fenced YAML block. Required keys depend on issue_type.
issue_type: Story # Story | Task | Bug | Epic | Spike | Sub-task | Improvement
org: my-org
repo: my-repo
summary: "[CU-1.2] Upload contract PDF from settings"
priority: medium
parent_ref: "my-org/my-repo#1234" # Parent Epic for non-Bug/non-Epic; Story for Sub-task
body: |
## Context / Business Value
...
## Technical Approach
...
## Acceptance Criteria
```gherkin
Scenario: <name>
Given <precondition>
When <action>
Then <observable outcome>
...
dev
Account: ...
backend-api
...
runtime_behavior_change: true # → requires Target Backend Environment + Validation Journey authenticated_surface: true # → requires Sign-in Required artifacts_attached: true # → requires Source Precedence section links: [{ ref: "my-org/my-repo#99", type: "is blocked by" }] # known issue links (may be empty) remote_links: [{ url: "https://github.com/.../pull/42", title: "PR #42" }] journey_followup: auto # auto | none — see S11 build_ready: true # caller asserts the build-ready role (status:ready) is/would be applied — see S15 child_refs: ["my-org/my-repo#601", "my-org/my-repo#602"] # known child work (sub-issues / task-list / "Blocked by" parentage) — see S15
If the caller passes only an issue ref, fetch via `gh issue view <number> --repo <org>/<repo> --json number,title,body,labels,state,milestone,assignees`, parse the body sections, derive the spec fields, then run gates. The parser lives in `lisa:github-read-issue` (composition).
## Gates
Gates are grouped into **Specification** (spec-only checks, no GitHub lookups) and **Feasibility** (requires GitHub lookups). The dry-run path may opt to run Specification gates only via `--spec-only`; the write path runs both.
Each gate is tagged with a fixed `category` and a `product_relevant` boolean. Categories are the same fixed set used by `lisa:jira-validate-ticket` so downstream PRD-intake comment-formatting policy is shared across vendors.
| Gate | Category | Product-relevant |
|------|----------|------------------|
| S1 Required core fields | `structural` | false |
| S2 Summary format | `structural` | false |
| S3 Description three audiences | `product-clarity` | true |
| S4 Acceptance criteria in Gherkin | `acceptance-criteria` | true |
| S5 Bug-specific content | `product-clarity` | true |
| S6 Spike-specific content | `scope` | true |
| S7 Parent sub-issue declared | `structural` | false |
| S8 Target Backend Environment | `technical` | false |
| S9 Sign-in Required | `technical` | false |
| S10 Single-repo scope | `scope` | false |
| S11 Validation Journey | `acceptance-criteria` | true |
| S12 Source Precedence | `design-ux` | true |
| S13 Relationship Search | `dependency` | true |
| S14 Evidence manifest binding (leaf work units) | `acceptance-criteria` | true |
| S15 Leaf-only build-ready | `structural` | false |
| F1 Issue type label exists in repo | `structural` | false |
| F2 Parent sub-issue exists and is the right type | `structural` | false |
| F3 Linked issues exist | `structural` | false |
| F4 Required labels populated | `structural` | false |
Category values are the same fixed set as `lisa:jira-validate-ticket`:
- `product-clarity`, `acceptance-criteria`, `design-ux`, `scope`, `dependency`, `data`, `technical`, `structural`.
### Specification Gates
#### S1 — Required core fields
`org`, `repo`, `issue_type`, `summary`, `priority`, `body` must all be present and non-empty.
#### S2 — Summary format
- Single line, ≤ 100 characters.
- Imperative voice ("Add X", "Fix Y", not "Adding X" or "X is broken").
- Bug / Task / Sub-task summaries SHOULD start with a `[repo-name]` prefix when the project convention uses one.
#### S3 — Description has all three audiences
Body must include all of these sections (case-insensitive `## ` headings):
- `Context / Business Value` — stakeholder-facing
- `Technical Approach` — developer-facing
- `Acceptance Criteria` — coding-assistant-facing
- `Out of Scope` — explicit non-coverage list
Missing any → FAIL with name of missing section.
#### S4 — Acceptance criteria in Gherkin
Applies when `issue_type ∈ {Story, Task, Bug, Sub-task, Improvement}`.
The `## Acceptance Criteria` section must contain at least one `Scenario:` block with `Given / When / Then` form, ideally inside a ` ```gherkin ` code fence. Reject prose-only criteria, "should work" language, or numbered lists without Given/When/Then verbs.
#### S5 — Bug-specific content
When `issue_type = Bug`, body must additionally include:
- Reproduction steps
- Expected vs. actual behavior
- Environment where reproduced
#### S6 — Spike-specific content
When `issue_type = Spike`, body must include:
- The question being answered
- Definition of done (decision doc / prototype / findings deliverable)
#### S7 — Parent sub-issue declared
When `issue_type ∉ {Bug, Epic}`, `parent_ref` must be set. The native sub-issue link is set by `lisa:github-write-issue` Phase 6 step 3. (Validity of the parent is checked in feasibility gate F2.)
#### S8 — Target Backend Environment
When `runtime_behavior_change = true`, body must contain `## Target Backend Environment` with one of `dev`, `staging`, `prod`. Skipped for doc-only / config-only / type-only / Epic.
#### S9 — Sign-in Required
When `authenticated_surface = true`, body must contain `## Sign-in Required` naming the account/role and credential source.
If the spec doesn't set `authenticated_surface`, infer it: scan the body and AC for sign-in / login / "as a {role} user" / authenticated route signals. If signals present and no `Sign-in Required` section: FAIL.
#### S10 — Repository section, single-repo scope
When `issue_type ∈ {Bug, Task, Sub-task, Improvement}` — or a **build-ready childless Story/Spike** (a claimable leaf per `leaf-only-lifecycle`) — body must contain `## Repository` naming exactly one repo. Multiple repos OR cross-repo references in AC: FAIL with recommendation `"Split into per-repo work units under a shared parent Story (see lisa:task-decomposition step 1.5)"`.
(GitHub Issues live in one repo by definition, so the `## Repository` section is technically redundant — keep it for parity with the JIRA path so downstream tooling sees the same shape. Cross-repo references in AC are still possible and still fail this gate.)
An **Epic**, or a **Story/Spike that still holds child work** (or is not build-ready): skipped (may span repos — coordination containers, not claimable leaf work units).
This gate is `product_relevant: false` because cross-repo work units are not a product question — they are a decomposition error. Callers (`lisa:github-to-tracker`, `lisa:notion-to-tracker`, etc.) MUST pre-split cross-repo work into per-repo work units during the decomposition phase per `lisa:task-decomposition` step 1.5; an S10 failure here indicates the agent skipped that step and must auto-split + revalidate before writing, not surface a clarifying comment to product.
#### S11 — Validation Journey present
When `runtime_behavior_change = true`, body must contain `## Validation Journey`. Skipped for doc-only / config-only / type-only / Epic.
The caller controls strictness via `journey_followup`:
- `auto` (default): missing section is FAIL with remediation `"Invoke lisa:github-add-journey to append the section after create"`. Callers like `lisa:github-write-issue` know to chain the followup automatically.
- `none`: missing section is FAIL the caller will not auto-fix (used by dry-run paths).
#### S12 — Source Precedence (when artifacts attached)
When `artifacts_attached = true`, body must include source-precedence guidance covering: business rules → PRD body, visual treatment → mocks, flow → prototypes, API/data → data artifacts. Cross-axis conflicts surfaced under `## Open Questions`.
Accept either placement:
- A dedicated `## Source Precedence` subsection, OR
- A "Source Precedence" / "authoritative source" paragraph under `## Technical Approach`.
Detect by scanning for the phrase `Source Precedence` (case-insensitive) AND verifying the four axes (business rules, visual, flow, data) are each named.
#### S13 — Relationship Search documented
The issue must EITHER have at least one entry in `links`, OR the body must contain a `## Relationship Search` block listing the git history queries and `gh issue list` queries that were run with their outcomes. ("Searched git history for `<keywords>` and `gh issue list` for label `component:X`; no related work found.")
An issue with zero links and no documented search: FAIL.
#### S14 — Evidence manifest binding (leaf work units)
When `issue_type ∈ {Bug, Task, Sub-task, Improvement}` AND `runtime_behavior_change = true`, the `## Validation Journey` must declare at least one `[EVIDENCE: name]` marker. Each marker name must be kebab-case and unique within the issue. These markers are the work unit's **evidence manifest** — the exact, enumerated set of artifacts that must be captured and attached before the issue may be closed (see the "Per-Work-Unit Evidence Contract" section of the `verification` rule, the Definition of Done in `verification-lifecycle`, and the evidence-manifest gate in `tracker-evidence`).
FAIL when the Validation Journey is present but declares zero `[EVIDENCE: name]` markers, or when any marker name is empty, duplicated, or not kebab-case. A behavior-changing work unit SHOULD declare both a success marker and an error/edge marker; a journey with only one marker passes but the remediation should recommend adding the error/edge case.
This gate depends on S11. It is `N/A` for containers — an **Epic**, or any item with open child work (coordination containers, not work units) — and for leaf units with `runtime_behavior_change = false` (doc-only / config-only / type-only). If S11 fails because the Validation Journey is absent, S14 also FAILs (there is no manifest to bind) with remediation pointing back to `lisa:github-add-journey`.
#### S15 — Leaf-only build-ready
Enforces the build-side of the vendor-neutral `leaf-only-lifecycle` rule: **only a leaf work unit may carry the build-ready role.** This is the symmetric write-side guard for the GitHub validator — a stale or hand-applied `status:ready` on a container is a lifecycle error and must FAIL here, regardless of how the issue was produced. (Mirrors the "Build-ready label is leaf-only" rule that `lisa:github-write-issue` applies at write time.)
**When the gate applies.** Run S15 whenever the issue is build-ready — i.e. `build_ready = true`, or the spec/live labels include `status:ready`. If the issue is not build-ready, S15 is `N/A` (nothing claims a non-ready issue, so the invariant is vacuous).
**Resolve container vs. leaf — structural first, then nominal.** Per `leaf-only-lifecycle` the classification is structural: an item is a **container** if it has child work, whatever its declared type; otherwise the **type label** decides. Determine child work from (in order) `child_refs`, native sub-issues, body task-list checkboxes, and `Blocked by #<n>` / parent references — the same hierarchy resolution `lisa:github-read-issue` uses. When validating a live ref, query sub-issues alongside the issue fetch.
Apply this decision and FAIL the two invariant-violating cases:
1. **Container with child work + build-ready** — child work is present (any type that has open children), AND build-ready. FAIL. A parent organizes work; it is never claimed and implemented directly. Its lifecycle state rolls up from its children.
2. **Childless Epic + build-ready** — `issue_type = Epic` with **no** child work, AND build-ready. Still FAIL: an Epic is a pure rollup container by design, and a childless one is an incomplete decomposition or a mis-applied role, not an implementable unit. (A childless Story or Spike is **not** failed here — the childless-parent exception in `leaf-only-lifecycle` promotes every childless non-Epic type to a build-ready leaf.)
PASS (the childless-parent exception) when the issue is build-ready and is a **leaf work unit**: it has **no** open child work and `issue_type ≠ Epic` (i.e. `Bug, Task, Sub-task, Improvement`, or a childless `Story` / `Spike`). A flat Task/Bug, or a childless Story/Spike with no sub-issues, is a valid build-ready leaf and must not be stranded.
| issue_type | has child work | build-ready | S15 |
|---|---|---|---|
| Bug / Task / Sub-task / Improvement / Story / Spike | no | yes | **PASS** (leaf) |
| any type | yes | yes | **FAIL** (structurally a container) |
| Epic | no | yes | **FAIL** (childless Epic — pure rollup container, exception does not apply) |
| any | any | no | **N/A** (not build-ready) |
Remediation: `"Build-ready (status:ready) is leaf-only per leaf-only-lifecycle. Move status:ready off this container onto its leaf children (or, for a childless Epic, decompose it into leaf children or reclassify it to a leaf type); a parent's lifecycle state rolls up from its children and is never set to ready directly."`
`product_relevant: false` — a build-ready container is a lifecycle/decomposition error for the caller to repair, not a product question.
### Feasibility Gates (require GitHub lookups; skip in `--spec-only`)
#### F1 — Issue type label exists in repo
```bash
gh label list --repo <org>/<repo> --json name --jq '.[].name'
Confirm type:<issue_type> exists. Missing labels can be auto-created by lisa:github-write-issue Phase 5 — flag the absence as a structural FAIL with remediation "Run gh label create type:<issue_type> or let the write path auto-create."
When parent_ref is set:
gh issue view <number> --repo <org>/<repo> --json number,labels,state
Confirm the parent issue exists and:
type:Epic label.type:Story, type:Task, type:Bug, or type:Improvement (anything that can host sub-tasks).For each entry in links, run gh issue view <number> --repo <link-org>/<link-repo> to confirm the ref resolves. Flag broken refs.
Per Phase 5 of lisa:github-write-issue, every issue MUST carry: type:<issue_type>, status:<status>, priority:<priority>. If any are missing from the spec / live issue, FAIL with the missing label name.
$ARGUMENTS. If it's an issue ref, fetch via gh issue view --json and derive the spec fields — including build_ready (label set contains status:ready) and child_refs (native sub-issues plus body task-list / Blocked by #<n> parentage, resolved as in lisa:github-read-issue) so S15 can classify the issue. Otherwise parse the YAML spec.gh auth status succeeds before any feasibility gate runs.--spec-only, run every Feasibility gate.Output is a single fenced text block. Callers parse it; do not add free-form prose around it.
## github-validate-issue: <ISSUE-REF-or-SUMMARY>
### Specification Gates
- [PASS|FAIL|N/A] S1 Required core fields — <one-line reason>
- [PASS|FAIL|N/A] S2 Summary format — <one-line reason>
- [PASS|FAIL|N/A] S3 Description three audiences — <one-line reason>
- [PASS|FAIL|N/A] S4 Acceptance criteria in Gherkin — <one-line reason>
- [PASS|FAIL|N/A] S5 Bug-specific content — <one-line reason>
- [PASS|FAIL|N/A] S6 Spike-specific content — <one-line reason>
- [PASS|FAIL|N/A] S7 Parent sub-issue declared — <one-line reason>
- [PASS|FAIL|N/A] S8 Target Backend Environment — <one-line reason>
- [PASS|FAIL|N/A] S9 Sign-in Required — <one-line reason>
- [PASS|FAIL|N/A] S10 Single-repo scope — <one-line reason>
- [PASS|FAIL|N/A] S11 Validation Journey — <one-line reason>
- [PASS|FAIL|N/A] S12 Source Precedence — <one-line reason>
- [PASS|FAIL|N/A] S13 Relationship Search — <one-line reason>
- [PASS|FAIL|N/A] S14 Evidence manifest binding — <one-line reason>
- [PASS|FAIL|N/A] S15 Leaf-only build-ready — <one-line reason>
### Feasibility Gates (omit this section when --spec-only)
- [PASS|FAIL|N/A] F1 Issue type label exists in repo — <one-line reason>
- [PASS|FAIL|N/A] F2 Parent sub-issue exists and is the right type — <one-line reason>
- [PASS|FAIL|N/A] F3 Linked issues exist — <one-line reason>
- [PASS|FAIL|N/A] F4 Required labels populated — <one-line reason>
### Verdict: PASS | FAIL
### Failures: <count>
### Failure details
- gate: <gate-id>
category: <product-clarity|acceptance-criteria|design-ux|scope|dependency|data|technical|structural>
product_relevant: <true|false>
what: <plain-language description, no gate IDs, no GitHub jargon — written for a non-engineer product owner>
recommendation: <1–3 concrete options the caller (or downstream product team) can pick from. Never "clarify this".>
- gate: <gate-id>
...
The verdict is PASS if every applicable gate is PASS. Any FAIL makes the verdict FAIL. N/A does not affect the verdict.
Same shape and meaning as lisa:jira-validate-ticket so downstream PRD-intake skills (Notion, Confluence, Linear, GitHub) can format comments uniformly:
S1–S15, F1–F4).false means the failure is an internal data-quality problem the caller should fix without bothering product.allowed-tools list intentionally excludes any gh issue create / edit / comment / close invocation.N/A with the reason if a gate genuinely doesn't apply; never omit it.what and recommendation must be concrete and product-readable — vague guidance ("clarify this") is useless.product_relevant is determined by the gate, not by the failure context.lisa:github-read-issue so the two skills agree on what they see.development
Use Expo DOM components to run web code in a webview on native and as-is on web. Migrate web code to native incrementally.
development
Guidelines for upgrading Expo SDK versions and fixing dependency issues
development
Use when implementing or debugging ANY network request, API call, or data fetching. Covers fetch API, React Query, SWR, error handling, caching, offline support, and Expo Router data loaders (`useLoaderData`).
tools
`@expo/ui/swift-ui` package lets you use SwiftUI Views and modifiers in your app.