@codyswann/lisa 2.21.1 → 2.23.1

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 (152) hide show
  1. package/package.json +3 -2
  2. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  3. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  4. package/plugins/lisa/agents/confluence-prd-intake.md +11 -9
  5. package/plugins/lisa/agents/github-agent.md +18 -10
  6. package/plugins/lisa/agents/github-build-intake.md +10 -8
  7. package/plugins/lisa/agents/github-prd-intake.md +11 -9
  8. package/plugins/lisa/agents/jira-agent.md +12 -8
  9. package/plugins/lisa/agents/jira-build-intake.md +9 -7
  10. package/plugins/lisa/agents/learnings-synthesizer.md +1 -1
  11. package/plugins/lisa/agents/linear-agent.md +15 -9
  12. package/plugins/lisa/agents/linear-build-intake.md +13 -11
  13. package/plugins/lisa/agents/linear-prd-intake.md +11 -9
  14. package/plugins/lisa/agents/notion-prd-intake.md +11 -9
  15. package/plugins/lisa/agents/pr-mining-specialist.md +1 -1
  16. package/plugins/lisa/agents/tracker-mining-specialist.md +1 -1
  17. package/plugins/lisa/commands/setup/atlassian.md +7 -0
  18. package/plugins/lisa/commands/setup/confluence.md +7 -0
  19. package/plugins/lisa/commands/setup/jira.md +7 -0
  20. package/plugins/lisa/commands/setup/notion.md +7 -0
  21. package/plugins/lisa/hooks/enforce-team-first.sh +14 -6
  22. package/plugins/lisa/rules/base-rules.md +3 -3
  23. package/plugins/lisa/rules/config-resolution.md +242 -24
  24. package/plugins/lisa/rules/intent-routing.md +4 -4
  25. package/plugins/lisa/rules/repo-scope-split.md +41 -0
  26. package/plugins/lisa/rules/verification.md +13 -0
  27. package/plugins/lisa/skills/atlassian-access/SKILL.md +260 -0
  28. package/plugins/lisa/skills/confluence-prd-intake/SKILL.md +167 -82
  29. package/plugins/lisa/skills/confluence-to-tracker/SKILL.md +39 -26
  30. package/plugins/lisa/skills/debrief/SKILL.md +4 -5
  31. package/plugins/lisa/skills/github-add-journey/SKILL.md +1 -0
  32. package/plugins/lisa/skills/github-build-intake/SKILL.md +104 -40
  33. package/plugins/lisa/skills/github-evidence/SKILL.md +22 -5
  34. package/plugins/lisa/skills/github-prd-intake/SKILL.md +87 -51
  35. package/plugins/lisa/skills/github-to-tracker/SKILL.md +2 -2
  36. package/plugins/lisa/skills/github-validate-issue/SKILL.md +11 -1
  37. package/plugins/lisa/skills/implement/SKILL.md +5 -6
  38. package/plugins/lisa/skills/intake/SKILL.md +5 -6
  39. package/plugins/lisa/skills/jira-add-journey/SKILL.md +1 -0
  40. package/plugins/lisa/skills/jira-build-intake/SKILL.md +110 -45
  41. package/plugins/lisa/skills/jira-create/SKILL.md +5 -3
  42. package/plugins/lisa/skills/jira-evidence/SKILL.md +19 -2
  43. package/plugins/lisa/skills/jira-journey/SKILL.md +3 -1
  44. package/plugins/lisa/skills/jira-read-ticket/SKILL.md +10 -8
  45. package/plugins/lisa/skills/jira-sync/SKILL.md +11 -5
  46. package/plugins/lisa/skills/jira-validate-ticket/SKILL.md +22 -10
  47. package/plugins/lisa/skills/jira-verify/SKILL.md +5 -3
  48. package/plugins/lisa/skills/jira-write-ticket/SKILL.md +16 -14
  49. package/plugins/lisa/skills/linear-add-journey/SKILL.md +1 -0
  50. package/plugins/lisa/skills/linear-build-intake/SKILL.md +90 -32
  51. package/plugins/lisa/skills/linear-evidence/SKILL.md +22 -5
  52. package/plugins/lisa/skills/linear-prd-intake/SKILL.md +92 -57
  53. package/plugins/lisa/skills/linear-validate-issue/SKILL.md +10 -0
  54. package/plugins/lisa/skills/monitor/SKILL.md +4 -5
  55. package/plugins/lisa/skills/notion-access/SKILL.md +193 -0
  56. package/plugins/lisa/skills/notion-prd-intake/SKILL.md +105 -46
  57. package/plugins/lisa/skills/notion-to-tracker/SKILL.md +7 -5
  58. package/plugins/lisa/skills/plan/SKILL.md +4 -5
  59. package/plugins/lisa/skills/research/SKILL.md +4 -5
  60. package/plugins/lisa/skills/setup-atlassian/SKILL.md +316 -0
  61. package/plugins/lisa/skills/setup-confluence/SKILL.md +245 -0
  62. package/plugins/lisa/skills/setup-jira/SKILL.md +198 -0
  63. package/plugins/lisa/skills/setup-notion/SKILL.md +283 -0
  64. package/plugins/lisa/skills/task-decomposition/SKILL.md +2 -0
  65. package/plugins/lisa/skills/ticket-triage/SKILL.md +4 -1
  66. package/plugins/lisa/skills/tracker-evidence/SKILL.md +1 -0
  67. package/plugins/lisa/skills/verification-lifecycle/SKILL.md +2 -0
  68. package/plugins/lisa/skills/verify/SKILL.md +4 -5
  69. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  70. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  71. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  73. package/plugins/lisa-expo/skills/ops-browser-uat/SKILL.md +1 -1
  74. package/plugins/lisa-expo/skills/ops-check-logs/SKILL.md +1 -1
  75. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  77. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  79. package/plugins/lisa-nestjs/skills/nestjs-graphql/references/project-patterns.md +48 -0
  80. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  82. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  83. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  84. package/plugins/src/base/agents/confluence-prd-intake.md +11 -9
  85. package/plugins/src/base/agents/github-agent.md +18 -10
  86. package/plugins/src/base/agents/github-build-intake.md +10 -8
  87. package/plugins/src/base/agents/github-prd-intake.md +11 -9
  88. package/plugins/src/base/agents/jira-agent.md +12 -8
  89. package/plugins/src/base/agents/jira-build-intake.md +9 -7
  90. package/plugins/src/base/agents/learnings-synthesizer.md +1 -1
  91. package/plugins/src/base/agents/linear-agent.md +15 -9
  92. package/plugins/src/base/agents/linear-build-intake.md +13 -11
  93. package/plugins/src/base/agents/linear-prd-intake.md +11 -9
  94. package/plugins/src/base/agents/notion-prd-intake.md +11 -9
  95. package/plugins/src/base/agents/pr-mining-specialist.md +1 -1
  96. package/plugins/src/base/agents/tracker-mining-specialist.md +1 -1
  97. package/plugins/src/base/commands/setup/atlassian.md +7 -0
  98. package/plugins/src/base/commands/setup/confluence.md +7 -0
  99. package/plugins/src/base/commands/setup/jira.md +7 -0
  100. package/plugins/src/base/commands/setup/notion.md +7 -0
  101. package/plugins/src/base/hooks/enforce-team-first.sh +14 -6
  102. package/plugins/src/base/rules/base-rules.md +3 -3
  103. package/plugins/src/base/rules/config-resolution.md +242 -24
  104. package/plugins/src/base/rules/intent-routing.md +4 -4
  105. package/plugins/src/base/rules/repo-scope-split.md +41 -0
  106. package/plugins/src/base/rules/verification.md +13 -0
  107. package/plugins/src/base/skills/atlassian-access/SKILL.md +260 -0
  108. package/plugins/src/base/skills/confluence-prd-intake/SKILL.md +167 -82
  109. package/plugins/src/base/skills/confluence-to-tracker/SKILL.md +39 -26
  110. package/plugins/src/base/skills/debrief/SKILL.md +4 -5
  111. package/plugins/src/base/skills/github-add-journey/SKILL.md +1 -0
  112. package/plugins/src/base/skills/github-build-intake/SKILL.md +104 -40
  113. package/plugins/src/base/skills/github-evidence/SKILL.md +22 -5
  114. package/plugins/src/base/skills/github-prd-intake/SKILL.md +87 -51
  115. package/plugins/src/base/skills/github-to-tracker/SKILL.md +2 -2
  116. package/plugins/src/base/skills/github-validate-issue/SKILL.md +11 -1
  117. package/plugins/src/base/skills/implement/SKILL.md +5 -6
  118. package/plugins/src/base/skills/intake/SKILL.md +5 -6
  119. package/plugins/src/base/skills/jira-add-journey/SKILL.md +1 -0
  120. package/plugins/src/base/skills/jira-build-intake/SKILL.md +110 -45
  121. package/plugins/src/base/skills/jira-create/SKILL.md +5 -3
  122. package/plugins/src/base/skills/jira-evidence/SKILL.md +19 -2
  123. package/plugins/src/base/skills/jira-journey/SKILL.md +3 -1
  124. package/plugins/src/base/skills/jira-read-ticket/SKILL.md +10 -8
  125. package/plugins/src/base/skills/jira-sync/SKILL.md +11 -5
  126. package/plugins/src/base/skills/jira-validate-ticket/SKILL.md +22 -10
  127. package/plugins/src/base/skills/jira-verify/SKILL.md +5 -3
  128. package/plugins/src/base/skills/jira-write-ticket/SKILL.md +16 -14
  129. package/plugins/src/base/skills/linear-add-journey/SKILL.md +1 -0
  130. package/plugins/src/base/skills/linear-build-intake/SKILL.md +90 -32
  131. package/plugins/src/base/skills/linear-evidence/SKILL.md +22 -5
  132. package/plugins/src/base/skills/linear-prd-intake/SKILL.md +92 -57
  133. package/plugins/src/base/skills/linear-validate-issue/SKILL.md +10 -0
  134. package/plugins/src/base/skills/monitor/SKILL.md +4 -5
  135. package/plugins/src/base/skills/notion-access/SKILL.md +193 -0
  136. package/plugins/src/base/skills/notion-prd-intake/SKILL.md +105 -46
  137. package/plugins/src/base/skills/notion-to-tracker/SKILL.md +7 -5
  138. package/plugins/src/base/skills/plan/SKILL.md +4 -5
  139. package/plugins/src/base/skills/research/SKILL.md +4 -5
  140. package/plugins/src/base/skills/setup-atlassian/SKILL.md +316 -0
  141. package/plugins/src/base/skills/setup-confluence/SKILL.md +245 -0
  142. package/plugins/src/base/skills/setup-jira/SKILL.md +198 -0
  143. package/plugins/src/base/skills/setup-notion/SKILL.md +283 -0
  144. package/plugins/src/base/skills/task-decomposition/SKILL.md +2 -0
  145. package/plugins/src/base/skills/ticket-triage/SKILL.md +4 -1
  146. package/plugins/src/base/skills/tracker-evidence/SKILL.md +1 -0
  147. package/plugins/src/base/skills/verification-lifecycle/SKILL.md +2 -0
  148. package/plugins/src/base/skills/verify/SKILL.md +4 -5
  149. package/plugins/src/expo/skills/ops-browser-uat/SKILL.md +1 -1
  150. package/plugins/src/expo/skills/ops-check-logs/SKILL.md +1 -1
  151. package/plugins/src/nestjs/skills/nestjs-graphql/references/project-patterns.md +48 -0
  152. package/scripts/check-plugins-sync.sh +45 -0
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: linear-prd-intake
3
- description: PRD intake agent for Linear-hosted PRDs. Runs one intake cycle against a Linear workspace or team — claims `prd-ready` projects (relabels to `prd-in-review`), validates each through the dry-run pipeline, and routes to `prd-blocked` (with clarifying comments on a sentinel feedback issue) or `prd-ticketed` (with JIRA tickets created). Linear counterpart of `notion-prd-intake` and `confluence-prd-intake`. Designed to be invoked manually via /linear-prd-intake or autonomously via a scheduled cron.
3
+ description: PRD intake agent for Linear-hosted PRDs. Runs one intake cycle against a Linear workspace or team — claims projects carrying the configured `ready` PRD label (relabels to the configured `in_review` label), validates each through the dry-run pipeline, and routes to the configured `blocked` label (with clarifying comments on a sentinel feedback issue) or `ticketed` label (with destination tickets created). Linear counterpart of `notion-prd-intake` and `confluence-prd-intake`. Designed to be invoked manually via /linear-prd-intake or autonomously via a scheduled cron.
4
4
  skills:
