@codyswann/lisa 2.326.2 → 2.327.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (190) hide show
  1. package/dist/core/upstream-evidence-manifest.d.ts.map +1 -1
  2. package/dist/core/upstream-evidence-manifest.js +25 -23
  3. package/dist/core/upstream-evidence-manifest.js.map +1 -1
  4. package/dist/sync/lifecycle-defaults.d.ts +61 -0
  5. package/dist/sync/lifecycle-defaults.d.ts.map +1 -0
  6. package/dist/sync/lifecycle-defaults.js +75 -0
  7. package/dist/sync/lifecycle-defaults.js.map +1 -0
  8. package/dist/sync/registry.d.ts.map +1 -1
  9. package/dist/sync/registry.js +15 -23
  10. package/dist/sync/registry.js.map +1 -1
  11. package/package.json +1 -1
  12. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  13. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  14. package/plugins/lisa/.codex-plugin/skills/lisa-confluence-to-tracker/SKILL.md +3 -3
  15. package/plugins/lisa/.codex-plugin/skills/lisa-github-validate-issue/SKILL.md +1 -1
  16. package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +1 -1
  17. package/plugins/lisa/.codex-plugin/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  18. package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +20 -9
  19. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +76 -66
  20. package/plugins/lisa/.codex-plugin/skills/lisa-linear-claim/SKILL.md +1 -1
  21. package/plugins/lisa/.codex-plugin/skills/lisa-linear-evidence/SKILL.md +7 -7
  22. package/plugins/lisa/.codex-plugin/skills/lisa-linear-journey/SKILL.md +2 -2
  23. package/plugins/lisa/.codex-plugin/skills/lisa-linear-sync/SKILL.md +34 -30
  24. package/plugins/lisa/.codex-plugin/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  25. package/plugins/lisa/.codex-plugin/skills/lisa-linear-validate-issue/SKILL.md +6 -6
  26. package/plugins/lisa/.codex-plugin/skills/lisa-linear-write-issue/SKILL.md +8 -7
  27. package/plugins/lisa/.codex-plugin/skills/lisa-notion-to-tracker/SKILL.md +3 -3
  28. package/plugins/lisa/.codex-plugin/skills/lisa-repair-intake/SKILL.md +1 -1
  29. package/plugins/lisa/.codex-plugin/skills/lisa-setup-linear/SKILL.md +59 -12
  30. package/plugins/lisa/.codex-plugin/skills/lisa-tracker-sync/SKILL.md +2 -2
  31. package/plugins/lisa/agents/linear-agent.md +6 -6
  32. package/plugins/lisa/agents/linear-build-intake.md +3 -3
  33. package/plugins/lisa/rules/eager/rejection-detection.md +2 -2
  34. package/plugins/lisa/rules/reference/config-resolution.md +37 -9
  35. package/plugins/lisa/rules/reference/rejection-detection.md +2 -2
  36. package/plugins/lisa/skills/lisa-confluence-to-tracker/SKILL.md +3 -3
  37. package/plugins/lisa/skills/lisa-github-validate-issue/SKILL.md +1 -1
  38. package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +1 -1
  39. package/plugins/lisa/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  40. package/plugins/lisa/skills/lisa-linear-access/SKILL.md +20 -9
  41. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +77 -67
  42. package/plugins/lisa/skills/lisa-linear-claim/SKILL.md +1 -1
  43. package/plugins/lisa/skills/lisa-linear-evidence/SKILL.md +7 -7
  44. package/plugins/lisa/skills/lisa-linear-journey/SKILL.md +2 -2
  45. package/plugins/lisa/skills/lisa-linear-sync/SKILL.md +34 -30
  46. package/plugins/lisa/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  47. package/plugins/lisa/skills/lisa-linear-validate-issue/SKILL.md +6 -6
  48. package/plugins/lisa/skills/lisa-linear-write-issue/SKILL.md +8 -7
  49. package/plugins/lisa/skills/lisa-notion-to-tracker/SKILL.md +3 -3
  50. package/plugins/lisa/skills/lisa-repair-intake/SKILL.md +1 -1
  51. package/plugins/lisa/skills/lisa-setup-linear/SKILL.md +59 -12
  52. package/plugins/lisa/skills/lisa-tracker-build-intake/SKILL.md +1 -1
  53. package/plugins/lisa/skills/lisa-tracker-sync/SKILL.md +2 -2
  54. package/plugins/lisa-agy/agents/linear-agent.md +6 -6
  55. package/plugins/lisa-agy/agents/linear-build-intake.md +3 -3
  56. package/plugins/lisa-agy/plugin.json +1 -1
  57. package/plugins/lisa-agy/skills/lisa-confluence-to-tracker/SKILL.md +3 -3
  58. package/plugins/lisa-agy/skills/lisa-github-validate-issue/SKILL.md +1 -1
  59. package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +1 -1
  60. package/plugins/lisa-agy/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  61. package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +20 -9
  62. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +77 -67
  63. package/plugins/lisa-agy/skills/lisa-linear-claim/SKILL.md +1 -1
  64. package/plugins/lisa-agy/skills/lisa-linear-evidence/SKILL.md +7 -7
  65. package/plugins/lisa-agy/skills/lisa-linear-journey/SKILL.md +2 -2
  66. package/plugins/lisa-agy/skills/lisa-linear-sync/SKILL.md +34 -30
  67. package/plugins/lisa-agy/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  68. package/plugins/lisa-agy/skills/lisa-linear-validate-issue/SKILL.md +6 -6
  69. package/plugins/lisa-agy/skills/lisa-linear-write-issue/SKILL.md +8 -7
  70. package/plugins/lisa-agy/skills/lisa-notion-to-tracker/SKILL.md +3 -3
  71. package/plugins/lisa-agy/skills/lisa-repair-intake/SKILL.md +1 -1
  72. package/plugins/lisa-agy/skills/lisa-setup-linear/SKILL.md +59 -12
  73. package/plugins/lisa-agy/skills/lisa-tracker-build-intake/SKILL.md +1 -1
  74. package/plugins/lisa-agy/skills/lisa-tracker-sync/SKILL.md +2 -2
  75. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  77. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  78. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  79. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  80. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-copilot/agents/linear-agent.agent.md +6 -6
  82. package/plugins/lisa-copilot/agents/linear-build-intake.agent.md +3 -3
  83. package/plugins/lisa-copilot/rules/eager/rejection-detection.md +2 -2
  84. package/plugins/lisa-copilot/rules/reference/config-resolution.md +37 -9
  85. package/plugins/lisa-copilot/rules/reference/rejection-detection.md +2 -2
  86. package/plugins/lisa-copilot/skills/lisa-confluence-to-tracker/SKILL.md +3 -3
  87. package/plugins/lisa-copilot/skills/lisa-github-validate-issue/SKILL.md +1 -1
  88. package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +1 -1
  89. package/plugins/lisa-copilot/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  90. package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +20 -9
  91. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +77 -67
  92. package/plugins/lisa-copilot/skills/lisa-linear-claim/SKILL.md +1 -1
  93. package/plugins/lisa-copilot/skills/lisa-linear-evidence/SKILL.md +7 -7
  94. package/plugins/lisa-copilot/skills/lisa-linear-journey/SKILL.md +2 -2
  95. package/plugins/lisa-copilot/skills/lisa-linear-sync/SKILL.md +34 -30
  96. package/plugins/lisa-copilot/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  97. package/plugins/lisa-copilot/skills/lisa-linear-validate-issue/SKILL.md +6 -6
  98. package/plugins/lisa-copilot/skills/lisa-linear-write-issue/SKILL.md +8 -7
  99. package/plugins/lisa-copilot/skills/lisa-notion-to-tracker/SKILL.md +3 -3
  100. package/plugins/lisa-copilot/skills/lisa-repair-intake/SKILL.md +1 -1
  101. package/plugins/lisa-copilot/skills/lisa-setup-linear/SKILL.md +59 -12
  102. package/plugins/lisa-copilot/skills/lisa-tracker-build-intake/SKILL.md +1 -1
  103. package/plugins/lisa-copilot/skills/lisa-tracker-sync/SKILL.md +2 -2
  104. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  105. package/plugins/lisa-cursor/agents/linear-agent.md +6 -6
  106. package/plugins/lisa-cursor/agents/linear-build-intake.md +3 -3
  107. package/plugins/lisa-cursor/rules/config-resolution-reference.mdc +37 -9
  108. package/plugins/lisa-cursor/rules/rejection-detection-reference.mdc +2 -2
  109. package/plugins/lisa-cursor/rules/rejection-detection.mdc +2 -2
  110. package/plugins/lisa-cursor/skills/lisa-confluence-to-tracker/SKILL.md +3 -3
  111. package/plugins/lisa-cursor/skills/lisa-github-validate-issue/SKILL.md +1 -1
  112. package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +1 -1
  113. package/plugins/lisa-cursor/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  114. package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +20 -9
  115. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +77 -67
  116. package/plugins/lisa-cursor/skills/lisa-linear-claim/SKILL.md +1 -1
  117. package/plugins/lisa-cursor/skills/lisa-linear-evidence/SKILL.md +7 -7
  118. package/plugins/lisa-cursor/skills/lisa-linear-journey/SKILL.md +2 -2
  119. package/plugins/lisa-cursor/skills/lisa-linear-sync/SKILL.md +34 -30
  120. package/plugins/lisa-cursor/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  121. package/plugins/lisa-cursor/skills/lisa-linear-validate-issue/SKILL.md +6 -6
  122. package/plugins/lisa-cursor/skills/lisa-linear-write-issue/SKILL.md +8 -7
  123. package/plugins/lisa-cursor/skills/lisa-notion-to-tracker/SKILL.md +3 -3
  124. package/plugins/lisa-cursor/skills/lisa-repair-intake/SKILL.md +1 -1
  125. package/plugins/lisa-cursor/skills/lisa-setup-linear/SKILL.md +59 -12
  126. package/plugins/lisa-cursor/skills/lisa-tracker-build-intake/SKILL.md +1 -1
  127. package/plugins/lisa-cursor/skills/lisa-tracker-sync/SKILL.md +2 -2
  128. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  129. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  130. package/plugins/lisa-expo-agy/plugin.json +1 -1
  131. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  132. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  133. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  134. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  135. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  136. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  137. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  138. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  139. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  140. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  141. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  142. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  143. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  144. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  145. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  146. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  147. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  148. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  149. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  150. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  151. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  152. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  153. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  154. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  155. package/plugins/lisa-rails-agy/plugin.json +1 -1
  156. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  157. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  158. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  159. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  160. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  161. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  162. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  163. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  164. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  165. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  166. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  167. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  168. package/plugins/src/base/agents/linear-agent.md +6 -6
  169. package/plugins/src/base/agents/linear-build-intake.md +3 -3
  170. package/plugins/src/base/rules/eager/rejection-detection.md +2 -2
  171. package/plugins/src/base/rules/reference/config-resolution.md +37 -9
  172. package/plugins/src/base/rules/reference/rejection-detection.md +2 -2
  173. package/plugins/src/base/skills/lisa-confluence-to-tracker/SKILL.md +3 -3
  174. package/plugins/src/base/skills/lisa-github-validate-issue/SKILL.md +1 -1
  175. package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +1 -1
  176. package/plugins/src/base/skills/lisa-jira-validate-ticket/SKILL.md +1 -1
  177. package/plugins/src/base/skills/lisa-linear-access/SKILL.md +20 -9
  178. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +77 -67
  179. package/plugins/src/base/skills/lisa-linear-claim/SKILL.md +1 -1
  180. package/plugins/src/base/skills/lisa-linear-evidence/SKILL.md +7 -7
  181. package/plugins/src/base/skills/lisa-linear-journey/SKILL.md +2 -2
  182. package/plugins/src/base/skills/lisa-linear-sync/SKILL.md +34 -30
  183. package/plugins/src/base/skills/lisa-linear-to-tracker/SKILL.md +3 -3
  184. package/plugins/src/base/skills/lisa-linear-validate-issue/SKILL.md +6 -6
  185. package/plugins/src/base/skills/lisa-linear-write-issue/SKILL.md +8 -7
  186. package/plugins/src/base/skills/lisa-notion-to-tracker/SKILL.md +3 -3
  187. package/plugins/src/base/skills/lisa-repair-intake/SKILL.md +1 -1
  188. package/plugins/src/base/skills/lisa-setup-linear/SKILL.md +59 -12
  189. package/plugins/src/base/skills/lisa-tracker-build-intake/SKILL.md +1 -1
  190. package/plugins/src/base/skills/lisa-tracker-sync/SKILL.md +2 -2
