plugins/src/base/skills/linear-validate-issue/SKILL.md
Validates a proposed Linear work item spec (Project, Issue, or sub-Issue) — or an existing Linear item — against the organizational quality gates without writing anything. Returns a structured PASS/FAIL report per gate with concrete remediation. Single source of truth for what makes a valid Linear item — both the write path (linear-write-issue runs it pre-write) and the dry-run path (linear-to-tracker runs it during PRD intake) call this skill so the bar can never drift.
npx skillsauth add codyswanngt/lisa linear-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 a Linear work item spec OR an existing Linear item. This skill is read-only — it never writes to Linear. The output is a structured report consumed by callers (lisa:linear-write-issue for pre-write gating, lisa:linear-to-tracker for PRD dry-run, lisa:linear-verify for post-write checks).
Reads linear.workspace, linear.teamKey from .lisa.config.json (with .local override) for any feasibility lookups.
$ARGUMENTS is one of:
ENG-123 for an Issue, or <workspace>/project/<slug>-<id> for a Project): fetch and validate the live state.issue_type: Story # Epic | Story | Task | Bug | Spike | Sub-task | Improvement
team_key: ENG
summary: "[CU-1.2] Upload contract PDF from settings"
priority: 3 # Linear native: 0=No priority, 1=Urgent, 2=High, 3=Medium, 4=Low
parent_project_id: <uuid> # Required for Story/Task/Improvement when in Epic context
parent_issue_id: <uuid> # Required for Sub-task (the Story Issue)
description: | # Full description text — every required section
## Context / Business Value
...
## Technical Approach
...
## Acceptance Criteria
1. Given <precondition>
When <action>
Then <observable outcome>
## Out of Scope
...
## Target Backend Environment
dev
## Sign-in Required
Account: ...
## Repository
backend-api
## Validation Journey
...
# Behavioral flags — caller asserts these so the validator picks the right gates
runtime_behavior_change: true # → requires Target Backend Environment + Validation Journey
authenticated_surface: true # → requires Sign-in Required
artifacts_attached: true # → requires Source Precedence section
relations: [{ id: "ENG-99", type: "blocked_by" }] # known issue relations (may be empty)
remote_links: [{ url: "https://github.com/...", title: "PR #42" }]
build_ready: true # caller asserts the build-ready role (status:ready) is/would be applied — see S15
child_refs: ["ENG-601", "ENG-602"] # known child work (sub-issues / project-member issues / blocked_by parentage) — see S15
If the caller passes only an identifier, fetch the item via mcp__linear-server__get_issue (Issue) or mcp__linear-server__get_project (Project), derive the same fields from the fetched data — including build_ready (label set contains status:ready) and child_refs (sub-issues, project-member issues, plus blocked_by parentage, resolved as in lisa:linear-read-issue) so S15 can classify the item — then run gates.
Gates are grouped into Specification (spec-only checks, no Linear lookups) and Feasibility (requires Linear lookups). The dry-run path may opt to run Specification gates only; the write path runs both.
Each gate is tagged with a fixed category and a product_relevant boolean. Categories drive how downstream callers (notably lisa:linear-prd-intake) translate failures into product-facing comments; product_relevant=false failures indicate internal data-quality problems the agent should fix itself rather than ask product to clarify.
| 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 Project parent 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 valid in team | structural | false |
| F2 Project parent exists and is in same team | structural | false |
| F3 Linked items exist | structural | false |
| F4 Required labels exist (or can be created) | structural | false |
Category values are the same fixed set as lisa:jira-validate-ticket:
product-clarity — feature behavior or user intent unclear in the PRDacceptance-criteria — pass/fail conditions missing or ambiguousdesign-ux — visual or interaction spec missingscope — boundary unclear, items overlap, split neededdependency — blocked by another team / system / decisiondata — data source / shape / volume unspecifiedtechnical — engineering decision requiredstructural — internal data-quality problem the agent must fix itself, not surface to productteam_key, issue_type, summary, priority, description must all be present and non-empty.
[repo-name] prefix when the project convention uses oneDescription text must include all of these sections (case-insensitive ## markdown headings):
Context / Business Value — stakeholder-facingTechnical Approach — developer-facingAcceptance Criteria — coding-assistant-facingOut of Scope — explicit non-coverage listMissing any → FAIL with name of missing section.
Applies when issue_type ∈ {Story, Task, Bug, Sub-task, Improvement}.
The Acceptance Criteria section must contain at least one criterion in Given / When / Then form. Reject prose-only criteria, "should work" language, or numbered lists without Given/When/Then verbs.
When issue_type = Bug, description must additionally include:
When issue_type = Spike, description must include:
When issue_type ∈ {Story, Task, Improvement} AND the item is part of an Epic context, parent_project_id must be set. When issue_type = Sub-task, parent_issue_id must be set. (Validity of the IDs is checked in feasibility gates.)
For top-level Bug / Spike not under an Epic, this gate is N/A.
When runtime_behavior_change = true, description must contain ## Target Backend Environment with one of dev, staging, prod. Skipped for doc-only / config-only / type-only / Epic.
When authenticated_surface = true, description must contain ## Sign-in Required naming the account/role and credential source.
If the spec doesn't set authenticated_surface, infer it: scan the description and AC for sign-in / login / "as a {role} user" / authenticated route signals. If signals present and no Sign-in Required section: FAIL.
When issue_type ∈ {Bug, Task, Sub-task, Improvement} — or a build-ready childless Story/Spike (a claimable leaf per leaf-only-lifecycle) — description 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)".
An Epic (a Linear Project), 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:linear-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.
When runtime_behavior_change = true, description must contain ## Validation Journey. Skipped for doc-only / config-only / type-only / Epic.
The caller controls strictness via journey_followup: "auto" or "none":
auto (default): missing section returns FAIL with remediation "Invoke lisa:linear-add-journey to append the section after create". The write path auto-fixes; dry-run path leaves it as a FAIL the caller must address.none: missing section is a FAIL the caller will not auto-fix.When artifacts_attached = true, description 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:
## Source Precedence subsection, ORTechnical Approach covering the four axes.Detect by scanning for the phrase Source Precedence (case-insensitive) anywhere in the description AND verifying the four axes are each named. Missing the phrase OR any axis: FAIL with remediation naming the missing axes.
The item must EITHER have at least one entry in relations, OR the description / a comment must contain a ## Relationship Search block listing the git history queries and Linear MCP queries that were run with their outcomes.
An item with zero relations and no documented search: FAIL.
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 item. These markers are the work unit's evidence manifest — the exact, enumerated set of artifacts that must be captured and attached before the item 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 — a Project (the Epic equivalent), 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:linear-add-journey.
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 Linear validator — a stale or hand-applied status:ready label on a container is a lifecycle error and must FAIL here, regardless of how the item was produced. (Mirrors the "Build-ready label is leaf-only" rule that lisa:linear-write-issue applies at write time.)
When the gate applies. Run S15 whenever the item is build-ready — i.e. build_ready = true, or the spec/live labels include status:ready. If the item is not build-ready, S15 is N/A (nothing claims a non-ready item, 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 issue type decides. Determine child work from (in order) child_refs, native sub-issues, project-member issues (an Epic is modeled as a Linear Project), and blocked_by / parent references — the same hierarchy resolution lisa:linear-read-issue uses. When validating a live identifier, query sub-issues / project members alongside the item fetch.
Apply this decision and FAIL the two invariant-violating cases:
issue_type = Epic (a Linear Project) with no child work, AND build-ready. Still FAIL: an Epic/Project 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 item 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 (Project) | no | yes | FAIL (childless Epic/Project — 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.
For Issue types: confirm the team supports the issue type via mcp__linear-server__get_team. Linear issue types are typically per-team; check that the requested type exists.
For Epic (Project): confirm the team allows projects.
When parent_project_id is set: fetch via mcp__linear-server__get_project, confirm it exists and belongs to the configured team.
When parent_issue_id is set (Sub-task case): fetch via mcp__linear-server__get_issue, confirm the issue is non-Sub-task and in the same team / project.
For each entry in relations, call mcp__linear-server__get_issue to confirm the identifier resolves. Flag broken identifiers.
For each label referenced (status:*, component:<name>, prd-*), confirm via mcp__linear-server__list_issue_labels (or list_project_labels for Project labels) that it exists OR is creatable. Linear labels are team-scoped or workspace-scoped; flag if the requested scope is wrong.
$ARGUMENTS. If it's an identifier, fetch the item and derive the spec from the fetched fields — including build_ready (label set contains status:ready) and child_refs (sub-issues, project-member issues, plus blocked_by parentage, resolved as in lisa:linear-read-issue) so S15 can classify the item. Otherwise parse the YAML spec.mcp__linear-server__list_teams({query: <teamKey>}) if any feasibility gate will run.--spec-only (dry-run), run every Feasibility gate. Collect results.Output is a single fenced text block. Callers parse it; do not add free-form prose around it.
## linear-validate-issue: <IDENTIFIER-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 Project parent 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 when --spec-only)
- [PASS|FAIL|N/A] F1 Issue type valid in team — <one-line reason>
- [PASS|FAIL|N/A] F2 Project parent exists and is in same team — <one-line reason>
- [PASS|FAIL|N/A] F3 Linked items exist — <one-line reason>
- [PASS|FAIL|N/A] F4 Required labels exist (or can be created) — <one-line reason>
### Verdict: PASS | FAIL
### Failures: <count>
### Failure details
- gate: <gate-id>
category: <category>
product_relevant: <true|false>
what: <plain-language description, no gate-IDs, no Linear jargon>
recommendation: <1–3 concrete options>
- gate: ...
The verdict is PASS if and only if every applicable gate is PASS. Any FAIL makes the verdict FAIL. N/A does not affect the verdict.
allowed-tools list intentionally excludes any save_* tool.N/A with the reason.what and recommendation fields must be concrete and product-readable — the dry-run path turns each failure into a Linear comment. Vague guidance is useless; always give 1–3 candidate resolutions.product_relevant is determined by the gate, not by the failure context.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.