5
5
  - linear-prd-intake
6
6
  - linear-to-tracker
@@ -17,9 +17,11 @@ You are a PRD intake agent. Your single job is to run one intake cycle against t
17
17
 
18
18
  This agent is the Linear counterpart of `notion-prd-intake` and `confluence-prd-intake`. The behavior is identical apart from the source-of-truth tool surface and one structural difference (clarifying comments land on a sentinel feedback issue under each project, not on the project page itself, because Linear's MCP doesn't expose project-level comments). If you have a Notion database, use the Notion agent; if you have a Confluence space, use the Confluence agent.
19
19
 
20
+ PRD label role names (`ready`, `in_review`, `blocked`, `ticketed`, `shipped`, `sentinel`) are resolved from `.lisa.config.json` `linear.labels.prd.*` by the `linear-prd-intake` skill. The defaults match the legacy hardcoded names (`prd-ready`, `prd-in-review`, `prd-blocked`, `prd-ticketed`, `prd-shipped`, `prd-intake-feedback`).
21
+
20
22
  ## Confirmation policy
21
23
 
22
- Once you have a workspace or team scope, RUN. Do not ask the caller whether to proceed, do not preview projected scope, do not offer "proceed / skip / dry-run" choices. The caller has already authorized the run by invoking you; re-prompting defeats the purpose of a background batch. `prd-blocked` is a valid terminal state of the lifecycle, not a failure mode — large PRDs and PRDs full of open questions are exactly what this skill is for. The `linear-prd-intake` skill defines the only legitimate early-exit conditions (missing scope, unreachable workspace/team, label convention not yet adopted, empty Ready set); ask only when one of those applies.
24
+ Once you have a workspace or team scope, RUN. Do not ask the caller whether to proceed, do not preview projected scope, do not offer "proceed / skip / dry-run" choices. The caller has already authorized the run by invoking you; re-prompting defeats the purpose of a background batch. The `blocked` label is a valid terminal state of the lifecycle, not a failure mode — large PRDs and PRDs full of open questions are exactly what this skill is for. The `linear-prd-intake` skill defines the only legitimate early-exit conditions (missing scope, unreachable workspace/team, label convention not yet adopted, empty ready set); ask only when one of those applies.
23
25
 
24
26
  ## Workflow
25
27
 
@@ -33,30 +35,30 @@ If no scope is provided, stop and ask. Never run intake against a default or gue
33
35
 
34
36
  Invoke the `linear-prd-intake` skill with the scope as `$ARGUMENTS`. The skill owns the cycle logic — claim, dry-run, branch, write or comment, label transitions, sentinel feedback issue management, summary. Do not duplicate that logic here.
35
37
 
36
- Treat the skill's output as the source of truth. If it reports `prd-ticketed: 3 / prd-blocked: 1 / Errors: 0`, that's what you report.
38
+ Treat the skill's output as the source of truth (e.g. `ticketed: 3 / blocked: 1 / errors: 0`).
37
39
 
38
40
  ### 3. Surface the summary
39
41
 
40
42
  Pass the skill's summary block through to the caller verbatim — do not paraphrase or condense. The caller (often a human running `/linear-prd-intake` ad-hoc, or a scheduled cron) needs the structured record:
41
43
 
42
44
  - Total processed
43
- - Per-PRD outcomes (`prd-ticketed` → which tickets created; `prd-blocked` → how many gate failures; Errors → reason)
44
- - JIRA ticket count
45
+ - Per-PRD outcomes (ticketed → which tickets created; blocked → how many gate failures; errors → reason)
46
+ - Destination ticket count
45
47
 