@@ -18,12 +18,12 @@ Callers (planning skills, lifecycle skills) invoke this skill at:
18
18
 
19
19
  | Milestone | What to post |
20
20
  |-----------|--------------|
21
- | Plan created | Plan contents (sections + ordered tasks) as a comment, suggest transition `Backlog → Todo` (label: `status:ready`) |
22
- | Implementation in progress | Branch URL + first commit, suggest transition `Todo → In Progress` (label: `status:in-progress`) |
23
- | PR ready for review | PR URL + summary, the implementation handoff comment, suggest transition `In Progress → In Review` (label: `status:code-review`) |
24
- | PR merged | Merge SHA + deploy environment (if known), suggest transition `In Review → Done` (label: `status:done`), **then run Phase 4b — mandatory when the merge target is a non-terminal env branch** |
21
+ | Plan created | Plan contents (sections + ordered tasks) as a comment, suggest transition `Backlog → Todo` (label: `Todo`) |
22
+ | Implementation in progress | Branch URL + first commit, suggest transition `Todo → In Progress` (label: `In Progress`) |
23
+ | PR ready for review | PR URL + summary, the implementation handoff comment, suggest transition `In Progress → In Review` (label: `In Review`) |
24
+ | PR merged | Merge SHA + deploy environment (if known), suggest transition `In Review → Done` (label: `Done`), **then run Phase 4b — mandatory when the merge target is a non-terminal env branch** |
25
25
 
26
- This skill **suggests** transitions but does not auto-transition the native Linear `state` field. It DOES update the `status:*` label set when the caller asks (the build queue is keyed off labels). Native state transitions remain a human / triage decision.
26
+ This skill **suggests** transitions and applies them to the native Linear `state` field when the caller asks the build queue is keyed off states, so the state IS the lane. Without `--update-state` it only suggests; an unasked-for transition remains a human / triage decision.
27
27
 
28
28
  ## Input
29
29
 
@@ -60,7 +60,7 @@ Sections:
60
60
 
61
61
  Tasks: 7 ordered items.
62
62
 
