plugins/lisa/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}`, 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.)
Story / Epic / Spike: skipped (may span repos — these are coordination containers, not 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 Epic / Story / Spike (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** — `issue_type ∈ {Epic, Story, Spike}` OR child work is present (any type that has 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 container-type + build-ready** — `issue_type ∈ {Epic, Story, Spike}` with **no** child work, AND build-ready. Still FAIL: these types are coordination containers by design, and an empty one is an incomplete decomposition, not an implementable unit (the childless-parent exception in `leaf-only-lifecycle` does **not** promote an Epic/Story/Spike to build-ready).
PASS (the childless-parent exception) when the issue is build-ready and is a **leaf work unit**: `issue_type ∈ {Bug, Task, Sub-task, Improvement}` AND has **no** child work. A flat Task or Bug 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 | no | yes | **PASS** (leaf) |
| Bug / Task / Sub-task / Improvement | yes | yes | **FAIL** (structurally a container) |
| Epic / Story / Spike | yes | yes | **FAIL** (container with children) |
| Epic / Story / Spike | no | yes | **FAIL** (childless container-type, 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/Story/Spike, 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.documentation
Onboard a user to the project via its LLM Wiki. Interviews the user about themselves in relation to the project, captures that to project-scoped memory only, then gives a guided tour of what the project is and sample questions they can ask. Use when someone is new to the project or asks to be onboarded. Read-mostly — it does not open PRs or write PII into the wiki.
documentation
Migrate an existing, hand-rolled wiki implementation onto the lisa-wiki kernel — phased and compatibility-first, with a strict no-loss guarantee. Use when adopting lisa-wiki in a repo that already has its own wiki/, ingest skills, docs, or roles. Renaming things into the canonical shape is fine; losing functionality or data is not. Ends by running /doctor.
development
Health-check the LLM Wiki. Reports orphan pages, contradictions, stale claims, broken internal links, missing index/log coverage, structure-manifest violations, and secret/tenant leaks. Use periodically or before hardening a wiki. Read-only — it reports findings, it does not fix them.
testing
Ingest source material into the LLM Wiki. With an argument (URL, file path, or prompt) it ingests that one source; with no argument it runs a full ingest across every enabled non-external-write source. Routes to the right connector, then runs the ordered pipeline (source note → synthesis → index → log → verify → state → commit/PR). Use whenever new knowledge should enter the wiki.