46
48
  If the cycle errored before processing any PRDs (e.g. workspace unreachable, missing config, label convention not yet adopted), surface the failure cause in plain language and stop.
47
49
 
48
50
  ### 4. Suggest next actions when warranted
49
51
 
50
- After a successful cycle, if any PRDs ended in `prd-blocked`, mention to the caller that those PRDs need product attention before they can be re-ticketed. Do not auto-notify product — comments on the sentinel feedback issue (and on specific sub-issues for anchored failures) are the channel; the caller decides whether to ping anyone.
52
+ After a successful cycle, if any PRDs ended in the `blocked` label, mention to the caller that those PRDs need product attention before they can be re-ticketed. Do not auto-notify product — comments on the sentinel feedback issue (and on specific sub-issues for anchored failures) are the channel; the caller decides whether to ping anyone.
51
53
 
52
- When reporting `prd-blocked` outcomes, distinguish the cause: **pre-write gate failure** (per-ticket validator caught a problem before any tickets were created) vs **post-write coverage gap** (tickets were created and remain in JIRA, but the PRD has uncovered requirements that the next intake cycle will address). Both result in `prd-blocked`, but the implication for product is different — coverage gaps mean some tickets are already real and product should not re-author the PRD from scratch.
54
+ When reporting `blocked` outcomes, distinguish the cause: **pre-write gate failure** (per-ticket validator caught a problem before any tickets were created) vs **post-write coverage gap** (tickets were created and remain in the destination tracker, but the PRD has uncovered requirements that the next intake cycle will address). Both result in the `blocked` label, but the implication for product is different — coverage gaps mean some tickets are already real and product should not re-author the PRD from scratch.
53
55
 
54
- If all PRDs ended in `prd-ticketed` with coverage `COMPLETE`, mention that the next step is for product to monitor the created tickets and apply the `prd-shipped` label after delivery. If any are `COMPLETE_WITH_SCOPE_CREEP`, point that out so product can review the flagged tickets.
56
+ If all PRDs ended in the `ticketed` label with coverage `COMPLETE`, mention that the next step is for product to monitor the created tickets and apply the configured `shipped` label after delivery. If any are `COMPLETE_WITH_SCOPE_CREEP`, point that out so product can review the flagged tickets.
55
57
 
56
58
  ## Rules
57
59
 
58
60
  - **Never run a cycle without an explicit scope.** Side effects are too high to default.
59
- - **Never modify the lifecycle**: only `prd-ready → prd-in-reviewprd-blocked|prd-ticketed`. Never touch `prd-draft` or `prd-shipped`. Never invent new labels.
61
+ - **Never modify the lifecycle**: only `ready → in_review → blocked|ticketed`. Never touch the `draft` or `shipped` labels. Never invent new labels.
60
62
  - **Never write destination tickets directly.** All writes go through the skill chain (intake → linear-to-tracker → tracker-write).
61
63
  - **Never edit a project's description or any attached Linear document.** Communication with product happens only via comments — on specific sub-issues for anchored failures, on the sentinel feedback issue otherwise.
62
64
  - **Never close, archive, or repurpose the sentinel feedback issue.** It is reused across cycles; its longevity is the audit trail.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: notion-prd-intake
3
- description: PRD intake agent. Runs one intake cycle against a Notion PRD database — claims Ready PRDs, validates each through the dry-run pipeline, and routes to Blocked (with clarifying comments) or Ticketed (with JIRA tickets created). Designed to be invoked manually via /notion-prd-intake or autonomously via a scheduled cron.
3
+ description: PRD intake agent. Runs one intake cycle against a Notion PRD database — claims PRDs in the configured `ready` status, validates each through the dry-run pipeline, and routes to the `blocked` status (with clarifying comments) or the `ticketed` status (with destination tickets created). Designed to be invoked manually via /notion-prd-intake or autonomously via a scheduled cron.
4
4
  skills:
5
5
  - notion-prd-intake
6
6
  - notion-to-tracker
@@ -15,9 +15,11 @@ skills:
15
15
 
16
16
  You are a PRD intake agent. Your single job is to run one intake cycle against the Notion PRD database whose URL is given to you, then report what happened.
17
17
 
18
+ Status role names (`draft`, `ready`, `in_review`, `blocked`, `ticketed`, `shipped`) are resolved from `.lisa.config.json` `notion.values.*` by the `notion-prd-intake` skill. The defaults match the legacy hardcoded names (`Draft`, `Ready`, `In Review`, `Blocked`, `Ticketed`, `Shipped`).
19
+
18
20
  ## Confirmation policy
19
21
 
20
- Once you have a database URL, RUN. Do not ask the caller whether to proceed, do not preview projected scope, do not offer "proceed / skip / dry-run" choices. The caller has already authorized the run by invoking you; re-prompting defeats the purpose of a background batch. `Blocked` is a valid terminal state of the lifecycle, not a failure mode — large PRDs and PRDs full of open questions are exactly what this skill is for. The `notion-prd-intake` skill defines the only legitimate early-exit conditions (missing URL, misconfigured database, empty Ready set); ask only when one of those applies.
22
+ Once you have a database URL, RUN. Do not ask the caller whether to proceed, do not preview projected scope, do not offer "proceed / skip / dry-run" choices. The caller has already authorized the run by invoking you; re-prompting defeats the purpose of a background batch. The `blocked` status is a valid terminal state of the lifecycle, not a failure mode — large PRDs and PRDs full of open questions are exactly what this skill is for. The `notion-prd-intake` skill defines the only legitimate early-exit conditions (missing URL, misconfigured database, empty ready set); ask only when one of those applies.
21
23
 
22
24
  ## Workflow
23
25
 
@@ -31,30 +33,30 @@ If no URL is provided, stop and ask. Never run intake against a default or guess
31
33
 
32
34
  Invoke the `notion-prd-intake` skill with the database URL as `$ARGUMENTS`. The skill owns the cycle logic — claim, dry-run, branch, write or comment, status transition, summary. Do not duplicate that logic here.
33
35
 
34
- Treat the skill's output as the source of truth. If it reports `Ticketed: 3 / Blocked: 1 / Errors: 0`, that's what you report.
36
+ Treat the skill's output as the source of truth (e.g. `ticketed: 3 / blocked: 1 / errors: 0`).
35
37
 
36
38
  ### 3. Surface the summary
37
39
 
38
40
  Pass the skill's summary block through to the caller verbatim — do not paraphrase or condense. The caller (often a human running `/notion-prd-intake` ad-hoc, or a future schedule wrapper) needs the structured record:
39
41
 
40
42
  - Total processed
41
- - Per-PRD outcomes (Ticketed → which tickets created; Blocked → how many gate failures; Errors → reason)
42
- - JIRA ticket count
43
+ - Per-PRD outcomes (ticketed → which tickets created; blocked → how many gate failures; errors → reason)
44
+ - Destination ticket count
43
45
 
44
46
  If the cycle errored before processing any PRDs (e.g. database misconfigured, missing config), surface the failure cause in plain language and stop.
45
47
 
46
48
  ### 4. Suggest next actions when warranted
47
49
 
48
- After a successful cycle, if any PRDs ended in `Blocked`, mention to the caller that those PRDs need product attention before they can be re-ticketed. Do not auto-notify product — Notion comments on the PRDs are the channel; the caller decides whether to ping anyone.
50
+ After a successful cycle, if any PRDs ended in the `blocked` status, mention to the caller that those PRDs need product attention before they can be re-ticketed. Do not auto-notify product — Notion comments on the PRDs are the channel; the caller decides whether to ping anyone.
49
51
 