63
- Next: implementation begins. Suggested status: **Todo** (label: `status:ready`).
63
+ Next: implementation begins. Suggested status: **Todo** (label: `Todo`).
64
64
  ```
65
65
 
66
66
  ## Phase 3 — Post Comment
@@ -79,57 +79,61 @@ The PR branch/title/body identifier is the PR -> Linear side. This phase is the
79
79
 
80
80
  ## Phase 4 — Update Status Label (when caller requests)
81
81
 
82
- If the caller passes `--update-label`, update the `status:*` label set via `lisa-linear-access operation: save-issue`:
82
+ If the caller passes `--update-state`, set the Issue's `stateId` via `lisa-linear-access operation: save-issue`:
83
83
 
84
- - `plan-created` → add `status:ready`
85
- - `implementation-in-progress` → remove `status:ready`, add `status:in-progress`
86
- - `pr-ready` → remove `status:in-progress`, add `status:code-review`
87
- - `pr-merged` → remove `status:code-review`, add `status:done`
84
+ - `plan-created` → add `Todo`
85
+ - `implementation-in-progress` → remove `Todo`, add `In Progress`
86
+ - `pr-ready` → remove `In Progress`, add `In Review`
87
+ - `pr-merged` → remove `In Review`, add `Done`
88
88
 
89
89
  If the requested label doesn't exist on the team, create it via `lisa-linear-access operation: create-issue-label`.
90
90
 
91
- Verify exactly one `status:*` label remains after the update having two simultaneously breaks the build-queue invariant.
91
+ No single-lane verification is needed: an Issue holds exactly one workflow state by construction, so the two-labels-at-once corruption the old label lane could produce is unrepresentable.
92
92
 
93
- Without `--update-label`, this skill posts the comment only and does NOT touch labels.
93
+ Without `--update-state`, this skill posts the comment only and does NOT touch labels.
94
94
 
95
95
  ## Phase 4b — Reconcile Native Auto-Close (Linear-specific)
96
96
 
97
- Linear's GitHub integration completes a linked Issue on merge to **any branch** — unlike GitHub's default-branch-scoped `Closes` auto-close — so a magic word (`Closes`/`Fixes`/`Resolves ENG-123`) or branch-name linkage can natively move the Issue to a Done/Completed workflow `state` at a **non-terminal** env merge, front-running the env-keyed `status:*` label ladder. `git-submit-pr` prevents the magic-word case; this phase is the required post-merge repair for the residual (branch-linkage) case we cannot suppress server-side — branch linkage completes the Issue even when the PR body carries only the non-closing `Linear: <ID>` form. This phase is a **mandatory** numbered step of every `pr-merged` sync, not an optional backstop; run it whenever the resolved env is **intermediate** (below the production terminal `done`):
97
+ Linear's per-team **git automations** complete a linked Issue on merge to **any branch** — unlike GitHub's default-branch-scoped `Closes` auto-close — so a magic word (`Closes`/`Fixes`/`Resolves ENG-123`) or branch-name linkage can move the Issue to a `completed` state at a **non-terminal** env merge, front-running the env-keyed ladder.
98
+
99
+ **Since the build lane moved to native states, this phase is a BACKSTOP, not the primary defence.** The lifecycle now writes the same field the automation writes, so the disagreement it repairs can only arise when something outside Lisa moves the Issue. The primary fix is upstream and structural: `/lisa:setup:linear` detects the team's `merge → Done` git automation and offers to delete it, because with this model that automation is a redundant second writer as well as a wrong one. Keep this phase — a workspace can always re-add the automation, and a magic word in a hand-written PR body still fires — but a recurrence here is a **setup defect to report**, not routine repair to absorb silently.
100
+
101
+ Run it whenever the resolved env is **intermediate** (below the production terminal `done`):
98
102
 
99
103
  1. Resolve the merged PR's base branch to its env via `.lisa.config.json` `deploy.branches` (`config-resolution`). If it maps to the production/terminal `done`, this phase is a **no-op** — native completion is correct there.
100
- 2. **Uniform / single-environment no-op.** When the project's env-keyed `done` map is uniform — every environment resolves to the same `status:done`, as in this repo (`production: main` only) and TunnlAI/frontend — dev-merge == terminal, so native completion is correct. Do nothing. Only a **non-uniform** env→`done` map (distinct `status:on-dev`/`status:on-stg`/`status:done` rungs) can desync.
101
- 3. Otherwise (non-uniform map, resolved env intermediate): re-read the Issue's native workflow `state`. If Linear natively moved it into a Done/Completed category while the derived `status:*` label is a lower env, **re-open** the native `state` back to the active/in-progress category (via `lisa-linear-access operation: save-issue`) so it mirrors the true env stage, and post a short `[lisa-linear-sync]` reconciliation comment. This applies the `leaf-only-lifecycle` "Terminal native closure" rule — native closure fires **only** at the production terminal `done` — as a *repair* of Linear front-running it. Cite the rule by slug; do not restate it.
102
- 4. **Safe default.** If the true terminal cannot be resolved (ambiguous env or unresolvable `done` map), do not change the native `state` — post a `[lisa-linear-sync]` reconciliation-suggestion comment and leave it untouched, mirroring the Phase 5 safe default.
104
+ 2. **Uniform / single-environment no-op.** When the project's env-keyed `done` map is uniform — every environment resolves to the same `Done`, as in this repo (`production: main` only) — dev-merge == terminal, so native completion is correct. Do nothing. Only a **non-uniform** env→`done` map (distinct `On Dev`/`On Stg`/`Done` rungs) can desync.
105
+ 3. Otherwise (non-uniform map, resolved env intermediate): re-read the Issue's `state`. If it sits in a `completed`-typed state while the derived role is a lower env rung, **re-open** the native state by moving it back to the correct env rung (via `lisa-linear-access operation: save-issue`) and post a short `[lisa-linear-sync]` reconciliation comment **naming the likely cause** — a live `merge → Done` git automation, or a magic word in the PR body. This applies the `leaf-only-lifecycle` "Terminal native closure" rule — closure fires **only** at the production terminal `done`. Cite the rule by slug; do not restate it.
106
+ 4. **Safe default.** If the true terminal cannot be resolved (ambiguous env or unresolvable `done` map), do not change the `state` — post a `[lisa-linear-sync]` reconciliation-suggestion comment and leave it untouched, mirroring the Phase 5 safe default.
103
107
 
104
108
  ## Phase 5 — Parent Status Rollup (`--rollup`)
105
109
 
106
- When the caller passes `--rollup`, this skill **derives a parent/container's `status:*` label from the roll-up of its children** instead of acting on a leaf. A **Project** (the Epic equivalent) rolls up from its Issues; an **Issue** rolls up from its sub-Issues. This implements the Linear child-issue-status arm of the **Parent status rollup (the state machine)** section of the `leaf-only-lifecycle` rule — cite that rule, do not restate the policy.
110
+ When the caller passes `--rollup`, this skill **derives a parent/container's workflow state from the roll-up of its children** instead of acting on a leaf. A **Project** (the Epic equivalent) rolls up from its Issues; an **Issue** rolls up from its sub-Issues. This implements the Linear child-issue-status arm of the **Parent status rollup (the state machine)** section of the `leaf-only-lifecycle` rule — cite that rule, do not restate the policy.
107
111
 
108
- **Resolve the child set the same way `lisa-linear-read-issue` does** — `lisa-linear-access operation: list-issues({project: <id>})` for a Project's Issues, or `lisa-linear-access operation: get-issue` per child for an Issue's sub-Issues (via `parentId`). Capture each child's `status:*` label. If the item has **no** children it is a leaf — rollup is N/A; behave as a normal milestone sync.
112
+ **Resolve the child set the same way `lisa-linear-read-issue` does** — `lisa-linear-access operation: list-issues({project: <id>})` for a Project's Issues, or `lisa-linear-access operation: get-issue` per child for an Issue's sub-Issues (via `parentId`). Capture each child's workflow state. If the item has **no** children it is a leaf — rollup is N/A; behave as a normal milestone sync.
109
113
 
110
- **Evaluate the required children over the env ladder `in-progress < dev < staging < production` (the ordered keys of the Linear env-keyed `done` map, e.g. `status:on-dev < status:on-stg < status:done`) and take the first match** (canonical roles from `config-resolution`; Linear label map is `status:blocked`, `status:in-progress`, `status:code-review`, env-keyed `done`):
114
+ **Evaluate the required children over the env ladder `in-progress < dev < staging < production` (the ordered keys of the Linear env-keyed `done` map, e.g. `On Dev < On Stg < Done`) and take the first match** (canonical roles from `config-resolution`; the Linear state map is `Blocked`, `In Progress`, `In Review`, env-keyed `done`):
111
115
 
112
116
  | If among the required child leaves… | Derived parent role | Linear label |
113
117
  |---|---|---|
114
- | any child carries `status:blocked` | `blocked` | `status:blocked` |
115
- | else **every** required child has shipped to some env (each at a `done`-map label, e.g. `status:on-dev`/`status:on-stg`/`status:done`) | `done[min-env]` | the **least-advanced** env label among them (all `status:on-stg` → `status:on-stg`; mixed dev+staging → `status:on-dev`; all production → `status:done`) |
116
- | else any child has **started** (`status:in-progress` / `status:code-review`, or shipped to an env while a sibling has not) | `claimed` | `status:in-progress` |
118
+ | any child carries `Blocked` | `blocked` | `Blocked` |
119
+ | else **every** required child has shipped to some env (each at a `done`-map label, e.g. `On Dev`/`On Stg`/`Done`) | `done[min-env]` | the **least-advanced** env label among them (all `On Stg` → `On Stg`; mixed dev+staging → `On Dev`; all production → `Done`) |
120
+ | else any child has **started** (`In Progress` / `In Review`, or shipped to an env while a sibling has not) | `claimed` | `In Progress` |
117
121
  | else (children exist, none started) | — | unchanged — parent keeps its non-ready container label |
118
122
 
119
- - **Blocked dominates** — one blocked child surfaces `status:blocked` on the parent even while siblings progress.
120
- - **Least-advanced env wins** — the parent reaches an env only when every required child has reached at least that env; it never sits ahead of its laggard child. Native completion (moving the workflow `state` to Done) fires only when the resolved env is the production `status:done`, never at `status:on-dev`/`status:on-stg`.
123
+ - **Blocked dominates** — one blocked child surfaces `Blocked` on the parent even while siblings progress.
124
+ - **Least-advanced env wins** — the parent reaches an env only when every required child has reached at least that env; it never sits ahead of its laggard child. Native completion (moving the workflow `state` to Done) fires only when the resolved env is the production `Done`, never at `On Dev`/`On Stg`.
121
125
  - **"Required" children only** — won't-do / optional (e.g. `Canceled`) children do not hold the parent open.
122
126
  - **Recursive** — a Project reaches an env only when its Issues have themselves rolled up to at least that env. Evaluate bottom-up.
123
- - **Never set the parent to `status:ready`** — `ready` is leaf-only. Rollup only moves the parent between non-ready container labels.
127
+ - **Never set the parent to `Todo`** — `ready` is leaf-only. Rollup only moves the parent between non-ready container labels.
124
128
 
125
- **Single-environment collapse (this repo).** The env rungs resolve via the env-keyed `done` logic in `config-resolution`. In this repo `deploy.branches` declares only `production: main`, so `done` collapses to the single `status:done` label, the only env rung is production, and the lifecycle is `status:readystatus:in-progressstatus:code-reviewstatus:done` with **no** dev/staging promotion hops; the rollup never resolves a dev or staging `done`. Multi-environment projects keep the env-keyed map and roll a parent up to intermediate env labels (`status:on-dev`/`status:on-stg`).
129
+ **Single-environment collapse (this repo).** The env rungs resolve via the env-keyed `done` logic in `config-resolution`. In this repo `deploy.branches` declares only `production: main`, so `done` collapses to the single `Done` state, the only env rung is production, and the lifecycle is `TodoIn Progress In Review Done` with **no** dev/staging promotion hops; the rollup never resolves a dev or staging `done`. Multi-environment projects keep the env-keyed map and roll a parent up to the intermediate env states (`On Dev`/`On Stg`).
126
130
 
127
- **Apply the derived label** via `lisa-linear-access operation: save-issue` (Project or Issue), removing the parent's existing `status:*` and adding the derived one so exactly one `status:*` label remains. Post an idempotent rollup comment naming the derived state and the child tally. The native Linear `state` is **not** auto-transitioned only the `status:*` label, mirroring the `--update-label` rule. **Safe default:** if the derived terminal cannot be resolved (ambiguous required-set or unresolvable env `done`), do not guess — post the derived suggestion as a comment and leave the parent's label untouched.
131
+ **Apply the derived state** via `lisa-linear-access operation: save-issue` (Project or Issue), setting the parent's `stateId` to the derived role. Post an idempotent rollup comment naming the derived state and the child tally. Because the terminal `done` state is itself typed `completed`, a parent rolled to terminal is natively closed by the same write — there is no second closure step. **Safe default:** if the derived terminal cannot be resolved (ambiguous required-set or unresolvable env `done`), do not guess — post the derived suggestion as a comment and leave the parent's state untouched.
128
132
 
129
133
  ## Rules
130
134
 
131
- - Never auto-transition the native Linear `state` — only the label, and only when the caller explicitly asks (`--update-label`, or `--rollup` for parent derivation per the `leaf-only-lifecycle` rule).
132
- - Rollup derives a *parent's* `status:*` label from its children and never sets a parent to `status:ready`. It cites the `leaf-only-lifecycle` rule by slug rather than restating the state machine.
135
+ - Never auto-transition the native Linear `state` — only the label, and only when the caller explicitly asks (`--update-state`, or `--rollup` for parent derivation per the `leaf-only-lifecycle` rule).
136
+ - Rollup derives a *parent's* workflow state from its children and never rolls a parent into the human-owned ready lane (never `$READY`). It cites the `leaf-only-lifecycle` rule by slug rather than restating the state machine.
133
137
  - Never post empty or minimal comments — if a milestone has no meaningful content, skip the post.
134
138
  - Do not delete prior milestone comments. They are the audit trail.
135
139
  - If `save_comment` fails, retry once. If it fails again, surface the error.
@@ -292,7 +292,7 @@ For each epic identified in Phase 1, **invoke the `lisa-tracker-write` skill** (
292
292
  - `artifacts`: the full Phase 1.5 artifact list — every artifact, regardless of domain. The epic is the canonical hub. No filtering at the epic level.
293
293
  - `priority`, `labels`, `components`, `fix_version`: as appropriate
294
294
 
295
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: an Epic is a container, not a leaf work unit. Do NOT mark it build-ready — `lisa-tracker-write` must not be passed `status:ready` for an Epic, and the Epic's lifecycle state rolls up from its children. The build-ready label is applied only in Phase 5.
295
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: an Epic is a container, not a leaf work unit. Do NOT mark it build-ready — `lisa-tracker-write` must not be passed the build-ready role for an Epic, and the Epic's lifecycle state rolls up from its children. The build-ready role is applied only in Phase 5.
296
296
 
297
297
  Capture the returned epic key — Phase 4 needs it as the parent for stories.
298
298
 
@@ -323,7 +323,7 @@ For each story, **invoke `lisa-tracker-write`** with:
323
323
  | Infrastructure | `ops`, `reference` |
324
324
  | Mixed / setup ("X.0") | All domains |
325
325
 
326
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: a Story is a container (it has child Sub-tasks), not a leaf work unit. Do NOT mark it build-ready — never pass `status:ready` to `lisa-tracker-write` for a Story. Its lifecycle state rolls up from its Sub-tasks. The build-ready label is applied only in Phase 5.
326
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: a Story is a container (it has child Sub-tasks), not a leaf work unit. Do NOT mark it build-ready — never pass the build-ready role to `lisa-tracker-write` for a Story. Its lifecycle state rolls up from its Sub-tasks. The build-ready role is applied only in Phase 5.
327
327
 
328
328
  Capture each returned story key — Phase 5 needs it as the parent for sub-tasks.
329
329
 
@@ -340,7 +340,7 @@ Each sub-task MUST:
340
340
  2. **Include an Empirical Verification Plan** — real user-like verification, NOT unit tests, linting, or typechecking
341
341
  3. **Carry its own `## Source Requirement` section** (shared format above) with the full verbatim quote(s) from the Phase 1.4 register — a leaf claimed by build-intake in isolation must be self-explanatory. When a sub-task is split per-repo, every split child inherits the same requirement quote(s).
342
342
 
343
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready label. `lisa-tracker-write` applies `status:ready` here so downstream build intake (`lisa-tracker-build-intake`) claims the leaves and never the Epic or Stories. Apply `status:ready` to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa-tracker-write` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
343
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready role. `lisa-tracker-write` applies the build-ready role here so downstream build intake (`lisa-tracker-build-intake`) claims the leaves and never the Epic or Stories. Apply the build-ready role to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa-tracker-write` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
344
344
 
345
345
  Sub-tasks inherit their parent story's artifacts by reference (the parent link). Do not pass the same artifact list to every sub-task.
346
346
 
@@ -61,12 +61,12 @@ authenticated_surface: true # → requires Sign-in Required
61
61
  artifacts_attached: true # → requires Source Precedence section
62
62
  relations: [{ id: "ENG-99", type: "blocked_by" }] # known issue relations (may be empty)
63
63
  remote_links: [{ url: "https://github.com/...", title: "PR #42" }]
64
- build_ready: true # caller asserts the build-ready role (status:ready) is/would be applied — see S15
64
+ build_ready: true # caller asserts the build-ready role (the `Todo` state) is/would be set — see S15
65
65
  child_refs: ["ENG-601", "ENG-602"] # known child work (sub-issues / project-member issues / blocked_by parentage) — see S15
66
66
  prd_source: "https://notion.so/..." # set when the Issue was generated from a PRD — requires the Source Requirement section, see S16
67
67
  ```
68
68
 
69
- If the caller passes only an identifier, fetch the item via `lisa-linear-access operation: get-issue` (Issue) or `lisa-linear-access operation: 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.
69
+ If the caller passes only an identifier, fetch the item via `lisa-linear-access operation: get-issue` (Issue) or `lisa-linear-access operation: get-project` (Project), derive the same fields from the fetched data — including `build_ready` (label set contains `Todo`) 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.
70
70
 
71
71
  ## Gates
72
72
 
@@ -235,9 +235,9 @@ This gate depends on S11. It is `N/A` for containers — a **Project** (the Epic
235
235
 
236
236
  #### S15 — Leaf-only build-ready
237
237
 
238
- 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.)
238
+ 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 `Todo` 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.)
239
239
 
240
- **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).
240
+ **When the gate applies.** Run S15 whenever the item is build-ready — i.e. `build_ready = true`, or the spec/live labels include `Todo`. If the item is not build-ready, S15 is `N/A` (nothing claims a non-ready item, so the invariant is vacuous).
241
241
 
242
242
  **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.
243
243
 
@@ -255,7 +255,7 @@ PASS (the childless-parent exception) when the item is build-ready and is a **le
255
255
  | Epic (Project) | no | yes | **FAIL** (childless Epic/Project — pure rollup container, exception does not apply) |
256
256
  | any | any | no | **N/A** (not build-ready) |
257
257
 
258
- 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."`
258
+ Remediation: `"Build-ready is leaf-only per leaf-only-lifecycle. Move the build-ready role 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."`
259
259
 
260
260
  `product_relevant: false` — a build-ready container is a lifecycle/decomposition error for the caller to repair, not a product question.
261
261
 
@@ -362,7 +362,7 @@ system, and never invent or ask for credentials inline.
362
362
 
363
363
  ## Execution
364
364
 
365
- 1. Parse `$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.
365
+ 1. Parse `$ARGUMENTS`. If it's an identifier, fetch the item and derive the spec from the fetched fields — including `build_ready` (label set contains `Todo`) 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.
366
366
  2. Resolve team ID via `lisa-linear-access operation: list-teams({query: <teamKey>})` if any feasibility gate will run.
367
367
  3. Run every Specification gate in order. Collect PASS / FAIL / N/A with a one-line reason.
368
368
  4. Unless the caller passed `--spec-only` (dry-run), run every Feasibility gate. Collect results.
@@ -31,7 +31,7 @@ Linear's data model maps Epic / Story / Sub-task to **different entity types**.
31
31
  | `Bug` | **Issue** | `lisa-linear-access operation: save-issue` | `projectId` if part of an Epic; else top-level |
32
32
  | `Spike` | **Issue** | `lisa-linear-access operation: save-issue` | `projectId` if part of an Epic; else top-level |
33
33
 
34
- Status workflow uses **labels** (`status:ready`, `status:in-progress`, `status:on-dev`, `status:done`) for portability across teamsLinear's per-team workflow state names vary, but labels are workspace-scoped and stable. Native Linear `state` is set to the team's default `Todo` state on create.
34
+ The build lifecycle uses native **workflow states** (`Todo`, `In Progress`, `In Review`, `Blocked`, `On Dev`, `On Stg`, `Done`), resolved per role from `linear.workflow` see "Why Linear uses states, not labels" in `config-resolution`. A new Issue is created in the team's default backlog/unstarted state unless `build_ready` promotes it (below).
35
35
 
36
36
  ## Phase 1 — Resolve Intent
37
37
 
@@ -227,7 +227,8 @@ If the item modifies an existing user-facing surface, a `lisa-product-walkthroug
227
227
 
228
228
  Before create/update, verify each field is populated where applicable:
229
229
 
230
- - **Labels**: include `status:ready` for a new **leaf** work unit (Bug / Task / Sub-task / Improvement with no child work) per `leaf-only-lifecycle`, **unless `build_ready: false`** (see the Build-ready control input below); component labels (`component:<name>`); status / priority labels are NOT redundant with native fields — labels exist for portability and downstream queries. A container (Epic Project / Story with sub-issues / Spike) never receives `status:ready`.
230
+ - **Workflow state**: set the resolved `ready` state (`linear.workflow.ready`, default `Todo`) on a new **leaf** work unit (Bug / Task / Sub-task / Improvement with no child work) per `leaf-only-lifecycle`, **unless `build_ready: false`** (see the Build-ready control input below). A container (Epic Project / Story with sub-issues / Spike) is never put in the build-ready state.
231
+ - **Labels**: taxonomy only — `type:<Kind>`, `repo:<name>`, `component:<name>`, and the `prd-intake-feedback` sentinel. Lifecycle is **not** a label on Linear; do not add `status:*` labels.
231
232
  - **Native priority field**: 0–4 per Linear's scale; explicit, not "unset".