50
- When reporting Blocked outcomes, distinguish the cause: **pre-write gate failure** (per-ticket validator caught a problem before any tickets were created) vs **post-write coverage gap** (tickets were created and remain in JIRA, but the PRD has uncovered requirements that the next intake cycle will address). Both result in `Status = Blocked`, but the implication for product is different — coverage gaps mean some tickets are already real and product should not re-author the PRD from scratch.
52
+ When reporting `blocked` outcomes, distinguish the cause: **pre-write gate failure** (per-ticket validator caught a problem before any tickets were created) vs **post-write coverage gap** (tickets were created and remain in the destination tracker, but the PRD has uncovered requirements that the next intake cycle will address). Both result in the `blocked` status, but the implication for product is different — coverage gaps mean some tickets are already real and product should not re-author the PRD from scratch.
51
53
 
52
- If all PRDs ended in `Ticketed` with coverage `COMPLETE`, mention that the next step is for product to monitor the created tickets and flip the PRDs to `Shipped` after delivery. If any are `COMPLETE_WITH_SCOPE_CREEP`, point that out so product can review the flagged tickets.
54
+ If all PRDs ended in the `ticketed` status with coverage `COMPLETE`, mention that the next step is for product to monitor the created tickets and flip the PRDs to the configured `shipped` status after delivery. If any are `COMPLETE_WITH_SCOPE_CREEP`, point that out so product can review the flagged tickets.
53
55
 
54
56
  ## Rules
55
57
 
56
58
  - **Never run a cycle without an explicit database URL.** Side effects are too high to default.
57
- - **Never modify the lifecycle**: only `ReadyIn Review Blocked|Ticketed`. Never touch `Draft` or `Shipped`. Never invent new status values.
59
+ - **Never modify the lifecycle**: only `readyin_reviewblocked|ticketed`. Never touch `draft` or `shipped`. Never invent new status values.
58
60
  - **Never write destination tickets directly.** All writes go through the skill chain (intake → notion-to-tracker → tracker-write). Bypassing this skips quality gates.
59
61
  - **Never edit a PRD's body.** Communication with product happens only via Notion comments on the PRD.
60
62
  - **Never start a second cycle while one is in flight against the same database.** This agent assumes serial execution; the scheduling layer is responsible for not double-firing.
@@ -80,6 +80,6 @@ If there are no findings under a checklist row, write `(none)`.
80
80
  - **Never judge.** Surface every match. The synthesizer reconciles signal vs. noise.
81
81
  - **Quote verbatim.** Don't paraphrase review comments; the exact wording often carries the learning.
82
82
  - **Link, don't summarize.** Every finding has at least one evidence link (PR comment anchor, commit URL, file blob URL).
83
- - **Run within the team.** Do not call `TeamCreate`. The Debrief skill created the team; you are a teammate.
83
+ - **Run within the team.** Do not create a second team. The Debrief skill created the team; you are a teammate.
84
84
  - **Read-only.** No `gh pr merge`, no `gh pr review`, no commits. You observe; you do not mutate.
85
85
  - **Parallel-safe.** You run alongside `tracker-mining-specialist`; do not coordinate with them. The synthesizer reconciles.
@@ -80,6 +80,6 @@ If there are no findings under a checklist row, write `(none)` — silence is it
80
80
  - **Never judge.** "Probably not interesting" is not a category. Every signal that matches a checklist row goes in.
81
81
  - **Quote verbatim.** Paraphrasing comments loses author voice and the specifics that make a finding actionable.
82
82
  - **Link, don't summarize.** Every finding has at least one evidence link to the source artifact (comment URL, ticket URL fragment, PR URL).
83
- - **Run within the team.** Do not call `TeamCreate`. The Debrief skill created the team; you are a teammate.
83
+ - **Run within the team.** Do not create a second team. The Debrief skill created the team; you are a teammate.
84
84
  - **Read-only.** Never call write MCP tools. You report; you do not mutate.
85
85
  - **Parallel-safe.** You run alongside `pr-mining-specialist`; do not coordinate with them. The synthesizer reconciles.
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: "Set up Atlassian (cloudId + acli profile) for this project. Writes the `atlassian` section of `.lisa.config.json` and enables the Atlassian MCP and/or installs acli as needed. Prerequisite for /lisa:setup:jira and /lisa:setup:confluence."
3
+ allowed-tools: ["Skill"]
4
+ argument-hint: "[--site=<site>] [--email=<email>]"
5
+ ---
6
+
7
+ Use the /lisa:setup-atlassian skill to configure Atlassian access for this project. $ARGUMENTS
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: "Set up Confluence as the PRD source for this project. Writes the `confluence` section of `.lisa.config.json` (spaceKey and/or parentPageId) and offers to set top-level `source: \"confluence\"`. Depends on /lisa:setup:atlassian."
3
+ allowed-tools: ["Skill"]
4
+ argument-hint: "[--space=<KEY>] [--parent=<pageId>]"
5
+ ---
6
+
7
+ Use the /lisa:setup-confluence skill to configure Confluence as the PRD source. $ARGUMENTS
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: "Set up JIRA as the tracker for this project. Writes `jira.project` and offers to set top-level `tracker: \"jira\"` in `.lisa.config.json`. Depends on /lisa:setup:atlassian (needs cloudId)."
3
+ allowed-tools: ["Skill"]
4
+ argument-hint: "[--project=<KEY>]"
5
+ ---
6
+
7
+ Use the /lisa:setup-jira skill to configure JIRA as the project tracker. $ARGUMENTS
@@ -0,0 +1,7 @@
1
+ ---
2
+ description: "Set up Notion as the PRD source for this project. Walks the user through creating a workspace-scoped internal-integration token, sharing the PRD database with it, and stores the token in OS keychain. Writes `notion.workspaceId`, `notion.prdDatabaseId`, and `notion.values` into `.lisa.config.json`. Offers to set top-level `source: \"notion\"`."
3
+ allowed-tools: ["Skill"]
4
+ argument-hint: "[--database=<uuid>] [--workspace=<slug>]"
5
+ ---
6
+
7
+ Use the /lisa:setup-notion skill to configure Notion as the PRD source. $ARGUMENTS
@@ -1,18 +1,22 @@
1
1
  #!/usr/bin/env bash
2
- # Enforces team-first orchestration for lifecycle skills.
2
+ # Enforces Claude's TeamCreate-first orchestration for lifecycle skills.
3
+ #
4
+ # This hook is intentionally Claude-specific. Other harnesses may use different
5
+ # team tooling or an explicit no-team fallback; those paths are described in the
6
+ # shared rules/skills but are not enforced by this Claude hook.
3
7
  #
4
8
  # Triggered on four hook events:
5
9
  # - UserPromptSubmit : detects /lisa:research|plan|implement|intake|debrief in the
6
10
  # raw prompt and arms enforcement for the session
7
11
  # - PreToolUse : detects the same skills via a `Skill` tool call,
8
12
  # arms enforcement, and blocks bypass tool calls
9
- # until ToolSearch+TeamCreate have fired
10
- # - PostToolUse : on a successful TeamCreate, marks the session as
13
+ # until ToolSearch+TeamCreate have fired in Claude
14
+ # - PostToolUse : on a successful Claude TeamCreate, marks the session as
11
15
  # team-created (lifts enforcement)
12
16
  # - SubagentStart : marks the new subagent session as a teammate so
13
17
  # it is exempt — teammates inherit the lead's team
14
- # and must never call TeamCreate (double-create
15
- # is rejected by the harness)
18
+ # and must never create a second team (double-create
19
+ # is rejected by the Claude harness)
16
20
  #
17
21
  # Per-session state lives under "$STATE_DIR" as flag files keyed by
18
22
  # session_id. Stale state (>24h) is cleaned on each invocation.
@@ -159,7 +163,7 @@ fi
159
163
  ACTIVE_SKILL=$(cat "$SKILL_FLAG" 2>/dev/null || echo "lisa:???")
160
164
  cat >&2 <<EOF
161
165
  Blocked: this session invoked /${ACTIVE_SKILL}, which is an agent-team flow.
162
- Before any other tool call, you must:
166
+ In Claude, before any other tool call, you must:
163
167
 
164
168
  1. ToolSearch with query: "select:TeamCreate" (load the deferred schema)
165
169
  2. TeamCreate (actually create the team)
@@ -169,6 +173,10 @@ the ticket, exploring the code, fetching context — those are tasks for the
169
173
  team you are about to create, not for the lead session before the team
170
174
  exists.
171
175
 
176
+ If you are running Lisa in a non-Claude harness, this Claude enforcement hook
177
+ should not be installed; follow the runtime-aware orchestration preamble in the
178
+ skill instead.
179
+
172
180
  Re-read the orchestration preamble in /${ACTIVE_SKILL} and start with
173
181
  ToolSearch.
174
182
  EOF
@@ -8,7 +8,7 @@ After echoing the chosen flow and BEFORE doing any work, state the orchestration
8
8
 
9
9
  Default to an agent team for Research, Plan, Implement (Build/Fix/Improve/Investigate-Only), and any flow that invokes the Review sub-flow. Use a single agent only for Verify (standalone) and Monitor (standalone). See the `intent-routing` rule's Orchestration section for the full decision matrix.
10
10
 
11
- When the mode is `agent team` **and you are not already operating inside an agent team**, your FIRST tool calls after the classification echo MUST be `ToolSearch` with `query: "select:TeamCreate"` (to load the deferred tool's schema), then `TeamCreate`. Do not reach for `TaskCreate`, `Agent`, `Skill`, MCP tools, `Read`, `Bash`, or any other content-gathering call before the team exists — those are bypass paths that skip durable task state and parallel review. Reading the ticket, exploring the code, querying the API are all tasks for the team, not for the lead session before the team exists.
11
+ When the mode is `agent team` **and you are not already operating inside an agent team**, your FIRST tool calls after the classification echo MUST establish team orchestration before any content-gathering work. Use `TeamCreate` if available. In Claude, if `TeamCreate` has not been loaded yet, first use `ToolSearch` with `query: "select:TeamCreate"` to load its schema. If `TeamCreate` is not available, use the current runtime's tool-discovery mechanism (for Codex, `tool_search`) to discover available multi-agent/team tools, then call the appropriate team creation tool. If no team creation tool is available, explicitly state that team orchestration is unavailable in this runtime, continue as the lead agent, and preserve the workflow's review, verification, and task-tracking obligations locally. Do not reach for `TaskCreate`, `Agent`, `Skill`, MCP tools, `Read`, `Bash`, or any other content-gathering call before the team exists or the no-team fallback has been declared — those are bypass paths that skip durable task state and parallel review. Reading the ticket, exploring the code, querying the API are all tasks for the team, not for the lead session before orchestration exists.
12
12
 
13
13
  Requirement Verification:
14
14
 
@@ -70,7 +70,7 @@ JIRA Discipline:
70
70
  - When reading a JIRA issue, always read ALL comments on the ticket — not just the description. Comments contain critical context: stakeholder decisions, scope changes, blockers, triage findings from other repos, and implementation notes. Use the Atlassian MCP or `jira issue view <TICKET_ID> --comments 100` to fetch them.
71
71
  - When requesting clarification on a JIRA issue, post the question as a comment using ADF (Atlassian Document Format) and @mention the Reporter so they receive a notification.
72
72
  - When creating JIRA tickets, establish issue link relationships (e.g. "is blocked by", "blocks", "relates to", "is duplicated by") between tickets that have dependencies or logical connections. Do not leave related tickets unlinked. Relationship discovery is mandatory on every create and update — search BOTH the local git history (`git log --all --grep=<keyword>`, `git log -- <path>`) AND Jira (JQL by component, keyword, label, epic siblings) before declaring "no related work." Record the searches you ran and their outcomes in the description (or a comment) so a reviewer can see the search was real.
73
- - Ticket scope by type: Bug, Task, and Sub-task tickets MUST be single-repo (one work unit, one repo). Epic, Spike, and Story tickets MAY span multiple repos. If a Bug/Task/Sub-task crosses repos, split it.
73
+ - Ticket scope by type: Bug, Task, and Sub-task tickets MUST be single-repo (one work unit, one repo). Epic, Spike, and Story tickets MAY span multiple repos. If a Bug/Task/Sub-task crosses repos, split it per the `repo-scope-split` rule — at PRD-decomposition time via `task-decomposition` step 1.5 (parent Story + per-repo children); at work-time (an existing ticket an agent is about to implement) via the work-time split procedure (narrow the original to one repo, spin off a sibling per additional repo cloning its metadata, link the producer→consumer dependency, then proceed). A cross-repo work unit is a decomposition error the agent fixes by splitting, not a reason to bounce the ticket to the reporter.
74
74
  - Ticket descriptions MUST contain everything an implementer needs to start work without asking the reporter. In particular:
75
75
  - **Target backend environment** (`dev` / `staging` / `prod`) when the ticket has runtime behavior. QA/product report against a deployed env; the implementer verifies locally first against that backend before CI/CD. Skip only for doc-only, config-only, type-only, or Epic tickets.
76
76
  - **Sign-in account / credentials** when the work requires being signed in. Name the account (or the source — 1Password item, env var, seeded fixture) and the role. Omit entirely when sign-in is not required.
@@ -130,4 +130,4 @@ When you detect any of the above:
130
130
  1. Do NOT guess or make assumptions about what the external code does
131
131
  2. Identify which repository contains the missing code
132
132
  3. Add that repository to your current session before proceeding
133
- 4. If you cannot determine which repository contains the code, ask — do not proceed without it
133
+ 4. If you cannot determine which repository contains the code, ask — do not proceed without it
@@ -18,9 +18,15 @@ A typical Bash read:
18
18
  ```bash
19
19
  local_value=$(jq -r '.tracker // empty' .lisa.config.local.json 2>/dev/null)
20
20
  global_value=$(jq -r '.tracker // empty' .lisa.config.json 2>/dev/null)
21
- tracker="${local_value:-${global_value:-jira}}"
21
+ tracker="${local_value:-${global_value}}"
22
+ if [ -z "$tracker" ]; then
23
+ echo "Error: 'tracker' not set in .lisa.config.json. Run /lisa:setup:jira (or :github, :linear) to configure." >&2
24
+ exit 1
25
+ fi
22
26
  ```
23
27
 
28
+ `tracker` is **required** — there is no implicit default. Projects must declare their destination explicitly via one of the `/lisa:setup:*` skills.
29
+
24
30
  ## Schema
25
31
 
26
32
  ```json
@@ -28,12 +34,88 @@ tracker="${local_value:-${global_value:-jira}}"
28
34
  "tracker": "jira",
29
35
  "source": "notion",
30
36
 
31
- "atlassian": { "cloudId": "<uuid>" },
32
- "jira": { "project": "<KEY>" },
33
- "confluence": { "spaceKey": "<KEY>", "parentPageId": "<id>" },
34
- "github": { "org": "<org-or-user>", "repo": "<repo>" },
35
- "notion": { "prdDatabaseId": "<uuid>", "statusProperty": "Status", "readyValue": "Ready" },
36
- "linear": { "workspace": "<workspace-slug>", "teamKey": "<TEAM>" }
37
+ "atlassian": { "cloudId": "<uuid>", "site": "<host>" },
38
+ "jira": {
39
+ "project": "<KEY>",
40
+ "workflow": {
41
+ "ready": "Ready",
42
+ "claimed": "In Progress",
43
+ "review": "Code Review",
44
+ "blocked": "Blocked",
45
+ "done": { "dev": "On Dev", "staging": "On Stg", "production": "Done" }
46
+ }
47
+ },
48
+ "confluence": {
49
+ "spaceKey": "<KEY>",
50
+ "parentPageId": "<id>",
51
+ "parents": {
52
+ "draft": "<page-id>",
53
+ "ready": "<page-id>",
54
+ "in_review": "<page-id>",
55
+ "blocked": "<page-id>",
56
+ "ticketed": "<page-id>",
57
+ "shipped": "<page-id>"
58
+ },
59
+ "dashboardPageId": "<page-id>",
60
+ "feedbackPageId": "<page-id>"
61
+ },
62
+ "github": {
63
+ "org": "<org-or-user>",
64
+ "repo": "<repo>",
65
+ "labels": {
66
+ "build": {
67
+ "ready": "status:ready",
68
+ "claimed": "status:in-progress",
69
+ "review": "status:code-review",
70
+ "blocked": "status:blocked",
71
+ "done": { "dev": "status:on-dev", "staging": "status:on-stg", "production": "status:done" }
72
+ },
73
+ "prd": {
74
+ "draft": "prd-draft",
75
+ "ready": "prd-ready", "in_review": "prd-in-review",
76
+ "blocked": "prd-blocked", "ticketed": "prd-ticketed",
77
+ "shipped": "prd-shipped",
78
+ "sentinel": "prd-intake-feedback"
79
+ }
80
+ }
81
+ },
82
+ "notion": {
83
+ "workspaceId": "<workspace-uuid-or-human-slug>",
84
+ "prdDatabaseId": "<uuid>",
85
+ "statusProperty": "Status",
86
+ "values": {
87
+ "draft": "Draft", "ready": "Ready", "in_review": "In Review",
88
+ "blocked": "Blocked", "ticketed": "Ticketed", "shipped": "Shipped"
89
+ }
90
+ },
91
+ "linear": {
92
+ "workspace": "<workspace-slug>",
93
+ "teamKey": "<TEAM>",
94
+ "labels": {
95
+ "build": {
96
+ "ready": "status:ready",
97
+ "claimed": "status:in-progress",
98
+ "review": "status:code-review",
99
+ "blocked": "status:blocked",
100
+ "done": { "dev": "status:on-dev", "staging": "status:on-stg", "production": "status:done" }
101
+ },
102
+ "prd": {
103
+ "draft": "prd-draft",
104
+ "ready": "prd-ready", "in_review": "prd-in-review",
105
+ "blocked": "prd-blocked", "ticketed": "prd-ticketed",
106
+ "shipped": "prd-shipped",
107
+ "sentinel": "prd-intake-feedback"
108
+ }
109
+ }
110
+ },
111
+
112
+ "deploy": {
113
+ "branches": {
114
+ "dev": "dev",
115
+ "staging": "staging",
116
+ "production": "main"
117
+ }
118
+ }
37
119
  }
38
120
  ```
39
121
 
@@ -41,7 +123,7 @@ tracker="${local_value:-${global_value:-jira}}"
41
123
 
42
124
  | Field | Required | Default | Notes |
43
125
  |-------|----------|---------|-------|
44
- | `tracker` | no | `"jira"` | Destination for ticket writes. One of `"jira"`, `"github"`, `"linear"`. Missing key resolves to `"jira"` for back-compat. |
126
+ | `tracker` | **yes** | | Destination for ticket writes. One of `"jira"`, `"github"`, `"linear"`. Missing fail with instruction to run the matching `/lisa:setup:*` skill. |
45
127
  | `source` | no | — | Default PRD source for batch skills (`/lisa:intake`) and arg-less single-PRD skills. One of `"notion"`, `"confluence"`, `"linear"`, `"github"`, `"jira"`. Explicit URLs/keys passed to a skill always win over `source`; this is a default, not a lock. |
46
128
 
47
129
  ### Vendor sections
@@ -50,9 +132,11 @@ Each vendor section is **conditionally required**: required only when that vendo
50
132
 
51
133
  #### `atlassian`
52
134
 
53
- | Field | Required when | Notes |
54
- |-------|---------------|-------|
55
- | `atlassian.cloudId` | `tracker = "jira"`, `source = "jira"`, `source = "confluence"`, or any `confluence-*` / `jira-*` skill is invoked | Atlassian Cloud site UUID. Resolve once via the Atlassian MCP `getAccessibleAtlassianResources` and paste in. Shared between JIRA and Confluence (same Atlassian site). If a project ever needs separate sites for JIRA vs Confluence, override via `jira.cloudId` / `confluence.cloudId` (not currently implemented — file an issue). |
135
+ | Field | Required when | Where it lives | Notes |
136
+ |-------|---------------|----------------|-------|
137
+ | `atlassian.cloudId` | `tracker = "jira"`, `source = "jira"`, `source = "confluence"`, or any `confluence-*` / `jira-*` skill is invoked | **committed** (`.lisa.config.json`) | Atlassian Cloud site UUID. Same for every developer on the project. Resolve once via `curl https://<site>/_edge/tenant_info` or `getAccessibleAtlassianResources`. Shared between JIRA and Confluence (same Atlassian site). |
138
+ | `atlassian.site` | same as above | **committed** | Human-readable site URL (e.g. `propswap.atlassian.net`). Same for every developer. |
139
+ | `atlassian.email` | when the developer's machine has multiple Atlassian accounts that can access the configured site | **local** (`.lisa.config.local.json`) | Per-developer. `--site` alone cannot disambiguate which acli profile to switch to when two accounts both have access to the same site (e.g., a personal account and a work account both invited to a customer's site). The setup skill writes this to the local override file, NEVER the committed file. |
56
140
 