232
233
  - **Native estimate**: per Linear's team-configured estimate scale (often 0–8 Fibonacci); skip for Epic / Spike.
233
234
  - **ProjectMilestone**: when the team uses dated milestones, set the milestone on the Project (Epic) or on the Issue (when an Issue belongs to a milestone).
@@ -238,11 +239,11 @@ For Bug / Task / Sub-task, ensure the summary is prefixed with `[<repo-name>]`.
238
239
 
239
240
  ### Build-ready control input (`build_ready`)
240
241
 
241
- `build_ready` is an optional write-control input (default: **omitted**). It governs whether a **leaf** work unit's `status:ready` label is applied on create. It never overrides `leaf-only-lifecycle` — a container is never stamped build-ready regardless of `build_ready`. "Not build-ready" is not a special state: the Issue is still created with Linear's default native `Todo` state; it just lacks the `status:ready` **label** the build lifecycle keys off, so a human can promote it later.
242
+ `build_ready` is an optional write-control input (default: **omitted**). It governs whether a **leaf** work unit is created **in the resolved `ready` workflow state**. It never overrides `leaf-only-lifecycle` — a container is never stamped build-ready regardless of `build_ready`. "Not build-ready" is not a special state: the Issue is simply left in the team's default backlog/unstarted state, which a human can promote later. This mirrors `lisa-jira-write-ticket`, because Linear is a state-driven tracker like JIRA, not a label-driven one like GitHub.
242
243
 
243
- - **Omitted** → current behavior: a leaf work unit receives `status:ready`. Preserves what every existing caller (`lisa-plan`, the `*-to-tracker` skills) relies on.
244
- - **`build_ready: false`** → create the leaf **without** the `status:ready` label, so it sits in the backlog for a human to review and promote into the queue.
245
- - **`build_ready: true`** → ensure the leaf carries `status:ready` so `lisa-intake` / `lisa-linear-build-intake` auto-picks it up.
244
+ - **Omitted** → current behavior: a leaf work unit is created in the resolved `ready` state. Preserves what every existing caller (`lisa-plan`, the `*-to-tracker` skills) relies on.
245
+ - **`build_ready: false`** → create the leaf **without** the `ready` state, leaving it in the team's default backlog state so it waits for a human to review and promote it into the queue.
246
+ - **`build_ready: true`** → transition the **leaf** to the resolved `ready` state (`.linear.workflow.ready`) so `lisa-intake` / `lisa-linear-build-intake` auto-picks it up. Best-effort: if the state cannot be resolved or the transition is rejected, do not fail the write — leave the Issue in its default state and record the reason.
246
247
 
247
248
  ## Phase 5.5 — Validate (Pre-write Gate)
248
249
 
@@ -268,7 +269,7 @@ If the validator reports `PASS`, continue to Phase 6.
268
269
 
269
270
  ### CREATE — Story / Task / Bug / Spike / Improvement (Issue with projectId)
270
271
 
271
- 1. Resolve any required Issue labels (`component:<name>`, `prd-intake-feedback` only if this is a sentinel issue, etc.) via `lisa-linear-access operation: list-issue-labels` (create via `lisa-linear-access operation: create-issue-label` if missing). Include `status:ready` in `labelIds` only for a **leaf** work unit and only when `build_ready` is not `false` (per the Build-ready control input) — omit it for a container, and for a `build_ready: false` leaf which then waits in the backlog for a human to promote it.
272
+ 1. Resolve any required Issue labels (`type:<Kind>`, `repo:<name>`, `component:<name>`, `prd-intake-feedback` only if this is a sentinel issue) via `lisa-linear-access operation: list-issue-labels` (create via `lisa-linear-access operation: create-issue-label` if missing). Separately resolve the `ready` **state** id via `lisa-linear-access operation: list-workflow-states`, and set it as `stateId` only for a **leaf** work unit and only when `build_ready` is not `false` — omit it for a container, and for a `build_ready: false` leaf which then waits in the default backlog state for a human to promote it.
272
273
  2. Call `lisa-linear-access operation: save-issue` with: `team` (teamId), `title` (summary), `description` (markdown), `projectId` (the Epic Project), `priority` (0–4), `estimate`, `labelIds`, `assignee` if known.
273
274
  3. Capture the returned identifier (e.g. `ENG-123`) — Phase 4 sub-tasks need it as `parentId`.
274
275
  4. Add relationships from Phase 4b via `save_issue` (relations field) or paired relation calls.