57
141
  #### `jira`
58
142
 
@@ -78,11 +162,12 @@ When `tracker = "github"` AND `source = "github"` (self-host), both reads and wr
78
162
 
79
163
  #### `notion`
80
164
 
81
- | Field | Required when | Notes |
82
- |-------|---------------|-------|
83
- | `notion.prdDatabaseId` | `source = "notion"` | Notion database ID (UUID, dashes optional). The database is the PRD queue. |
84
- | `notion.statusProperty` | `source = "notion"` | Name of the database property that drives the lifecycle. Defaults to `"Status"` if absent. |
85
- | `notion.readyValue` | `source = "notion"` | Status value that means "ready for ticketing". Defaults to `"Ready"` if absent. The full lifecycle (Ready → In Review → Blocked / Ticketed → Shipped) is hardcoded; only the entry-point value name is configurable for now. |
165
+ | Field | Required when | Where it lives | Notes |
166
+ |-------|---------------|----------------|-------|
167
+ | `notion.workspaceId` | `source = "notion"` | **committed** | Workspace identifier (Notion workspace UUID, or a stable human slug the user picks at setup). Same for every developer on the project. Used as the keychain `account` value when looking up the Notion API token, so each project's `notion-access` finds the right per-workspace token. |
168
+ | `notion.prdDatabaseId` | `source = "notion"` | **committed** | Notion database ID (UUID, dashes optional). The database is the PRD queue. Same for every developer on the project. |
169
+ | `notion.statusProperty` | `source = "notion"` | **committed** | Name of the database property that drives the lifecycle. Defaults to `"Status"` if absent. |
170
+ | `notion.values` | optional | **committed** | Map of role → Notion status-value name (`draft`, `ready`, `in_review`, `blocked`, `ticketed`, `shipped`). Defaults match the role names in title case. Override here if your Notion DB uses different value names. |
86
171
 
87
172
  #### `linear`
88
173
 
@@ -91,12 +176,70 @@ When `tracker = "github"` AND `source = "github"` (self-host), both reads and wr
91
176
  | `linear.workspace` | `tracker = "linear"`, `source = "linear"`, or any `linear-*` skill is invoked | Linear workspace slug (e.g. `acme`). |
92
177
  | `linear.teamKey` | `tracker = "linear"` | Linear team key (e.g. `ENG`). The team owns the destination Issues. For source mode, projects are workspace-scoped or team-scoped per the URL passed. |
93
178
 
179
+ ## Workflow & vocabulary roles
180
+
181
+ Every lifecycle skill operates on a fixed set of **roles** (`ready`, `claimed`, `done`, etc.), not concrete status/label strings. The role → string mapping lives in the per-vendor section above, with defaults that match the legacy hardcoded names. A project that uses different names overrides the relevant key; everything else inherits.
182
+
183
+ ### Roles
184
+
185
+ **Build lifecycle** (work items):
186
+
187
+ | Role | What it means | JIRA default | GitHub/Linear default |
188
+ |---|---|---|---|
189
+ | `ready` | Human signal "this is buildable; agent may claim" | `Ready` (status) | `status:ready` (label) |
190
+ | `claimed` | Agent has picked the item up | `In Progress` (status) | `status:in-progress` (label) |
191
+ | `review` | Build complete, in code review | `Code Review` (status) | `status:code-review` (label) |
192
+ | `blocked` | Agent stopped on triage ambiguities or external blocker | `Blocked` (status) | `status:blocked` (label) |
193
+ | `done` | Terminal state for this work, **env-keyed** | map of env → status | map of env → label |
194
+
195
+ `review` is required for label-driven systems (GitHub, Linear) because that's how the agent signals "PR opened, awaiting human review." For JIRA, `review` is optional — projects that keep the ticket in `claimed` until terminal can omit it and lifecycle skills will skip the intermediate transition.
196
+
197
+ `blocked` is what every vendor agent flips to when triage finds unresolved ambiguities or the build path is blocked by something the agent can't resolve. Different from `claimed` because it explicitly signals "human attention required."
198
+
199
+ **PRD lifecycle** (specifications):
200
+
201
+ | Role | What it means | Notion default | Confluence/GitHub/Linear default |
202
+ |---|---|---|---|
203
+ | `draft` | Author drafting; agent ignores until promoted to `ready` | `Draft` (status) | `prd-draft` (GitHub/Linear label); parent-page lookup (Confluence) |
204
+ | `ready` | "Ready for ticketing"; agent claims | `Ready` (status) | `prd-ready` (label) |
205
+ | `in_review` | Agent has claimed and is validating | `In Review` (status) | `prd-in-review` (label) |
206
+ | `blocked` | Validation failed; clarifying-comments posted | `Blocked` (status) | `prd-blocked` (label) |
207
+ | `ticketed` | Validated and tickets created | `Ticketed` (status) | `prd-ticketed` (label) |
208
+ | `shipped` | All child tickets shipped | `Shipped` (status) | `prd-shipped` (label) |
209
+ | `sentinel` | (PRD-intake feedback issue marker, GitHub/Linear self-host only) | — | `prd-intake-feedback` |
210
+
211
+ ### Env-keyed `done`
212
+
213
+ The `done` role is special: the terminal status/label depends on which environment a PR was merged into. A hotfix to staging ends at `On Stg`; a production hotfix ends at `Done`. So `done` is a **map** keyed by env name (`dev`, `staging`, `production`).
214
+
215
+ Skills that transition to `done` MUST resolve the env first:
216
+
217
+ 1. **Explicit caller arg** (`target_env=staging`) — always wins.
218
+ 2. **Branch inference** — derive from the PR's base branch via `deploy.branches`. Reverse-lookup: if base branch is `staging`, env is `staging`.
219
+ 3. **Failure** — if neither resolves and `done` is a map, fail loudly. Never pick arbitrarily.
220
+
221
+ If a project's terminal state is the same regardless of env, set `done` to a string instead of a map (lifecycle skills accept either shape).
222
+
223
+ ### What's configurable, what's not
224
+
225
+ - **Status / label NAMES** are configurable per project — that's the point of the vocabulary maps.
226
+ - **Role SEMANTICS and TRANSITIONS** are not. The build lifecycle is always `ready → claimed → done` (with optional `review` for label-driven systems). The PRD lifecycle is always `ready → in_review → (blocked | ticketed) → shipped`. Lisa skills hardcode these transitions because they encode the design intent of the framework, not the project's preferences.
227
+ - **Extra statuses/labels** the project uses outside these roles are fine — lisa never touches them.
228
+
229
+ ### Defaults vs. requirements
230
+
231
+ Vocabulary maps are **optional** in `.lisa.config.json`. Missing keys inherit the defaults shown in the schema above. The setup skills probe the project's actual workflow / labels at setup time and either:
232
+
233
+ - Confirm the default name exists → proceed silently.
234
+ - Confirm a different name exists (e.g., `Resolved` instead of `Done`) → prompt the user to either rename in the tracker or override the key in config.
235
+ - Find nothing matching → stop and ask the user to (a) create the missing status/label in the tracker, or (b) provide the actual name to write into config.
236
+
94
237
  ## Resolution algorithm
95
238
 
96
239
  Every `tracker-*` shim and every vendor-neutral caller follows this:
97
240
 
98
241
  1. Read `.lisa.config.local.json` first (if present), then `.lisa.config.json`. Local overrides global on a per-key basis. Use `jq` — never hand-parse JSON.
99
- 2. Extract the `tracker` field. If missing or null, default to `"jira"`.
242
+ 2. Extract the `tracker` field. If missing or null, stop and report: `"'tracker' is not set in .lisa.config.json. Run /lisa:setup:jira (or :github, :linear) to configure."`
100
243
  3. Dispatch:
101
244
  - `tracker = "jira"` → delegate to the matching `jira-*` skill. Validate `atlassian.cloudId` and `jira.project` are present.
102
245
  - `tracker = "github"` → delegate to the matching `github-*` skill. Validate `github.org` and `github.repo` are present.
@@ -167,21 +310,96 @@ Never overload one label across both lifecycles.
167
310
 
168
311
  The same separation applies for Linear self-host (`source = "linear"` AND `tracker = "linear"`): project-level labels (`prd-*`) drive the PRD lifecycle; issue-level labels (`status:*`) drive the build lifecycle; the sentinel feedback issue carries the issue-level `prd-intake-feedback` label.
169
312
 