@@ -280,7 +280,7 @@ For each PRD epic, **invoke the `lisa-tracker-write` skill** (do not call `creat
280
280
  - `artifacts`: the full Phase 1.5 artifact list — every artifact, regardless of domain. The epic is the canonical hub, and anyone working on the epic or its descendants must be able to reach the full set from one place. No filtering at the epic level. `lisa-tracker-write` Phase 4c attaches them as remote links.
281
281
  - `priority`, `labels`, `components`, `fix_version`: as appropriate
282
282
 
283
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: an Epic is a container, not a leaf work unit. Do NOT mark it build-ready — `lisa-tracker-write` must not be passed `status:ready` for an Epic, and the Epic's lifecycle state rolls up from its children. The build-ready label is applied only in Phase 5.
283
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: an Epic is a container, not a leaf work unit. Do NOT mark it build-ready — `lisa-tracker-write` must not be passed the build-ready role for an Epic, and the Epic's lifecycle state rolls up from its children. The build-ready role is applied only in Phase 5.
284
284
 
285
285
  Capture the returned epic key — Phase 4 needs it as the parent for stories.
286
286
 
@@ -314,7 +314,7 @@ For each story, **invoke `lisa-tracker-write`** with:
314
314
  - `artifacts`: the Phase 1.5 artifacts filtered by domain per the inheritance table below — `lisa-tracker-write` Phase 4c attaches them as remote links
315
315
  - `priority`, `labels`, `components`, `fix_version`: as appropriate
316
316
 
317
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: a Story is a container (it has child Sub-tasks), not a leaf work unit. Do NOT mark it build-ready — never pass `status:ready` to `lisa-tracker-write` for a Story. Its lifecycle state rolls up from its Sub-tasks. The build-ready label is applied only in Phase 5.
317
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: a Story is a container (it has child Sub-tasks), not a leaf work unit. Do NOT mark it build-ready — never pass the build-ready role to `lisa-tracker-write` for a Story. Its lifecycle state rolls up from its Sub-tasks. The build-ready role is applied only in Phase 5.
318
318
 
319
319
  Capture each returned story key — Phase 5 needs it as the parent for sub-tasks.
320
320
 
@@ -342,7 +342,7 @@ Each sub-task MUST:
342
342
  2. **Include an Empirical Verification Plan** — real user-like verification, NOT unit tests, linting, or typechecking
343
343
  3. **Carry its own `## Source Requirement` section** (shared format above) with the full verbatim quote(s) from the Phase 1.4 register — a leaf claimed by build-intake in isolation must be self-explanatory. When a sub-task is split per-repo, every split child inherits the same requirement quote(s).
344
344
 
345
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready label. `lisa-tracker-write` applies `status:ready` here so downstream build intake (`lisa-tracker-build-intake`) claims the leaves and never the Epic or Stories. Apply `status:ready` to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa-tracker-write` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
345
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready role. `lisa-tracker-write` applies the build-ready role here so downstream build intake (`lisa-tracker-build-intake`) claims the leaves and never the Epic or Stories. Apply the build-ready role to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa-tracker-write` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
346
346
 
347
347
  **Verification plan examples by stack:**
348
348
  - **Backend APIs**: curl GraphQL/REST calls with auth token, database queries, checking audit entries
@@ -178,7 +178,7 @@ rule — never hardcode status/label strings. The relevant repair roles:
178
178
  |-----------|--------|----------------------|------------------|----------------------------|
179
179
  | Build | JIRA | `jira.workflow.claimed` (`In Progress`) | `jira.workflow.blocked` (`Blocked`) | env-resolved `jira.workflow.done` |
180
180
  | Build | GitHub | `github.labels.build.claimed` (`status:in-progress`) | `github.labels.build.blocked` (`status:blocked`) | env-resolved `github.labels.build.done` (`status:done`) |
181
- | Build | Linear | `linear.labels.build.claimed` (`status:in-progress`) | `linear.labels.build.blocked` (`status:blocked`) | env-resolved `linear.labels.build.done` (`status:done`) |
181
+ | Build | Linear | `linear.workflow.claimed` (`In Progress`) | `linear.workflow.blocked` (`Blocked`) | env-resolved `linear.workflow.done` (`Done`) |
182
182
  | PRD | Notion | `notion.values.in_review` (`In Review`) | `notion.values.blocked` (`Blocked`) | `notion.values.shipped` (`Shipped`) |
183
183
  | PRD | GitHub | `github.labels.prd.in_review` (`prd-in-review`) | `github.labels.prd.blocked` (`prd-blocked`) | `github.labels.prd.shipped` (`prd-shipped`) |
184
184
  | PRD | Linear | `linear.labels.prd.in_review` (`prd-in-review`) | `linear.labels.prd.blocked` (`prd-blocked`) | `linear.labels.prd.shipped` (`prd-shipped`) |
@@ -152,19 +152,41 @@ read_role() { # $1=namespace (build|prd) $2=role $3=default
152
152
  }
153
153
  ```
154
154
 
155
- #### 3a. Build-queue labelsISSUE labels (only if Linear is the tracker)
155
+ #### 3a. Build-queue lifecycleWORKFLOW STATES (only if Linear is the tracker)
156
156
 
157
- Probe with `lisa-linear-access operation: list-issue-labels` (scoped to the team). For each role's resolved name, create it via `lisa-linear-access operation: create-issue-label` only if absent. The `done` role is env-keyed create all three defaults; collapse to a single string in config later if the project's terminal state is env-independent.
157
+ The build lane resolves to native workflow **states**, not labels see "Why Linear uses states, not labels" in `config-resolution`. Read role state name with the same ladder, against `linear.workflow`:
158
158
 
159
- | Role | Default |
160
- |------|---------|
161
- | `ready` | `status:ready` |
162
- | `claimed` | `status:in-progress` |
163
- | `review` | `status:code-review` |
164
- | `blocked` | `status:blocked` |
165
- | `done.dev` | `status:on-dev` |
166
- | `done.staging` | `status:on-stg` |
167
- | `done.production` | `status:done` |
159
+ ```bash
160
+ read_state() { # $1=role path (e.g. ready, done.dev) $2=default
161
+ local role="$1" default="$2" local_v global_v
162
+ local_v=$(jq -r ".linear.workflow.${role} // empty" .lisa.config.local.json 2>/dev/null)
163
+ global_v=$(jq -r ".linear.workflow.${role} // empty" .lisa.config.json 2>/dev/null)
164
+ echo "${local_v:-${global_v:-$default}}"
165
+ }
166
+ ```
167
+
168
+ Enumerate the team's states with `lisa-linear-access operation: list-workflow-states` (each carries `id`, `name`, `type`, `position`). For each role, resolve in this order — the same cascade `lisa-setup-jira` uses, with one extra rung Linear affords that JIRA does not:
169
+
170
+ 1. **Exact name match** → resolved, nothing to do.
171
+ 2. **A plausible existing state of the right `type`** (`ready` → `unstarted`, `claimed`/`review` → `started`, `blocked` → `started` or `unstarted`, terminal `done` → `completed`) → present the team's state list via `AskUserQuestion` and let the user pick which state means this role. Record the choice as a config override in Step 4.
172
+ 3. **Nothing plausible** → offer to **create** the state via `lisa-linear-access operation: create-workflow-state` (name, `type`, `position`, colour), showing the exact name and type first. Linear's API permits this where JIRA's workflow editing is admin-gated — which is why this rung exists here and not there.
173
+ 4. **User declines creation** → stop and say which role is unresolvable and that the lifecycle cannot run without it. Never silently fall back to a state whose meaning differs, and never invent a name in config that does not exist in the team.
174
+
175
+ | Role | Default state | `type` | Ships with a stock team? |
176
+ |------|---------------|--------|--------------------------|
177
+ | `ready` | `Todo` | `unstarted` | yes |
178
+ | `claimed` | `In Progress` | `started` | yes |
179
+ | `review` | `In Review` | `started` | yes |
180
+ | `blocked` | `Blocked` | `unstarted` | **no — must be created or mapped** |
181
+ | `done.dev` | `On Dev` | `started` | **no — must be created or mapped** |
182
+ | `done.staging` | `On Stg` | `started` | **no — must be created or mapped** |
183
+ | `done.production` | `Done` | `completed` | yes |
184
+
185
+ **The env rungs are deliberately `started`, not `completed`.** `On Dev` and `On Stg` mean "merged and deployed *that far*" — work that is emphatically not finished. Typing them `completed` would make Linear treat them as closed: they would leave the active board, stop counting in cycles, and re-create the exact premature-closure problem this model exists to fix. Only `done.production` is `completed`.
186
+
187
+ **Position them between `In Review` and `Done`** so the board reads left-to-right in real lifecycle order. A team that orders its board differently can pass its own `position`.
188
+
189
+ **Turn off the team's `merge → Done` git automation.** Linear's per-team git automations (Settings → Team → Workflow, or the `gitAutomationStates` API) auto-complete an Issue on merge to **any** branch. With this model that automation is an unwanted second writer: it jumps an Issue straight to `Done` at a `dev` merge, skipping `On Dev` / `On Stg` and asserting production-done. Lisa itself moves the state at each rung, so the automation is redundant as well as wrong. Detect it and offer to delete it; leave `start` and `review` alone — those assert non-terminal states and are harmless.
168
190
 
169
191
  #### 3b. PRD-lifecycle labels — PROJECT labels (only if Linear is the PRD source)
170
192
 
@@ -205,14 +227,39 @@ if [ -n "$TEAM_KEY" ]; then
205
227
  .lisa.config.json > .lisa.config.json.tmp && mv .lisa.config.json.tmp .lisa.config.json
206
228
  fi
207
229
 
208
- # Conditionally write label overrides (only non-default role names).
230
+ # Conditionally write label overrides (markers + PRD lane only the build lane
231
+ # is states now, and lives under .linear.workflow below).
209
232
  if [ -n "$LABEL_OVERRIDES_JSON" ] && [ "$LABEL_OVERRIDES_JSON" != "{}" ]; then
210
233
  jq --argjson o "$LABEL_OVERRIDES_JSON" \
211
234
  '.linear.labels = ((.linear.labels // {}) * $o)' \
212
235
  .lisa.config.json > .lisa.config.json.tmp && mv .lisa.config.json.tmp .lisa.config.json
213
236
  fi
237
+
238
+ # Workflow-state overrides: only roles whose resolved state name differs from
239
+ # the default, INCLUDING any the user mapped onto an existing state in 3a.
240
+ if [ -n "$WORKFLOW_OVERRIDES_JSON" ] && [ "$WORKFLOW_OVERRIDES_JSON" != "{}" ]; then
241
+ jq --argjson w "$WORKFLOW_OVERRIDES_JSON" \
242
+ '.linear.workflow = ((.linear.workflow // {}) * $w)' \
243
+ .lisa.config.json > .lisa.config.json.tmp && mv .lisa.config.json.tmp .lisa.config.json
244
+ fi
214
245
  ```
215
246
 
247
+ **Migrating a project that predates the state model.** A config carrying
248
+ `linear.labels.build.{ready,claimed,review,blocked,done}` was written against the
249
+ old label-driven lane. Those keys are inert now — nothing reads them — but
250
+ leaving them in place reads as configuration and will mislead the next person.
251
+ Migrate in one pass, and do it before the first intake cycle runs, or that cycle
252
+ sees an empty queue:
253
+
254
+ 1. Resolve each build role to a state per 3a, writing `linear.workflow`.
255
+ 2. **Backfill live Issues**: for every Issue carrying a `status:*` label, set its
256
+ workflow state to the role that label encoded. Do this before deleting
257
+ anything — the labels are the only record of where each Issue sits.
258
+ 3. Drop `build.{ready,claimed,review,blocked,done}` from `linear.labels`, keeping
259
+ `build.human_needed` and the whole `prd` map.
260
+ 4. Leave the `status:*` labels themselves in the workspace, unapplied, until the
261
+ first intake cycle after the migration has run green. They are the rollback.
262
+
216
263
  No secrets in config — the API key stays in keychain / `LINEAR_API_KEY`, the MCP session in its own store.
217
264
 
218
265
  ### Step 5 — Offer to set top-level `tracker` / `source`
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: lisa-tracker-build-intake
3
- description: "Vendor-neutral wrapper for the build-queue scanner. Reads the required `tracker` from .lisa.config.json and dispatches to lisa-jira-build-intake (JQL/project-key queue), lisa-github-build-intake (GitHub repo queue keyed off the `status:ready` label), or lisa-linear-build-intake (Linear team queue keyed off the `status:ready` label). Every vendor scanner processes at most one eligible item per cycle and enforces the claim-time arm of the `leaf-only-lifecycle` rule — dispatch leaf work units only; move or safe-block a container with open child work (or a childless Epic) that carries a stale build-ready role according to the vendor's lifecycle semantics. Counterpart to lisa-intake's PRD-side dispatchers."
3
+ description: "Vendor-neutral wrapper for the build-queue scanner. Reads the required `tracker` from .lisa.config.json and dispatches to lisa-jira-build-intake (JQL/project-key queue), lisa-github-build-intake (GitHub repo queue keyed off the `status:ready` label), or lisa-linear-build-intake (Linear team queue keyed off the configured `ready` workflow state). Every vendor scanner processes at most one eligible item per cycle and enforces the claim-time arm of the `leaf-only-lifecycle` rule — dispatch leaf work units only; move or safe-block a container with open child work (or a childless Epic) that carries a stale build-ready role according to the vendor's lifecycle semantics. Counterpart to lisa-intake's PRD-side dispatchers."
4
4
  allowed-tools: ["Skill", "Bash", "Read"]
5
5
  ---
6
6
 
@@ -21,7 +21,7 @@ See the `config-resolution` rule for configuration and dispatch table.
21
21
  - Anything else → stop and report `"Unknown tracker '<value>' in .lisa.config.json. Expected 'jira', 'github', or 'linear'."`
22
22
  3. Pass through the output.
23
23
 
24
- `$ARGUMENTS` is forwarded verbatim, including the optional `--rollup` flag (see "Parent status rollup" below), `--update-label`, `pr_url=<url>`, and `merge_sha=<sha>`. The shim never interprets these — the vendor skill does.
24
+ `$ARGUMENTS` is forwarded verbatim, including the optional `--rollup` flag (see "Parent status rollup" below), the vendor lane-write flag (`--update-label` on GitHub, `--update-state` on Linear), `pr_url=<url>`, and `merge_sha=<sha>`. The shim never interprets these — the vendor skill does.
25
25
 
26
26
  If `$ARGUMENTS` is empty, all vendor skills auto-detect a ticket reference from the active plan file (most recently modified `.md` in `plans/`).
27
27
 
@@ -60,6 +60,6 @@ This is the reverse half of `lisa-git-submit-pr`'s PR body linkage. A PR that me
60
60
  ## Rules
61
61
 
62
62
  - Idempotent updates — running sync at the same milestone twice should not produce duplicate comments. Vendor skills enforce this.
63
- - Never auto-transition the underlying state. Linear's label-based transition (`status:*`) is the canonical signal and is updated only when the caller passes `--update-label`. Native states stay as suggestions.
63
+ - Never auto-transition a lane the caller did not ask for. On GitHub the canonical signal is the `status:*` label, written only with `--update-label`; on Linear it is the native workflow state, written only with `--update-state`. Without the flag, every vendor arm only suggests.
64
64
  - Parent rollup derives state from children per the `leaf-only-lifecycle` rule; it never sets a parent to `ready` and never resolves a dev/staging `done` in this single-environment repo.
65
65
  - Pull request backlinks are mandatory when `pr_url=<url>` is present: native first, managed-comment fallback, never silently dropped.
@@ -47,7 +47,7 @@ Use the `linear-verify` skill to check the item against organizational standards
47
47
 
48
48
  **Gating behavior — this is the one place auto-transitioning is allowed:**
49
49
 
50
- Resolve build labels from `.lisa.config.json` `linear.labels.build.*` (defaults: `status:ready` / `status:in-progress` / `status:code-review`); resolve the `blocked` label from the same section (`linear.labels.build.blocked`, default `status:blocked`) and the `human_needed` marker label from the same section (`linear.labels.build.human_needed`, default `human-needed`).
50
+ Resolve build labels from `.lisa.config.json` `linear.workflow.*` (defaults: `Todo` / `In Progress` / `In Review`); resolve the `blocked` label from the same section (`linear.workflow.blocked`, default `Blocked`) and the `human_needed` marker label from the same section (`linear.labels.build.human_needed`, default `human-needed`).
51
51
 
52
52
  If `linear-verify` returns `FAIL` on any of the above, do NOT continue to build. **Draft the missing spec content first, then block for confirmation** — never bounce a raw "go write all this" checklist back to the creator:
53
53
  1. **Best-effort autofill (before blocking).** Run `pre-flight-autofill` for every work item. Preserve a human bare configured key or `Confirmed: <env>`; automation writes `Inferred: <env> — evidence: <title|body|reproduction|hostname>`, `Assumption: <env> — remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` otherwise. Human confirmation replaces the annotation with the bare key or `Confirmed: <env>`. For a legacy bare value, use managed draft markers and current ticket content only; provider edit history is not required. A marker proves automation and requires re-annotation; otherwise unknown provenance plus conflicting evidence stops for confirmation. Resolve one exact `deploy.branches` key from the human-authored title, body, and reproduction steps or URL hostname; exclude the complete `Target Backend Environment` section and other machine-authored metadata/draft blocks so annotations cannot become evidence. A reported bug environment is an example, not a restriction. Evidence supersedes only `Assumption:`. Normalize `prod` ↔ `production` only when exactly one is configured; no other aliases exist. Conflicts stop; never infer from arbitrary branch text, URL paths/query strings, or substrings. Write through `linear-write-issue`, never overwrite human prose, then re-run `linear-verify`.
@@ -116,13 +116,13 @@ Use the `linear-evidence` skill to:
116
116
 
117
117
  ### 8. Suggest Status Transition
118
118
 
119
- Based on the milestone, suggest (but don't auto-transition the native Linear `state`). Label role names are resolved from `.lisa.config.json` `linear.labels.build.*`:
119
+ Based on the milestone, suggest (but don't auto-transition the native Linear `state`). Label role names are resolved from `.lisa.config.json` `linear.workflow.*`:
120
120
 
121
121
  | Milestone | Suggested role | Default label |
122
122
  |-----------|----------------|---------------|
123
- | Plan created | `claimed` | `status:in-progress` |
124
- | PR ready | `review` | `status:code-review` |
125
- | PR merged | `done` (env-aware; build-intake performs if dispatched via that flow) | env-keyed variant per `linear.labels.build.done` |
123
+ | Plan created | `claimed` | `In Progress` |
124
+ | PR ready | `review` | `In Review` |
125
+ | PR merged | `done` (env-aware; build-intake performs if dispatched via that flow) | env-keyed variant per `linear.workflow.done` |
126
126
 
127
127
  Note: `done` may be a string or an env-keyed map (`{ dev, staging, production }`). When suggesting the PR-merged transition, the env is implied by the PR's base branch via `deploy.branches` — surface the resolved label name; do not auto-transition.
128
128
 
@@ -132,7 +132,7 @@ The label transitions ARE the canonical signal. The native `state` field stays a
132
132
 
133
133
  - Never auto-transition the native Linear `state`, with one explicit exception: when `linear-verify` returns `FAIL` for the pre-flight gate (Step 2), first run the `pre-flight-autofill` draft-then-block procedure (draft the authorable missing sections into the description as labeled assumptions), then update labels to the configured `blocked` label, add the configured `human_needed` marker label (`linear.labels.build.human_needed`, default `human-needed`), and reassign to the creator with a confirmation comment. Every other status change remains a label-driven suggestion.
134
134
  - Always read the full item graph via `linear-read-issue` before determining intent — don't rely on type labels alone.
135
- - Never create or materially edit an item by calling MCP write tools directly — always delegate to `linear-write-issue` so relationships, Gherkin criteria, and metadata gates are enforced. Two explicit exceptions are permitted: (1) the Step 2 pre-flight failure path (when `linear-verify` returns `FAIL`) may call `lisa-linear-access operation: save-issue` and `lisa-linear-access operation: save-comment` directly to set `status:blocked`, add the configured `human_needed` marker label, and reassign to the creator — this narrow exception is already granted by the rule above; (2) the Step 3 triage path may call `lisa-linear-access operation: save-comment` to post triage findings and `lisa-linear-access operation: save-issue` to add the `claude-triaged-{repo}` label — these are lightweight metadata updates that do not create or materially edit ticket content and therefore do not need to route through `linear-write-issue`.
135
+ - Never create or materially edit an item by calling MCP write tools directly — always delegate to `linear-write-issue` so relationships, Gherkin criteria, and metadata gates are enforced. Two explicit exceptions are permitted: (1) the Step 2 pre-flight failure path (when `linear-verify` returns `FAIL`) may call `lisa-linear-access operation: save-issue` and `lisa-linear-access operation: save-comment` directly to set `Blocked`, add the configured `human_needed` marker label, and reassign to the creator — this narrow exception is already granted by the rule above; (2) the Step 3 triage path may call `lisa-linear-access operation: save-comment` to post triage findings and `lisa-linear-access operation: save-issue` to add the `claude-triaged-{repo}` label — these are lightweight metadata updates that do not create or materially edit ticket content and therefore do not need to route through `linear-write-issue`.
136
136
  - If sign-in credentials are in the item, extract and pass them to the flow. If the item touches an authenticated surface and credentials are missing, that is a Step 2 failure — block and reassign rather than guessing.
137
137
  - If the item has a Validation Journey section, pass it to the verifier agent. The Validation Journey's local-verification step must point at the target backend environment named in the description.
138
138
  - The environment handoff for every work item uses the same durable grammar: human bare configured key or `Confirmed: <env>`; automated `Inferred: <env> — evidence: <title|body|reproduction|hostname>`, `Assumption: <env> — remote default branch <branch>` for a unique reverse-map, or `Assumption: remote default branch <branch>` otherwise. Human confirmation replaces an automated annotation with the bare key or `Confirmed: <env>`. For legacy bare values, managed draft markers and current ticket content decide provenance; provider edit history is not required. A marker proves automation; otherwise unknown provenance plus conflicting evidence stops for confirmation. Human-confirmed wins, then validated `Inferred:`; otherwise one exact `deploy.branches` key from the human-authored title, body, and reproduction steps or URL hostname drives the implementation base branch. Exclude the complete `Target Backend Environment` section and other machine-authored metadata/draft blocks so annotations cannot become evidence. Evidence supersedes only `Assumption:`. Normalize `prod` ↔ `production` only when exactly one is configured; no other aliases exist. Conflicts stop. Never infer from arbitrary branch text, URL paths/query strings, or substrings. With no signal, use the remote default and record the applicable assumption without blocking on a non-unique reverse-map. Require any selected mapping and remote branch. A reported bug environment is an example of the all-work-type rule. Non-integration fixes still require the linked forward cherry-pick.
@@ -17,7 +17,7 @@ skills:
17
17
 
18
18
  You are a Linear build-intake agent. Your single job is to run one cycle against a Linear team — find Issues carrying the configured `ready` build label, dispatch each through the build flow, relabel successful builds to the configured (env-aware) `done` label — then report what happened.
19
19
 
20
- Build-label role names (`ready`, `claimed`, `review`, `done`) are resolved from `.lisa.config.json` `linear.labels.build.*` by the `linear-build-intake` skill. The defaults match the legacy hardcoded names (`status:ready`, `status:in-progress`, `status:code-review`, env-keyed `{ dev: status:on-dev, staging: status:on-stg, production: status:done }`).
20
+ Build-lifecycle role names (`ready`, `claimed`, `review`, `blocked`, `done`) are resolved from `.lisa.config.json` `linear.workflow.*` by the `linear-build-intake` skill, and name native **workflow states**, not labels. Defaults: `Todo`, `In Progress`, `In Review`, `Blocked`, env-keyed `{ dev: "On Dev", staging: "On Stg", production: "Done" }`.
21
21
 
22
22
  ## Confirmation policy
23
23
 
@@ -27,7 +27,7 @@ Once you have a team key, RUN. Do not ask the caller whether to proceed, do not
27
27
 
28
28
  ### 1. Receive the query
29
29
 
30
- The invoking caller (a slash command, a scheduled cron, or a parent agent) hands you a Linear team key (e.g. `ENG`) or the literal token `linear` (which falls back to `linear.teamKey` in `.lisa.config.json`). You do not pick the team yourself. Lifecycle label names are read from `linear.labels.build.*` and are not your concern at this layer.
30
+ The invoking caller (a slash command, a scheduled cron, or a parent agent) hands you a Linear team key (e.g. `ENG`) or the literal token `linear` (which falls back to `linear.teamKey` in `.lisa.config.json`). You do not pick the team yourself. Lifecycle label names are read from `linear.workflow.*` and are not your concern at this layer.
31
31
 
32
32
  If no query is provided AND no `linear.teamKey` is configured, stop and ask. Never run intake against a default scope without explicit configuration — the side effects (label transitions, PRs opened, builds running) are too high to act without an explicit target.
33
33
 
@@ -58,7 +58,7 @@ If any Issues ended at the configured `blocked` label (pre-flight verify failed)
58
58
  - **Never run a cycle without an explicit query or configured `linear.teamKey`.** Side effects too high to default.
59
59
  - **Never modify the lifecycle**: only the configured `ready → claimed → done` transitions and terminal-only native Issue completion. Never touch the configured `blocked` label (owned by `linear-agent`) or any other label. (Exception: the configured `review` label is set by `linear-evidence` mid-flow — that's not your concern.)
60
60
  - **Never bypass `linear-agent` to do build work directly.** The intake skill dispatches; `linear-agent` builds. Skipping the dispatch produces broken work.
61
- - **Never invent labels.** Names live in `.lisa.config.json` `linear.labels.build.*` (canonical) — the setup skill writes them. If a team hasn't adopted them yet, the skill exits with an adoption hint. Don't guess label names.
61
+ - **Never invent labels.** Names live in `.lisa.config.json` `linear.workflow.*` (canonical) — the setup skill writes them. If a team hasn't adopted them yet, the skill exits with an adoption hint. Don't guess label names.
62
62
  - **Never start a second cycle while one is in flight against an overlapping team.** Serial execution. Scheduling layer (when added) is responsible for not double-firing.
63
63
  - **Stop and surface failures rather than retry-loop.** If `linear-agent` returns an unexpected response or an error, the skill records it under "Errors" — pass that through. Do not auto-retry.
64
64
  - **Pre-flight failures are not your problem to fix.** If an Issue fails `linear-verify` (missing Validation Journey, sign-in, etc.), `linear-agent` transitions it to the configured `blocked` label and reassigns to the creator. Surface the count and move on. Do NOT try to add the missing pieces from this agent.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa",
3
- "version": "2.326.2",
3
+ "version": "2.327.0",
4
4
  "description": "Universal governance — agents, skills, commands, hooks, and rules for all projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -308,7 +308,7 @@ For each PRD epic, **invoke the `lisa-tracker-write` skill** (do not invoke `lis
308
308
  - `artifacts`: the full Phase 1.5 artifact list — every artifact, regardless of domain. The epic is the canonical hub. No filtering at the epic level.
309
309
  - `priority`, `labels`, `components`, `fix_version`: as appropriate
310
310
 
311
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: an Epic is a container, not a leaf work unit. Do NOT mark it build-ready — `lisa-tracker-write` must not be passed `status:ready` for an Epic, and the Epic's lifecycle state rolls up from its children. The build-ready label is applied only in Phase 5.
311
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: an Epic is a container, not a leaf work unit. Do NOT mark it build-ready — `lisa-tracker-write` must not be passed the build-ready role for an Epic, and the Epic's lifecycle state rolls up from its children. The build-ready role is applied only in Phase 5.
312
312
 
313
313
  Capture the returned epic key — Phase 4 needs it as the parent for stories.
314
314
 
@@ -339,7 +339,7 @@ For each story, **invoke `lisa-tracker-write`** with:
339
339
  | Infrastructure | `ops`, `reference` |
340
340
  | Mixed / setup ("X.0") | All domains |
341
341
 
342
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: a Story is a container (it has child Sub-tasks), not a leaf work unit. Do NOT mark it build-ready — never pass `status:ready` to `lisa-tracker-write` for a Story. Its lifecycle state rolls up from its Sub-tasks. The build-ready label is applied only in Phase 5.
342
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: a Story is a container (it has child Sub-tasks), not a leaf work unit. Do NOT mark it build-ready — never pass the build-ready role to `lisa-tracker-write` for a Story. Its lifecycle state rolls up from its Sub-tasks. The build-ready role is applied only in Phase 5.
343
343
 
344
344
  Capture each returned story key — Phase 5 needs it as the parent for sub-tasks.
345
345
 
@@ -356,7 +356,7 @@ Each sub-task MUST:
356
356
  2. **Include an Empirical Verification Plan** — real user-like verification, NOT unit tests, linting, or typechecking
357
357
  3. **Carry its own `## Source Requirement` section** (shared format above) with the full verbatim quote(s) from the Phase 1.4 register — a leaf claimed by build-intake in isolation must be self-explanatory. When a sub-task is split per-repo, every split child inherits the same requirement quote(s).
358
358
 
359
- **Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready label. `lisa-tracker-write` applies `status:ready` here so downstream build intake (`lisa-tracker-build-intake`) claims the leaves and never the Epic or Stories. Apply `status:ready` to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa-tracker-write` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
359
+ **Leaf-only build-ready (`leaf-only-lifecycle`)**: Sub-tasks are the **leaf work units** of the decomposition — they are the ONLY items in the hierarchy that receive the build-ready role. `lisa-tracker-write` applies the build-ready role here so downstream build intake (`lisa-tracker-build-intake`) claims the leaves and never the Epic or Stories. Apply the build-ready role to each Sub-task; never to its parent Story or Epic (Phases 3–4). `lisa-tracker-write` enforces the same invariant on the write side, so a Sub-task split into per-repo children (the cross-repo case above) carries build-ready on the children, not on any intermediate parent that gains child work.
360
360
 
361
361
  Sub-tasks inherit their parent story's artifacts by reference (the parent link). Do not pass the same artifact list to every sub-task.
362
362
 
@@ -251,7 +251,7 @@ PASS (the childless-parent exception) when the issue is build-ready and is a **l
251
251
  | Epic | no | yes | **FAIL** (childless Epic — pure rollup container, exception does not apply) |
252
252
  | any | any | no | **N/A** (not build-ready) |
253
253
 
254
- Remediation (render `<READY_ROLE>` as the resolved configured label, never as a hard-coded default): `"Build-ready (<READY_ROLE>; status:ready by default) is leaf-only per leaf-only-lifecycle. Move <READY_ROLE> 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."`
254
+ Remediation (render `<READY_ROLE>` as the resolved configured label, never as a hard-coded default): `"Build-ready is leaf-only per leaf-only-lifecycle. Move <READY_ROLE> 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."`
255
255
 
256
256
  `product_relevant: false` — a build-ready container is a lifecycle/decomposition error for the caller to repair, not a product question.
257
257
 
@@ -189,7 +189,7 @@ The childless-parent exception promotes every childless type **except Epic** to
189
189
  Post via `lisa-atlassian-access` `operation: comment key: <TICKET> body: "<message>"` with:
190
190
 
191
191
  ```text
192
- [claude-build-intake] Not claimed: this ticket carries the build-ready status ($READY) but is a container with open child work (or a childless Epic), which violates the leaf-only-lifecycle rule. Build-ready (status:ready) is leaf-only per leaf-only-lifecycle — an agent claims and implements leaves, never a container. Repair: move $READY off this parent 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.
192
+ [claude-build-intake] Not claimed: this ticket carries the build-ready status ($READY) but is a container with open child work (or a childless Epic), which violates the leaf-only-lifecycle rule. Build-ready is leaf-only per leaf-only-lifecycle — an agent claims and implements leaves, never a container. Repair: move $READY off this parent 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.
193
193
  ```
194
194
 
195
195
  This gate never blocks a legitimate flat Task/Bug: those have no open children and a leaf type, so they fall straight through to the claim in 3b.