313
+ ## Notion access (substrate ladder)
314
+
315
+ `notion-access` selects a substrate per operation in this order:
316
+
317
+ 1. **Notion MCP** — used when authenticated and its identity covers `notion.workspaceId`. Identity-match is verified by attempting to fetch `notion.prdDatabaseId` through the MCP; success means the MCP is authed to the correct workspace. If the MCP is authed elsewhere or unauthenticated, this tier is skipped.
318
+ 2. **curl + API token** — used when MCP isn't viable. Token is read via the standard lookup ladder (env → workspace-suffixed env → keychain → `tokenSource`).
319
+ 3. Fail with a clear diagnostic.
320
+
321
+ (No CLI tier — Notion has no first-party CLI; community wrappers aren't taken as a dependency.)
322
+
323
+ **Identity-match is mandatory.** A Notion MCP authed to the wrong workspace must be skipped, not used. `notion-access` verifies the configured `prdDatabaseId` is fetchable through the MCP before any operation; failure routes to the next tier.
324
+
325
+ **Token type**: Notion **internal-integration tokens** (`ntn_*` prefix). Created at notion.so/profile/integrations or workspace settings → Connections → New integration. Each token is **bound to one workspace** by construction. There is no v1/v2 scope mess like Atlassian — the token's access is uniform across whichever pages have been explicitly shared with the integration.
326
+
327
+ **Multi-account / multi-workspace**: same approach as Atlassian. The keychain entry is keyed by the workspace identifier (workspace id or human slug) declared in `.lisa.config.json` `notion.workspaceId`. Different projects targeting different Notion workspaces resolve to different keychain entries, no collision.
328
+
329
+ **Per-page access**: Notion's integration model requires each PRD page (or the parent database) to be explicitly **shared** with the integration before the API can see it. `setup-notion` prompts the user to share the PRD database with the freshly-created integration; downstream lifecycle skills assume the share has happened and fail loudly if a page isn't visible.
330
+
331
+ **Token storage and lookup ladder** (mirrors `atlassian-access`):
332
+
333
+ ```bash
334
+ read_notion_token() {
335
+ local workspace="$1"
336
+ [ -n "$NOTION_API_TOKEN" ] && { echo "$NOTION_API_TOKEN"; return; }
337
+ local slug=$(echo "$workspace" | tr '[:upper:]-' '[:lower:]_')
338
+ local varname="NOTION_API_TOKEN_${slug}"
339
+ [ -n "${!varname}" ] && { echo "${!varname}"; return; }
340
+ case "$(uname -s)" in
341
+ Darwin) security find-generic-password -s lisa-notion -a "$workspace" -w 2>/dev/null ;;
342
+ Linux) command -v secret-tool >/dev/null && \
343
+ secret-tool lookup service lisa-notion account "$workspace" 2>/dev/null ;;
344
+ MINGW*|MSYS*|CYGWIN*) cmdkey /list:"lisa-notion-${workspace}" 2>/dev/null | grep Password | awk '{print $NF}' ;;
345
+ esac
346
+ }
347
+ ```
348
+
349
+ **Schema additions** to `notion` section:
350
+
351
+ ```json
352
+ "notion": {
353
+ "workspaceId": "<uuid-or-human-slug>",
354
+ "prdDatabaseId": "<uuid>",
355
+ "statusProperty": "Status",
356
+ "values": { "draft": "Draft", "ready": "Ready", ... }
357
+ }
358
+ ```
359
+
360
+ `workspaceId` is the connection-match key. The notion-access skill calls `GET /v1/users/me` with the token and verifies the returned `bot.workspace_name` (or workspace id when Notion exposes it) matches the configured value before allowing operations to proceed.
361
+
362
+ ## Confluence PRD lifecycle uses parent pages, not labels
363
+
364
+ GitHub and Linear PRD lifecycles use labels (`prd-ready` / `prd-in-review` / etc.). **Confluence does not** — it uses parent pages instead. Each lifecycle role maps to a parent page; a PRD's current state is determined by which parent it's a child of; transitions are `PUT /wiki/api/v2/pages/{id}` with a new `parentId`.
365
+
366
+ **Why this asymmetry exists**: scoped API tokens (the only secure form Atlassian offers) cannot write labels on Confluence pages. The v1 label endpoint `POST /wiki/rest/api/content/{id}/label` rejects scoped-token granular scopes with 401 "scope does not match"; the v2 Label API group has no POST endpoint at all (see open bug `CONFCLOUD-76866`). Until Atlassian ships v2 label writes, labels are read-only via scoped tokens. Parent-id transitions, by contrast, are first-class in v2 and work with `write:page:confluence` scope.
367
+
368
+ **`confluence.parents` map**: each role's parent page id is stored in `.lisa.config.json` after `setup-confluence` creates the lifecycle scaffolding. Skills that need to discover the current state of a PRD read its `parentId` and reverse-lookup in `confluence.parents`. Skills that need to transition update the page's `parentId` to the new role's value.
369
+
370
+ **Native UX benefit**: parent-page state shows up automatically in Confluence's left-sidebar page tree — users see PRDs grouped by state without ever opening the Dashboard page. The Dashboard is still produced, but as a `Children Display`-macro aggregation rather than `Content by Label`.
371
+
372
+ ## Atlassian access (substrate ladder)
373
+
374
+ `atlassian-access` selects a substrate per operation in this order:
375
+
376
+ 1. **acli** — preferred when installed and authenticated, and when its active profile's site matches `atlassian.site` from config. `atlassian-access` calls `acli auth status` and compares the returned site/email to config before routing.
377
+ 2. **Atlassian MCP** — used when acli is unavailable for an op (e.g., Confluence page writes — acli has no `confluence page` write surface), or when acli isn't installed at all. Before routing, `atlassian-access` calls `getAccessibleAtlassianResources` and verifies `atlassian.cloudId` is in the returned list. If the configured cloudId isn't visible to the MCP's authed identity, the MCP tier is skipped.
378
+ 3. **curl + API token** — used when neither acli nor MCP is viable (headless, multi-account where MCP is authed elsewhere, scoped-token-only deployments). Token is read via the standard lookup ladder (env → email-suffixed env → keychain → `tokenSource`).
379
+ 4. Fail with a clear diagnostic listing what was attempted.
380
+
381
+ **Identity-match is mandatory at every tier.** A substrate that's authenticated as the *wrong* Atlassian account is more dangerous than no substrate — it silently performs operations against the wrong workspace. `atlassian-access` verifies identity before every operation and skips substrates that don't match.
382
+
383
+ **Why curl is still needed**: acli's Confluence surface only covers `space` and `page view`. v1 page-write endpoints accept scoped tokens but return 410 Gone (deprecated); v2 endpoints require granular OAuth scopes acli doesn't request. API tokens via Basic auth bypass this with full user scope, so curl is the headless-friendly path for ops neither acli nor MCP can do.
384
+
170
385
  ## Invariants
171
386
 
172
387
  - Project tracker selection is **persistent** within a project — always read from config, never infer from the shape of `$ARGUMENTS`. If a developer wants a different destination for one run, they edit `.lisa.config.local.json`.
388
+ - **Developer-specific fields (e.g., `atlassian.email`) live in `.lisa.config.local.json`, never in the committed file.** The committed file describes the project (which site, which tracker, which space); the local file describes the developer's identity (which account, which profile, which override). Setup skills MUST write developer-specific fields to the local override and shared fields to the committed file.
173
389
  - A vendor-neutral skill never embeds vendor-specific terminology in its prompts (no "JIRA ticket key", "epic parent" — use "tracker key", "parent issue"). The vendor skill is responsible for translating its inputs.
174
390
  - The shim layer is intentionally thin — its only job is dispatch. Gate logic, validation rules, and field schemas all live in the vendor skills.
175
- - Secrets stay in env (`JIRA_API_TOKEN`, `LINEAR_API_KEY`, `GH_TOKEN`, `NOTION_API_KEY`, `ATLASSIAN_API_TOKEN`). Configuration in `.lisa.config.json` is non-secret only — IDs, keys, slugs, project codes.
391
+ - Secrets stay in env (`ATLASSIAN_API_TOKEN`, `NOTION_API_TOKEN`, `LINEAR_API_KEY`, `GH_TOKEN`). Configuration in `.lisa.config.json` is non-secret only — IDs, keys, slugs, project codes.
392
+ - **`ATLASSIAN_API_TOKEN`** is required when the project uses JIRA or Confluence and any operation that acli doesn't cover (Confluence page writes, label edits, etc. — see `atlassian-access` skill's dispatch table). It's per-developer and per-project (different projects under different Atlassian accounts get different tokens). Setup-atlassian guides token generation and persists it to a gitignored `.envrc` (direnv) or `.env.lisa` (manual source); CI sets it directly as a pipeline secret. The token MUST belong to the account whose email is declared in `.lisa.config.local.json` `atlassian.email` — `atlassian-access` validates the pairing on first use of the curl substrate.
176
393
  - E2E test config (`E2E_BASE_URL`, `E2E_TEST_PHONE`, `E2E_TEST_OTP`, `E2E_TEST_ORG`, `E2E_GRAPHQL_URL`) stays in env for now — not tracker-related and frequently per-environment.
177
394
 
178
395
  ## Migration from the previous schema
179
396
 
180
- The pre-expansion `.lisa.config.json` had only `tracker` and `github.{org,repo}`. Existing projects continue to work the new fields are all conditionally required, and `tracker = "jira"` (the default) only requires `atlassian.cloudId` and `jira.project`, which were previously read from env (`JIRA_SERVER`, `JIRA_PROJECT`).
397
+ The pre-expansion `.lisa.config.json` had only `tracker` and `github.{org,repo}`, and a missing `tracker` defaulted to `"jira"`. That default has been removed `tracker` is now required.
398
+
399
+ To migrate a project to the new requirements:
181
400
 
182
- To migrate a project off env vars:
401
+ 1. Run `/lisa:setup:atlassian` (or `/lisa:setup:github`, `/lisa:setup:linear`) — installs the vendor MCP if needed, authenticates, and writes the vendor section.
402
+ 2. Run `/lisa:setup:jira` (or matching) — writes `jira.project` and prompts to set top-level `tracker`.
403
+ 3. Optionally run `/lisa:setup:confluence` / `/lisa:setup:notion` / etc. for source vendors — writes their sections and prompts to set top-level `source`.
183
404
 
184
- 1. Add `atlassian.cloudId` (resolve via `getAccessibleAtlassianResources` once).
185
- 2. Add `jira.project` (was `JIRA_PROJECT`).
186
- 3. Drop `JIRA_SERVER` from env (replaced by `atlassian.cloudId`).
187
- 4. Optionally add `source` to set the default PRD source for batch skills.
405
+ Projects that previously relied on the `"jira"` default will now fail loudly at the next vendor-neutral skill invocation; the error message points the user at the right setup skill.