@codyswann/lisa 2.59.1 → 2.60.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.
- package/README.md +2 -0
- package/package.json +1 -1
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa/rules/config-resolution.md +10 -7
- package/plugins/lisa/rules/leaf-only-lifecycle.md +3 -3
- package/plugins/lisa/rules/prd-lifecycle-rollup.md +13 -0
- package/plugins/lisa/skills/github-build-intake/SKILL.md +39 -17
- package/plugins/lisa/skills/tracker-build-intake/SKILL.md +3 -3
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/src/base/rules/config-resolution.md +10 -7
- package/plugins/src/base/rules/leaf-only-lifecycle.md +3 -3
- package/plugins/src/base/rules/prd-lifecycle-rollup.md +13 -0
- package/plugins/src/base/skills/github-build-intake/SKILL.md +39 -17
- package/plugins/src/base/skills/tracker-build-intake/SKILL.md +3 -3
package/README.md
CHANGED
|
@@ -80,6 +80,8 @@ Most users only ever call `/lisa:research`, `/lisa:plan`, and `/lisa:implement`.
|
|
|
80
80
|
| --- | --- |
|
|
81
81
|
| `/lisa:intake <queue-url>` | Scans a Ready queue (Notion PRD database, JIRA project, GitHub repo, Linear team, Confluence space) and dispatches each item through the right lifecycle command. Designed as the cron target for unattended runs. |
|
|
82
82
|
|
|
83
|
+
PRD intake records generated work with native hierarchy where the source and tracker support it, and with a durable generated-work fallback everywhere else. The vendor matrix for GitHub, Linear, JIRA/Atlassian, Confluence, Notion, and cross-vendor queues lives in `plugins/src/base/rules/prd-lifecycle-rollup.md`.
|
|
84
|
+
|
|
83
85
|
### Maintenance and Operations
|
|
84
86
|
|
|
85
87
|
| Command | What it does |
|
package/package.json
CHANGED
|
@@ -82,7 +82,7 @@
|
|
|
82
82
|
"lodash": ">=4.18.1"
|
|
83
83
|
},
|
|
84
84
|
"name": "@codyswann/lisa",
|
|
85
|
-
"version": "2.
|
|
85
|
+
"version": "2.60.1",
|
|
86
86
|
"description": "Claude Code governance framework that applies guardrails, guidance, and automated enforcement to projects",
|
|
87
87
|
"main": "dist/index.js",
|
|
88
88
|
"exports": {
|
|
@@ -54,7 +54,8 @@ fi
|
|
|
54
54
|
"in_review": "<page-id>",
|
|
55
55
|
"blocked": "<page-id>",
|
|
56
56
|
"ticketed": "<page-id>",
|
|
57
|
-
"shipped": "<page-id>"
|
|
57
|
+
"shipped": "<page-id>",
|
|
58
|
+
"verified": "<page-id>"
|
|
58
59
|
},
|
|
59
60
|
"dashboardPageId": "<page-id>",
|
|
60
61
|
"feedbackPageId": "<page-id>",
|
|
@@ -75,7 +76,7 @@ fi
|
|
|
75
76
|
"draft": "prd-draft",
|
|
76
77
|
"ready": "prd-ready", "in_review": "prd-in-review",
|
|
77
78
|
"blocked": "prd-blocked", "ticketed": "prd-ticketed",
|
|
78
|
-
"shipped": "prd-shipped",
|
|
79
|
+
"shipped": "prd-shipped", "verified": "prd-verified",
|
|
79
80
|
"sentinel": "prd-intake-feedback",
|
|
80
81
|
"rollup": { "closeOnShipped": false }
|
|
81
82
|
}
|
|
@@ -87,7 +88,8 @@ fi
|
|
|
87
88
|
"statusProperty": "Status",
|
|
88
89
|
"values": {
|
|
89
90
|
"draft": "Draft", "ready": "Ready", "in_review": "In Review",
|
|
90
|
-
"blocked": "Blocked", "ticketed": "Ticketed", "shipped": "Shipped"
|
|
91
|
+
"blocked": "Blocked", "ticketed": "Ticketed", "shipped": "Shipped",
|
|
92
|
+
"verified": "Verified"
|
|
91
93
|
},
|
|
92
94
|
"rollup": { "closeOnShipped": false }
|
|
93
95
|
},
|
|
@@ -106,7 +108,7 @@ fi
|
|
|
106
108
|
"draft": "prd-draft",
|
|
107
109
|
"ready": "prd-ready", "in_review": "prd-in-review",
|
|
108
110
|
"blocked": "prd-blocked", "ticketed": "prd-ticketed",
|
|
109
|
-
"shipped": "prd-shipped",
|
|
111
|
+
"shipped": "prd-shipped", "verified": "prd-verified",
|
|
110
112
|
"sentinel": "prd-intake-feedback",
|
|
111
113
|
"rollup": { "closeOnShipped": false }
|
|
112
114
|
}
|
|
@@ -171,7 +173,7 @@ When `tracker = "github"` AND `source = "github"` (self-host), both reads and wr
|
|
|
171
173
|
| `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. |
|
|
172
174
|
| `notion.prdDatabaseId` | `source = "notion"` | **committed** | Notion database ID (UUID, dashes optional). The database is the PRD queue. Same for every developer on the project. |
|
|
173
175
|
| `notion.statusProperty` | `source = "notion"` | **committed** | Name of the database property that drives the lifecycle. Defaults to `"Status"` if absent. |
|
|
174
|
-
| `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. |
|
|
176
|
+
| `notion.values` | optional | **committed** | Map of role → Notion status-value name (`draft`, `ready`, `in_review`, `blocked`, `ticketed`, `shipped`, `verified`). Defaults match the role names in title case. Override here if your Notion DB uses different value names. |
|
|
175
177
|
|
|
176
178
|
#### `linear`
|
|
177
179
|
|
|
@@ -210,6 +212,7 @@ Every lifecycle skill operates on a fixed set of **roles** (`ready`, `claimed`,
|
|
|
210
212
|
| `blocked` | Validation failed; clarifying-comments posted | `Blocked` (status) | `prd-blocked` (label) |
|
|
211
213
|
| `ticketed` | Validated and tickets created | `Ticketed` (status) | `prd-ticketed` (label) |
|
|
212
214
|
| `shipped` | All child tickets shipped | `Shipped` (status) | `prd-shipped` (label) |
|
|
215
|
+
| `verified` | Shipped product empirically checked against the PRD | `Verified` (status) | `prd-verified` (label); parent-page lookup (Confluence) |
|
|
213
216
|
| `sentinel` | (PRD-intake feedback issue marker, GitHub/Linear self-host only) | — | `prd-intake-feedback` |
|
|
214
217
|
|
|
215
218
|
### PRD rollup config (`prd.rollup`)
|
|
@@ -245,7 +248,7 @@ The true terminal `done` value is also the only value that triggers provider-nat
|
|
|
245
248
|
### What's configurable, what's not
|
|
246
249
|
|
|
247
250
|
- **Status / label NAMES** are configurable per project — that's the point of the vocabulary maps.
|
|
248
|
-
- **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
|
|
251
|
+
- **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`, then verification may move `shipped → verified` on a pass or `shipped → blocked` on a failed verification. `verified` is terminal and product-owned like `draft` and `shipped`; Lisa does not add `prd-verifying` or `prd-verification-failed` states. Skills hardcode these transitions because they encode the design intent of the framework, not the project's preferences.
|
|
249
252
|
- **Extra statuses/labels** the project uses outside these roles are fine — lisa never touches them.
|
|
250
253
|
|
|
251
254
|
### Defaults vs. requirements
|
|
@@ -324,7 +327,7 @@ Initiatives (Linear's cross-Project rollup) are NOT used — they're intended fo
|
|
|
324
327
|
|
|
325
328
|
When `github-to-tracker` is invoked AND `tracker = "github"`, both reads and writes hit the same GitHub repo. Label namespaces are kept separate so the two flows don't collide:
|
|
326
329
|
|
|
327
|
-
- PRD-source labels: `prd-draft`, `prd-ready`, `prd-in-review`, `prd-blocked`, `prd-ticketed`, `prd-shipped` — owned by `github-prd-intake` and the human PM.
|
|
330
|
+
- PRD-source labels: `prd-draft`, `prd-ready`, `prd-in-review`, `prd-blocked`, `prd-ticketed`, `prd-shipped`, `prd-verified` — owned by `github-prd-intake`, `verify-prd`, and the human PM.
|
|
328
331
|
- Build-queue labels: `status:ready`, `status:in-progress`, `status:code-review`, `status:on-dev`, `status:done` — owned by `github-build-intake` and `github-agent`.
|
|
329
332
|
- Sentinel issue label: `prd-intake-feedback` — owned by `github-prd-intake`.
|
|
330
333
|
|
|
@@ -10,7 +10,7 @@ The first two are the same idea seen from opposite ends: a parent never enters t
|
|
|
10
10
|
|
|
11
11
|
## Why this exists
|
|
12
12
|
|
|
13
|
-
Build intake
|
|
13
|
+
Build intake processes whatever carries the build-ready role (the `ready` role — see `config-resolution`). A parent container (an Epic, a Story, a Linear Project, any issue with child work) is not a unit of implementation; it organizes work. If a parent is marked build-ready, an agent may try to implement the container itself unless intake gates it first — the wrong permission and lifecycle boundary. This surfaced in real PRD intake: a PRD decomposed into an Epic, Stories, and Sub-tasks, and *every* item received the build-ready label, so a subsequent build pass would have tried to "implement" the Epic.
|
|
14
14
|
|
|
15
15
|
The fix is not vendor-specific. It belongs here, in a cross-vendor rule, and every writer / validator / intake path enforces it.
|
|
16
16
|
|
|
@@ -43,7 +43,7 @@ Where a vendor lacks native hierarchy for a given pair, a text link or metadata
|
|
|
43
43
|
|
|
44
44
|
- **At decomposition / write time** — when a PRD decomposes into a hierarchy, only the leaf work units receive the `ready` role (status/label). Parent containers (Epic, Story, Project, and any parent issue that has child work) are created in their normal non-ready state and never receive the build-ready role directly. The leaves are what downstream build intake will claim.
|
|
45
45
|
- **At validate time** — the `*-validate-*` gate FAILs any container carrying the build-ready role. This is the symmetric write-side guard: a stale or hand-applied build-ready role on a parent is a lifecycle error.
|
|
46
|
-
- **At claim time** — build intake scans for the `ready` role but
|
|
46
|
+
- **At claim time** — build intake scans for the `ready` role but dispatches **only leaf work units**. A container that still carries a stale build-ready role (e.g. applied before this rule existed) is **not dispatched**: intake either moves it into the vendor's parent/container progress state or safely blocks it with a clear lifecycle-repair message. Intake never silently implements a container.
|
|
47
47
|
|
|
48
48
|
The permission boundary is the maintainer-applied build-ready role, not authorship — do not add author-based guards (PRD #522 non-goal). This rule narrows *what* may carry that role, not *who* may apply it.
|
|
49
49
|
|
|
@@ -108,7 +108,7 @@ Skills that enforce this invariant or perform rollup cite this rule by slug (the
|
|
|
108
108
|
|
|
109
109
|
- **Decomposition / write** (`*-to-tracker`, `*-write-*`) — apply the `ready` role to leaves only; never to containers.
|
|
110
110
|
- **Validate** (`*-validate-*`) — FAIL a container carrying the build-ready role; FAIL a childless Epic/Story/Spike marked build-ready.
|
|
111
|
-
- **Build intake** (`*-build-intake`, `tracker-build-intake`) —
|
|
111
|
+
- **Build intake** (`*-build-intake`, `tracker-build-intake`) — dispatch leaves only; move or safe-block containers with stale build-ready roles according to vendor lifecycle semantics.
|
|
112
112
|
- **Rollup** — derive parent state from children per the state machine above.
|
|
113
113
|
- **Terminal native closure** (`*-build-intake`, terminal helpers) — after a leaf reaches the true terminal `done` role, finalize it through the provider's native close / complete / resolve mechanism where available; never do this for intermediate env states.
|
|
114
114
|
|
|
@@ -46,6 +46,19 @@ The relationship is recorded with the source tool's **native hierarchy first**,
|
|
|
46
46
|
|
|
47
47
|
The documented-section fallback is always written so the generated child set is readable later without relying only on free-form comments. Comment summaries are still useful human-facing audit trails and are not removed (PRD #525 non-goal).
|
|
48
48
|
|
|
49
|
+
### Vendor relationship and closure matrix
|
|
50
|
+
|
|
51
|
+
Use this matrix when implementing or auditing a PRD-source integration. It describes the native relationship to prefer, the documented fallback that must remain durable, and the closure behavior after the all-terminal rollup condition is met.
|
|
52
|
+
|
|
53
|
+
| PRD source / tracker shape | Native hierarchy mechanism | Documented fallback | Closure behavior |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| **GitHub Issues (source and tracker in the same repo)** | Link generated top-level work as native sub-issues of the PRD issue when the repo supports GitHub sub-issues. The PRD's direct sub-issues are the generated top-level child set; descendants under those children are excluded from PRD rollup. | Always maintain the machine-readable `## Tickets` / `## Generated Work` section keyed by `owner/repo#number`, and use it when sub-issues are unavailable, disabled, or incomplete. | Rollup changes the PRD lifecycle label from `prd-ticketed` to `prd-shipped` when every required generated top-level issue is terminal. Close the PRD issue only when `github.labels.prd.rollup.closeOnShipped` is `true`; the default is to leave it open. |
|
|
56
|
+
| **Linear** | Use Linear native grouping where the PRD also lives in Linear: generated top-level Issues are related through `parentId`, or a generated Project groups the generated Issues. Read only top-level Issues for PRD rollup. | Use the PRD's machine-readable generated-work section when the destination tracker is not Linear or native project / parent relationships cannot represent the PRD-to-work link. Entries are keyed by Linear issue or project identifier / UUID. | Rollup removes `prd-ticketed` and adds `prd-shipped` to the PRD project when every required generated top-level Issue / Project is completed. Archive or close the project only when `linear.labels.prd.rollup.closeOnShipped` is `true`; otherwise leave it active. |
|
|
57
|
+
| **JIRA / Atlassian tracker work** | Prefer native Epic / parent fields, or a documented issue-link type where the PRD-to-Epic relationship can be represented in JIRA. JIRA child terminal state is read from the issue's Done status category. | If the PRD source is not JIRA or the native link cannot attach tracker work to the PRD artifact, record generated top-level JIRA issue keys in the PRD's generated-work section. | Rollup may transition a JIRA-hosted PRD to the configured shipped / Done status only after all required generated top-level issues are in the Done status category. Native resolution / closure is config-gated through the PRD rollup close-on-shipped setting. |
|
|
58
|
+
| **Confluence PRDs** | No native issue hierarchy for tracker work. Confluence's native structure is used for PRD lifecycle lanes by parent page, not for destination work children. | The Confluence page's machine-readable `## Tickets` / `## Generated Work` section is the primary child source. Top-level generated work entries are keyed by destination ticket ref. | Rollup re-parents the PRD page from the `ticketed` parent to the `shipped` parent when every required generated-work entry is marked done. Archive the page only when `confluence.rollup.closeOnShipped` is `true`; otherwise leave it active. |
|
|
59
|
+
| **Notion PRDs** | No native issue hierarchy for tracker work. Notion's native status/select property stores PRD lifecycle state, not generated ticket parentage. | The Notion page's machine-readable `## Tickets` / `## Generated Work` section is the primary child source. Top-level generated work entries are keyed by destination ticket ref. | Rollup sets the configured Notion status/select value to `Shipped` when every required generated-work entry is marked done. Archive the page only when `notion.rollup.closeOnShipped` is `true`; otherwise leave it active. |
|
|
60
|
+
| **Cross-vendor PRD -> tracker** | Native hierarchy cannot cross systems, so the destination ticket is not expected to become a native child of the PRD artifact. Native tracker hierarchy still applies inside the destination system among generated Epics, Stories, and Sub-tasks. | The source PRD artifact's generated-work section is authoritative for the PRD-to-top-level-work child set, and each entry links to the destination ticket URL / key. | The PRD source owns the final lifecycle transition and optional close/archive. It evaluates terminal state using the destination tracker's predicate, then applies the source vendor's `shipped` transition and close-on-shipped behavior. |
|
|
61
|
+
|
|
49
62
|
## Per-vendor terminal-state predicate
|
|
50
63
|
|
|
51
64
|
A generated top-level child is **terminal** (counts as done for rollup) when it reaches the source/tracker's done/shipped state. The predicate is vendor-specific; the *semantics* ("this child has shipped") are not:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: github-build-intake
|
|
3
|
-
description: "GitHub counterpart to lisa:jira-build-intake. Scans a GitHub repository for issues carrying the configured `ready` build label, claims each leaf work unit by relabeling to the configured `claimed` label, runs the implementation/build flow via lisa:github-agent, and relabels to the configured `done` label on completion. Enforces the claim-time arm of the `leaf-only-lifecycle` rule: a parent/container with open child work (or a childless Epic/Story/Spike) that still carries a stale build-ready label is
|
|
3
|
+
description: "GitHub counterpart to lisa:jira-build-intake. Scans a GitHub repository for issues carrying the configured `ready` build label, claims each leaf work unit by relabeling to the configured `claimed` label, runs the implementation/build flow via lisa:github-agent, and relabels to the configured `done` label on completion. Enforces the claim-time arm of the `leaf-only-lifecycle` rule: a parent/container with open child work (or a childless Epic/Story/Spike) that still carries a stale build-ready label is moved out of the ready pickup queue into the configured `claimed` label with a lifecycle-repair comment, never dispatched to lisa:github-agent. The `ready` label is the human-flipped signal that an issue is truly ready for direct development pickup — mirroring how Notion PRDs work product Draft → Ready → (us) In Review → Blocked|Ticketed."
|
|
4
4
|
allowed-tools: ["Skill", "Bash"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -135,13 +135,13 @@ If none of the configured role labels exist on the repo → label convention not
|
|
|
135
135
|
|
|
136
136
|
### Phase 3 — Process each ready issue (serial)
|
|
137
137
|
|
|
138
|
-
#### 3a. Leaf-only claim gate (
|
|
138
|
+
#### 3a. Leaf-only claim gate (repair containers)
|
|
139
139
|
|
|
140
|
-
Build intake
|
|
140
|
+
Build intake dispatches **only independently implementable leaf work units** to the build agent. This enforces the claim-time arm of the vendor-neutral `leaf-only-lifecycle` rule: a parent/container that still carries a stale build-ready role (e.g. `status:ready` applied before this rule existed, or hand-applied to an Epic/Story) is **never dispatched** — intake moves it out of the pickup queue by replacing `$READY` with `$CLAIMED`, then posts a clear lifecycle-repair message. It is the claim-time complement to the write-time labeling in `lisa:github-write-issue` and the validate-time S15 gate in `lisa:github-validate-issue`; all three cite the same rule so the classification never drifts. **Never silently implement a container.**
|
|
141
141
|
|
|
142
|
-
Run this gate **before** the claim relabel, for every candidate issue. Do NOT
|
|
142
|
+
Run this gate **before** the leaf claim relabel, for every candidate issue. Do NOT comment "Claimed" or invoke `lisa:github-agent` for an issue that fails the gate. A container repair still changes labels: remove `$READY`, add `$CLAIMED`, and explain that parent/container `$CLAIMED` means rollup/build-lane progress through child/leaf work, not direct implementation.
|
|
143
143
|
|
|
144
|
-
**Resolve container vs. leaf — structural first, then nominal.** Per `leaf-only-lifecycle` the classification is structural: an issue is a **container** if it has **open** child work, whatever its declared type; otherwise the **type label** decides. Resolve child work using the same hierarchy `lisa:github-read-issue` uses — native sub-issues first, then body parentage (task-list checkboxes referencing other issues, `
|
|
144
|
+
**Resolve container vs. leaf — structural first, then nominal.** Per `leaf-only-lifecycle` the classification is structural: an issue is a **container** if it has **open** child work, whatever its declared type; otherwise the **type label** decides. Resolve child work using the same hierarchy `lisa:github-read-issue` uses — native sub-issues first, then body parentage (task-list checkboxes referencing other issues, `Parent: #<n>` references). Dependency links such as `Blocked by:` are not parentage; they are handled by the active dependency hold gate below.
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
147
|
# Native sub-issues via GraphQL (same query lisa:github-read-issue uses).
|
|
@@ -168,20 +168,39 @@ Classify and act (first match wins). `type:` is read from the issue's labels (`t
|
|
|
168
168
|
|
|
169
169
|
| Condition | Class | Action |
|
|
170
170
|
|---|---|---|
|
|
171
|
-
| `OPEN_CHILDREN > 0` (open child work, any type) | **Container** | **
|
|
172
|
-
| no open children AND `type ∈ {Epic, Story, Spike}` | **Childless container-type** | **
|
|
171
|
+
| `OPEN_CHILDREN > 0` (open child work, any type) | **Container** | **Move to `$CLAIMED` as lifecycle repair — do NOT dispatch** |
|
|
172
|
+
| no open children AND `type ∈ {Epic, Story, Spike}` | **Childless container-type** | **Move to `$CLAIMED` as lifecycle repair — do NOT dispatch** |
|
|
173
173
|
| no open children AND `type ∈ {Bug, Task, Sub-task, Improvement}` (or no `type:` label) | **Leaf work unit** | **Proceed to 3b claim** |
|
|
174
174
|
|
|
175
|
-
The childless-parent exception is narrow: childlessness enables
|
|
175
|
+
The childless-parent exception is narrow: childlessness enables direct build-agent dispatch **only** for types that are leaf work units to begin with. A childless Epic/Story/Spike is an incomplete decomposition, not an implementable unit — it is moved out of the ready pickup queue for repair/rollup and never dispatched.
|
|
176
176
|
|
|
177
|
-
**
|
|
177
|
+
**Lifecycle repair (default action for a flagged container).** Move the issue out of the pickup queue by removing `$READY` and adding `$CLAIMED`, post a single lifecycle-repair comment, and record the issue under "Repaired (container)" in the summary. Do NOT invoke `lisa:github-agent`. Keep the comment idempotent — skip posting if an identical `[claude-build-intake]` lifecycle-repair comment already exists on the issue, so a re-entrant cycle doesn't spam it.
|
|
178
178
|
|
|
179
179
|
```bash
|
|
180
|
-
gh issue
|
|
180
|
+
gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$CLAIMED"
|
|
181
|
+
gh issue comment <number> --repo <org>/<repo> --body "[claude-build-intake] Lifecycle repair: this issue carried the build-ready role ($READY) but is a parent/container with open child work (or a childless Epic/Story/Spike). I moved it to $CLAIMED without invoking the build agent. For parent/container issues, $CLAIMED means rollup/build-lane progress through child/leaf work; direct implementation must happen on leaf issues. Build-ready is leaf-only per leaf-only-lifecycle — move $READY onto its leaf children, or decompose/reclassify a childless Epic/Story/Spike."
|
|
181
182
|
```
|
|
182
183
|
|
|
183
184
|
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.
|
|
184
185
|
|
|
186
|
+
**Active dependency hold gate.** After the leaf-only gate passes, but still before the claim relabel, parse explicit blocker relationships from the issue body and durable Lisa relationship sections. Support these forms at minimum:
|
|
187
|
+
|
|
188
|
+
- `Blocked by: #123`
|
|
189
|
+
- `Blocked by: #123, #456`
|
|
190
|
+
- `Blocked by: owner/repo#123`
|
|
191
|
+
- `Blocked by: https://github.com/owner/repo/issues/123`
|
|
192
|
+
|
|
193
|
+
Resolve local `#123` references against the candidate issue's repo. Resolve qualified refs and GitHub issue URLs against their named repo. For each blocker, read the blocker issue's status labels with `gh issue view <number> --repo <owner>/<repo> --json labels,state`.
|
|
194
|
+
|
|
195
|
+
Default cleared blocker labels for GitHub build intake are:
|
|
196
|
+
|
|
197
|
+
- `status:code-review`
|
|
198
|
+
- `status:on-dev`
|
|
199
|
+
- `status:on-stg`
|
|
200
|
+
- `status:done`
|
|
201
|
+
|
|
202
|
+
A blocker is active if it is open and has no cleared status label. Treat `status:ready`, `status:in-progress`, missing status labels, and inaccessible blockers as active. Closed blockers are cleared. If any blocker is active, skip the candidate without changing lifecycle labels, without posting "Claimed", and without invoking `lisa:github-agent`. Record it under "Skipped (active blockers)" in the summary and include the active blocker refs. Keep any dependency-hold comment idempotent with a `[claude-build-intake]` prefix.
|
|
203
|
+
|
|
185
204
|
#### 3b. Claim
|
|
186
205
|
|
|
187
206
|
```bash
|
|
@@ -251,8 +270,10 @@ Cycle completed: <ISO timestamp>
|
|
|
251
270
|
Issues processed: <n>
|
|
252
271
|
- $DONE (build complete, PR ready): <n>
|
|
253
272
|
- <org>/<repo>#<number> <title> → PR <URL>
|
|
254
|
-
-
|
|
255
|
-
- <org>/<repo>#<number> <title> — build-ready on a parent
|
|
273
|
+
- Repaired (container — leaf-only-lifecycle): <n>
|
|
274
|
+
- <org>/<repo>#<number> <title> — build-ready on a parent/container; moved $READY → $CLAIMED without invoking lisa:github-agent; lifecycle-repair comment posted
|
|
275
|
+
- Skipped (active blockers): <n>
|
|
276
|
+
- <org>/<repo>#<number> <title> — waiting on <blocker refs>
|
|
256
277
|
- Blocked (pre-flight verify failed): <n>
|
|
257
278
|
- <org>/<repo>#<number> <title> — see issue comments
|
|
258
279
|
- Held (triage found ambiguities): <n>
|
|
@@ -265,9 +286,10 @@ Total PRs opened: <n>
|
|
|
265
286
|
|
|
266
287
|
## Idempotency & safety
|
|
267
288
|
|
|
268
|
-
- **Leaf-only claim gate runs first**: Phase 3a classifies each candidate before any claim; a container with open child work (or a childless Epic/Story/Spike) is
|
|
269
|
-
- **
|
|
270
|
-
- **
|
|
289
|
+
- **Leaf-only claim gate runs first**: Phase 3a classifies each candidate before any leaf claim; a container with open child work (or a childless Epic/Story/Spike) is moved `$READY` → `$CLAIMED` as lifecycle repair and never dispatched. The lifecycle-repair comment is idempotent — a re-entrant cycle does not re-post it.
|
|
290
|
+
- **Dependency hold runs before leaf claim**: explicit `Blocked by:` relationships are resolved after container repair is ruled out but before `$READY → $CLAIMED`; active blockers leave the leaf candidate in `$READY` and are reported as skipped, not blocked.
|
|
291
|
+
- **Claim-first ordering**: `$CLAIMED` set BEFORE `lisa:github-agent` invocation for leaves; containers are also moved to `$CLAIMED` to leave the ready pickup queue, but are not dispatched.
|
|
292
|
+
- **No writes outside the lifecycle**: this skill only relabels `$READY → $CLAIMED` and `$CLAIMED → $DONE`. For containers, `$READY → $CLAIMED` is a lifecycle repair, not a direct build claim. Every other label change is owned by `lisa:github-agent`.
|
|
271
293
|
- **Terminal native closure**: after `$CLAIMED → $DONE`, close the GitHub issue only when `$DONE` is the true terminal done value per `leaf-only-lifecycle`; intermediate env labels stay open.
|
|
272
294
|
- **Failure isolation**: per-issue exceptions caught and recorded; the cycle continues.
|
|
273
295
|
- **Single cycle per repo**: do not run two `lisa:github-build-intake` cycles in parallel against the same repo — concurrent claims could race. The scheduling layer is responsible for serialization.
|
|
@@ -290,8 +312,8 @@ If the repo has not adopted the `status:*` label namespace, this skill cannot ru
|
|
|
290
312
|
|
|
291
313
|
## Rules
|
|
292
314
|
|
|
293
|
-
- **
|
|
294
|
-
- Never relabel an issue the cycle
|
|
315
|
+
- **Dispatch leaves only.** Per the `leaf-only-lifecycle` rule, never dispatch a container — an issue with open child work, or a childless Epic/Story/Spike — even if it carries the build-ready role. Move it `$READY → $CLAIMED` as lifecycle repair (Phase 3a); never silently implement a container.
|
|
316
|
+
- Never relabel an issue outside the cycle's allowed transitions. The `$CLAIMED` label is the signature of cycle ownership for leaves, and the parent/container progress state for lifecycle repairs.
|
|
295
317
|
- Never bypass `lisa:github-agent` to do build work directly. `lisa:github-agent` owns the per-issue lifecycle.
|
|
296
318
|
- Never auto-transition past `$DONE`. Downstream labels (terminal `status:done`, etc.) are owned by QA / PM / merge automation.
|
|
297
319
|
- Never close a GitHub issue at intermediate env states (`status:on-dev`, `status:on-stg`, or configured equivalents). Native close happens only at the terminal `done` value.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tracker-build-intake
|
|
3
|
-
description: "Vendor-neutral wrapper for the build-queue batch scanner. Reads `tracker` from .lisa.config.json (default: jira) 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 enforces the claim-time arm of the `leaf-only-lifecycle` rule —
|
|
3
|
+
description: "Vendor-neutral wrapper for the build-queue batch scanner. Reads `tracker` from .lisa.config.json (default: jira) 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 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/Story/Spike) 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
|
|
|
@@ -27,7 +27,7 @@ The vendor scanners also own the terminal native-closure step from `leaf-only-li
|
|
|
27
27
|
This shim is dispatch only — it does not reclassify or re-gate items — but the contract it forwards is part of the build-intake API, so it is documented here once and the three vendor scanners implement it identically. Per the vendor-neutral `leaf-only-lifecycle` rule, **build intake claims only independently implementable leaf work units**:
|
|
28
28
|
|
|
29
29
|
- A **leaf work unit** (Bug, Task, Sub-task, Improvement with no open child work) is claimed and built.
|
|
30
|
-
- A **container** — anything with open child work, or a childless Epic/Story/Spike — that still carries a stale build-ready role is **never
|
|
30
|
+
- A **container** — anything with open child work, or a childless Epic/Story/Spike — that still carries a stale build-ready role is **never dispatched**. The GitHub scanner moves it out of the pickup queue by replacing `status:ready` with `status:in-progress` and posting an idempotent lifecycle-repair comment; other vendor scanners skip or safe-block according to their native lifecycle semantics.
|
|
31
31
|
|
|
32
32
|
This is the claim-time arm of the rule. Its siblings are the write-time labeling (`lisa:tracker-write` → the vendor `*-write-*` skills apply build-ready to leaves only) and the validate-time S15 gate (`lisa:tracker-validate` → the vendor `*-validate-*` skills FAIL a build-ready container). All three arms cite `leaf-only-lifecycle` so no vendor drifts. Each vendor scanner implements the gate against its own hierarchy:
|
|
33
33
|
|
|
@@ -55,6 +55,6 @@ Intermediate env states are not native closure. A vendor scanner that resolves `
|
|
|
55
55
|
|
|
56
56
|
- Single cycle per invocation — the vendor skill processes the current `Ready` set and exits.
|
|
57
57
|
- The vendor skills run their own pre-flight checks (JIRA workflow transitions for the JIRA path; label namespace adoption for the GitHub and Linear paths) before processing items. Never bypass.
|
|
58
|
-
- **Leaf-only
|
|
58
|
+
- **Leaf-only dispatch, every vendor.** Per the `leaf-only-lifecycle` rule, each vendor scanner dispatches leaf work units only and moves or safe-blocks a container (open child work, or a childless Epic/Story/Spike) carrying a stale build-ready role according to its lifecycle semantics. This shim does not re-implement the gate — it relies on the vendor scanner's Phase 3a — but the contract is uniform across `jira`, `github`, and `linear` so behavior never drifts by tracker.
|
|
59
59
|
- **Terminal native closure, every capable vendor.** Per the same rule, each vendor scanner finalizes native open/closed state only at the true terminal `done` value. This shim never performs native closure itself, but callers can rely on the dispatched vendor scanner to apply the contract.
|
|
60
60
|
- Never run two intake cycles concurrently against overlapping queues — the scheduling layer is responsible for serialization.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.60.1",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, for Claude Code and Codex",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lisa-openclaw",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.60.1",
|
|
4
4
|
"description": "Connect staff roles to Telegram or Slack via OpenClaw — facilitator/specialist hub-and-spoke routing and repo-coding topics, across Claude and Codex.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Cody Swann"
|
|
@@ -54,7 +54,8 @@ fi
|
|
|
54
54
|
"in_review": "<page-id>",
|
|
55
55
|
"blocked": "<page-id>",
|
|
56
56
|
"ticketed": "<page-id>",
|
|
57
|
-
"shipped": "<page-id>"
|
|
57
|
+
"shipped": "<page-id>",
|
|
58
|
+
"verified": "<page-id>"
|
|
58
59
|
},
|
|
59
60
|
"dashboardPageId": "<page-id>",
|
|
60
61
|
"feedbackPageId": "<page-id>",
|
|
@@ -75,7 +76,7 @@ fi
|
|
|
75
76
|
"draft": "prd-draft",
|
|
76
77
|
"ready": "prd-ready", "in_review": "prd-in-review",
|
|
77
78
|
"blocked": "prd-blocked", "ticketed": "prd-ticketed",
|
|
78
|
-
"shipped": "prd-shipped",
|
|
79
|
+
"shipped": "prd-shipped", "verified": "prd-verified",
|
|
79
80
|
"sentinel": "prd-intake-feedback",
|
|
80
81
|
"rollup": { "closeOnShipped": false }
|
|
81
82
|
}
|
|
@@ -87,7 +88,8 @@ fi
|
|
|
87
88
|
"statusProperty": "Status",
|
|
88
89
|
"values": {
|
|
89
90
|
"draft": "Draft", "ready": "Ready", "in_review": "In Review",
|
|
90
|
-
"blocked": "Blocked", "ticketed": "Ticketed", "shipped": "Shipped"
|
|
91
|
+
"blocked": "Blocked", "ticketed": "Ticketed", "shipped": "Shipped",
|
|
92
|
+
"verified": "Verified"
|
|
91
93
|
},
|
|
92
94
|
"rollup": { "closeOnShipped": false }
|
|
93
95
|
},
|
|
@@ -106,7 +108,7 @@ fi
|
|
|
106
108
|
"draft": "prd-draft",
|
|
107
109
|
"ready": "prd-ready", "in_review": "prd-in-review",
|
|
108
110
|
"blocked": "prd-blocked", "ticketed": "prd-ticketed",
|
|
109
|
-
"shipped": "prd-shipped",
|
|
111
|
+
"shipped": "prd-shipped", "verified": "prd-verified",
|
|
110
112
|
"sentinel": "prd-intake-feedback",
|
|
111
113
|
"rollup": { "closeOnShipped": false }
|
|
112
114
|
}
|
|
@@ -171,7 +173,7 @@ When `tracker = "github"` AND `source = "github"` (self-host), both reads and wr
|
|
|
171
173
|
| `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. |
|
|
172
174
|
| `notion.prdDatabaseId` | `source = "notion"` | **committed** | Notion database ID (UUID, dashes optional). The database is the PRD queue. Same for every developer on the project. |
|
|
173
175
|
| `notion.statusProperty` | `source = "notion"` | **committed** | Name of the database property that drives the lifecycle. Defaults to `"Status"` if absent. |
|
|
174
|
-
| `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. |
|
|
176
|
+
| `notion.values` | optional | **committed** | Map of role → Notion status-value name (`draft`, `ready`, `in_review`, `blocked`, `ticketed`, `shipped`, `verified`). Defaults match the role names in title case. Override here if your Notion DB uses different value names. |
|
|
175
177
|
|
|
176
178
|
#### `linear`
|
|
177
179
|
|
|
@@ -210,6 +212,7 @@ Every lifecycle skill operates on a fixed set of **roles** (`ready`, `claimed`,
|
|
|
210
212
|
| `blocked` | Validation failed; clarifying-comments posted | `Blocked` (status) | `prd-blocked` (label) |
|
|
211
213
|
| `ticketed` | Validated and tickets created | `Ticketed` (status) | `prd-ticketed` (label) |
|
|
212
214
|
| `shipped` | All child tickets shipped | `Shipped` (status) | `prd-shipped` (label) |
|
|
215
|
+
| `verified` | Shipped product empirically checked against the PRD | `Verified` (status) | `prd-verified` (label); parent-page lookup (Confluence) |
|
|
213
216
|
| `sentinel` | (PRD-intake feedback issue marker, GitHub/Linear self-host only) | — | `prd-intake-feedback` |
|
|
214
217
|
|
|
215
218
|
### PRD rollup config (`prd.rollup`)
|
|
@@ -245,7 +248,7 @@ The true terminal `done` value is also the only value that triggers provider-nat
|
|
|
245
248
|
### What's configurable, what's not
|
|
246
249
|
|
|
247
250
|
- **Status / label NAMES** are configurable per project — that's the point of the vocabulary maps.
|
|
248
|
-
- **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
|
|
251
|
+
- **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`, then verification may move `shipped → verified` on a pass or `shipped → blocked` on a failed verification. `verified` is terminal and product-owned like `draft` and `shipped`; Lisa does not add `prd-verifying` or `prd-verification-failed` states. Skills hardcode these transitions because they encode the design intent of the framework, not the project's preferences.
|
|
249
252
|
- **Extra statuses/labels** the project uses outside these roles are fine — lisa never touches them.
|
|
250
253
|
|
|
251
254
|
### Defaults vs. requirements
|
|
@@ -324,7 +327,7 @@ Initiatives (Linear's cross-Project rollup) are NOT used — they're intended fo
|
|
|
324
327
|
|
|
325
328
|
When `github-to-tracker` is invoked AND `tracker = "github"`, both reads and writes hit the same GitHub repo. Label namespaces are kept separate so the two flows don't collide:
|
|
326
329
|
|
|
327
|
-
- PRD-source labels: `prd-draft`, `prd-ready`, `prd-in-review`, `prd-blocked`, `prd-ticketed`, `prd-shipped` — owned by `github-prd-intake` and the human PM.
|
|
330
|
+
- PRD-source labels: `prd-draft`, `prd-ready`, `prd-in-review`, `prd-blocked`, `prd-ticketed`, `prd-shipped`, `prd-verified` — owned by `github-prd-intake`, `verify-prd`, and the human PM.
|
|
328
331
|
- Build-queue labels: `status:ready`, `status:in-progress`, `status:code-review`, `status:on-dev`, `status:done` — owned by `github-build-intake` and `github-agent`.
|
|
329
332
|
- Sentinel issue label: `prd-intake-feedback` — owned by `github-prd-intake`.
|
|
330
333
|
|
|
@@ -10,7 +10,7 @@ The first two are the same idea seen from opposite ends: a parent never enters t
|
|
|
10
10
|
|
|
11
11
|
## Why this exists
|
|
12
12
|
|
|
13
|
-
Build intake
|
|
13
|
+
Build intake processes whatever carries the build-ready role (the `ready` role — see `config-resolution`). A parent container (an Epic, a Story, a Linear Project, any issue with child work) is not a unit of implementation; it organizes work. If a parent is marked build-ready, an agent may try to implement the container itself unless intake gates it first — the wrong permission and lifecycle boundary. This surfaced in real PRD intake: a PRD decomposed into an Epic, Stories, and Sub-tasks, and *every* item received the build-ready label, so a subsequent build pass would have tried to "implement" the Epic.
|
|
14
14
|
|
|
15
15
|
The fix is not vendor-specific. It belongs here, in a cross-vendor rule, and every writer / validator / intake path enforces it.
|
|
16
16
|
|
|
@@ -43,7 +43,7 @@ Where a vendor lacks native hierarchy for a given pair, a text link or metadata
|
|
|
43
43
|
|
|
44
44
|
- **At decomposition / write time** — when a PRD decomposes into a hierarchy, only the leaf work units receive the `ready` role (status/label). Parent containers (Epic, Story, Project, and any parent issue that has child work) are created in their normal non-ready state and never receive the build-ready role directly. The leaves are what downstream build intake will claim.
|
|
45
45
|
- **At validate time** — the `*-validate-*` gate FAILs any container carrying the build-ready role. This is the symmetric write-side guard: a stale or hand-applied build-ready role on a parent is a lifecycle error.
|
|
46
|
-
- **At claim time** — build intake scans for the `ready` role but
|
|
46
|
+
- **At claim time** — build intake scans for the `ready` role but dispatches **only leaf work units**. A container that still carries a stale build-ready role (e.g. applied before this rule existed) is **not dispatched**: intake either moves it into the vendor's parent/container progress state or safely blocks it with a clear lifecycle-repair message. Intake never silently implements a container.
|
|
47
47
|
|
|
48
48
|
The permission boundary is the maintainer-applied build-ready role, not authorship — do not add author-based guards (PRD #522 non-goal). This rule narrows *what* may carry that role, not *who* may apply it.
|
|
49
49
|
|
|
@@ -108,7 +108,7 @@ Skills that enforce this invariant or perform rollup cite this rule by slug (the
|
|
|
108
108
|
|
|
109
109
|
- **Decomposition / write** (`*-to-tracker`, `*-write-*`) — apply the `ready` role to leaves only; never to containers.
|
|
110
110
|
- **Validate** (`*-validate-*`) — FAIL a container carrying the build-ready role; FAIL a childless Epic/Story/Spike marked build-ready.
|
|
111
|
-
- **Build intake** (`*-build-intake`, `tracker-build-intake`) —
|
|
111
|
+
- **Build intake** (`*-build-intake`, `tracker-build-intake`) — dispatch leaves only; move or safe-block containers with stale build-ready roles according to vendor lifecycle semantics.
|
|
112
112
|
- **Rollup** — derive parent state from children per the state machine above.
|
|
113
113
|
- **Terminal native closure** (`*-build-intake`, terminal helpers) — after a leaf reaches the true terminal `done` role, finalize it through the provider's native close / complete / resolve mechanism where available; never do this for intermediate env states.
|
|
114
114
|
|
|
@@ -46,6 +46,19 @@ The relationship is recorded with the source tool's **native hierarchy first**,
|
|
|
46
46
|
|
|
47
47
|
The documented-section fallback is always written so the generated child set is readable later without relying only on free-form comments. Comment summaries are still useful human-facing audit trails and are not removed (PRD #525 non-goal).
|
|
48
48
|
|
|
49
|
+
### Vendor relationship and closure matrix
|
|
50
|
+
|
|
51
|
+
Use this matrix when implementing or auditing a PRD-source integration. It describes the native relationship to prefer, the documented fallback that must remain durable, and the closure behavior after the all-terminal rollup condition is met.
|
|
52
|
+
|
|
53
|
+
| PRD source / tracker shape | Native hierarchy mechanism | Documented fallback | Closure behavior |
|
|
54
|
+
|---|---|---|---|
|
|
55
|
+
| **GitHub Issues (source and tracker in the same repo)** | Link generated top-level work as native sub-issues of the PRD issue when the repo supports GitHub sub-issues. The PRD's direct sub-issues are the generated top-level child set; descendants under those children are excluded from PRD rollup. | Always maintain the machine-readable `## Tickets` / `## Generated Work` section keyed by `owner/repo#number`, and use it when sub-issues are unavailable, disabled, or incomplete. | Rollup changes the PRD lifecycle label from `prd-ticketed` to `prd-shipped` when every required generated top-level issue is terminal. Close the PRD issue only when `github.labels.prd.rollup.closeOnShipped` is `true`; the default is to leave it open. |
|
|
56
|
+
| **Linear** | Use Linear native grouping where the PRD also lives in Linear: generated top-level Issues are related through `parentId`, or a generated Project groups the generated Issues. Read only top-level Issues for PRD rollup. | Use the PRD's machine-readable generated-work section when the destination tracker is not Linear or native project / parent relationships cannot represent the PRD-to-work link. Entries are keyed by Linear issue or project identifier / UUID. | Rollup removes `prd-ticketed` and adds `prd-shipped` to the PRD project when every required generated top-level Issue / Project is completed. Archive or close the project only when `linear.labels.prd.rollup.closeOnShipped` is `true`; otherwise leave it active. |
|
|
57
|
+
| **JIRA / Atlassian tracker work** | Prefer native Epic / parent fields, or a documented issue-link type where the PRD-to-Epic relationship can be represented in JIRA. JIRA child terminal state is read from the issue's Done status category. | If the PRD source is not JIRA or the native link cannot attach tracker work to the PRD artifact, record generated top-level JIRA issue keys in the PRD's generated-work section. | Rollup may transition a JIRA-hosted PRD to the configured shipped / Done status only after all required generated top-level issues are in the Done status category. Native resolution / closure is config-gated through the PRD rollup close-on-shipped setting. |
|
|
58
|
+
| **Confluence PRDs** | No native issue hierarchy for tracker work. Confluence's native structure is used for PRD lifecycle lanes by parent page, not for destination work children. | The Confluence page's machine-readable `## Tickets` / `## Generated Work` section is the primary child source. Top-level generated work entries are keyed by destination ticket ref. | Rollup re-parents the PRD page from the `ticketed` parent to the `shipped` parent when every required generated-work entry is marked done. Archive the page only when `confluence.rollup.closeOnShipped` is `true`; otherwise leave it active. |
|
|
59
|
+
| **Notion PRDs** | No native issue hierarchy for tracker work. Notion's native status/select property stores PRD lifecycle state, not generated ticket parentage. | The Notion page's machine-readable `## Tickets` / `## Generated Work` section is the primary child source. Top-level generated work entries are keyed by destination ticket ref. | Rollup sets the configured Notion status/select value to `Shipped` when every required generated-work entry is marked done. Archive the page only when `notion.rollup.closeOnShipped` is `true`; otherwise leave it active. |
|
|
60
|
+
| **Cross-vendor PRD -> tracker** | Native hierarchy cannot cross systems, so the destination ticket is not expected to become a native child of the PRD artifact. Native tracker hierarchy still applies inside the destination system among generated Epics, Stories, and Sub-tasks. | The source PRD artifact's generated-work section is authoritative for the PRD-to-top-level-work child set, and each entry links to the destination ticket URL / key. | The PRD source owns the final lifecycle transition and optional close/archive. It evaluates terminal state using the destination tracker's predicate, then applies the source vendor's `shipped` transition and close-on-shipped behavior. |
|
|
61
|
+
|
|
49
62
|
## Per-vendor terminal-state predicate
|
|
50
63
|
|
|
51
64
|
A generated top-level child is **terminal** (counts as done for rollup) when it reaches the source/tracker's done/shipped state. The predicate is vendor-specific; the *semantics* ("this child has shipped") are not:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: github-build-intake
|
|
3
|
-
description: "GitHub counterpart to lisa:jira-build-intake. Scans a GitHub repository for issues carrying the configured `ready` build label, claims each leaf work unit by relabeling to the configured `claimed` label, runs the implementation/build flow via lisa:github-agent, and relabels to the configured `done` label on completion. Enforces the claim-time arm of the `leaf-only-lifecycle` rule: a parent/container with open child work (or a childless Epic/Story/Spike) that still carries a stale build-ready label is
|
|
3
|
+
description: "GitHub counterpart to lisa:jira-build-intake. Scans a GitHub repository for issues carrying the configured `ready` build label, claims each leaf work unit by relabeling to the configured `claimed` label, runs the implementation/build flow via lisa:github-agent, and relabels to the configured `done` label on completion. Enforces the claim-time arm of the `leaf-only-lifecycle` rule: a parent/container with open child work (or a childless Epic/Story/Spike) that still carries a stale build-ready label is moved out of the ready pickup queue into the configured `claimed` label with a lifecycle-repair comment, never dispatched to lisa:github-agent. The `ready` label is the human-flipped signal that an issue is truly ready for direct development pickup — mirroring how Notion PRDs work product Draft → Ready → (us) In Review → Blocked|Ticketed."
|
|
4
4
|
allowed-tools: ["Skill", "Bash"]
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -135,13 +135,13 @@ If none of the configured role labels exist on the repo → label convention not
|
|
|
135
135
|
|
|
136
136
|
### Phase 3 — Process each ready issue (serial)
|
|
137
137
|
|
|
138
|
-
#### 3a. Leaf-only claim gate (
|
|
138
|
+
#### 3a. Leaf-only claim gate (repair containers)
|
|
139
139
|
|
|
140
|
-
Build intake
|
|
140
|
+
Build intake dispatches **only independently implementable leaf work units** to the build agent. This enforces the claim-time arm of the vendor-neutral `leaf-only-lifecycle` rule: a parent/container that still carries a stale build-ready role (e.g. `status:ready` applied before this rule existed, or hand-applied to an Epic/Story) is **never dispatched** — intake moves it out of the pickup queue by replacing `$READY` with `$CLAIMED`, then posts a clear lifecycle-repair message. It is the claim-time complement to the write-time labeling in `lisa:github-write-issue` and the validate-time S15 gate in `lisa:github-validate-issue`; all three cite the same rule so the classification never drifts. **Never silently implement a container.**
|
|
141
141
|
|
|
142
|
-
Run this gate **before** the claim relabel, for every candidate issue. Do NOT
|
|
142
|
+
Run this gate **before** the leaf claim relabel, for every candidate issue. Do NOT comment "Claimed" or invoke `lisa:github-agent` for an issue that fails the gate. A container repair still changes labels: remove `$READY`, add `$CLAIMED`, and explain that parent/container `$CLAIMED` means rollup/build-lane progress through child/leaf work, not direct implementation.
|
|
143
143
|
|
|
144
|
-
**Resolve container vs. leaf — structural first, then nominal.** Per `leaf-only-lifecycle` the classification is structural: an issue is a **container** if it has **open** child work, whatever its declared type; otherwise the **type label** decides. Resolve child work using the same hierarchy `lisa:github-read-issue` uses — native sub-issues first, then body parentage (task-list checkboxes referencing other issues, `
|
|
144
|
+
**Resolve container vs. leaf — structural first, then nominal.** Per `leaf-only-lifecycle` the classification is structural: an issue is a **container** if it has **open** child work, whatever its declared type; otherwise the **type label** decides. Resolve child work using the same hierarchy `lisa:github-read-issue` uses — native sub-issues first, then body parentage (task-list checkboxes referencing other issues, `Parent: #<n>` references). Dependency links such as `Blocked by:` are not parentage; they are handled by the active dependency hold gate below.
|
|
145
145
|
|
|
146
146
|
```bash
|
|
147
147
|
# Native sub-issues via GraphQL (same query lisa:github-read-issue uses).
|
|
@@ -168,20 +168,39 @@ Classify and act (first match wins). `type:` is read from the issue's labels (`t
|
|
|
168
168
|
|
|
169
169
|
| Condition | Class | Action |
|
|
170
170
|
|---|---|---|
|
|
171
|
-
| `OPEN_CHILDREN > 0` (open child work, any type) | **Container** | **
|
|
172
|
-
| no open children AND `type ∈ {Epic, Story, Spike}` | **Childless container-type** | **
|
|
171
|
+
| `OPEN_CHILDREN > 0` (open child work, any type) | **Container** | **Move to `$CLAIMED` as lifecycle repair — do NOT dispatch** |
|
|
172
|
+
| no open children AND `type ∈ {Epic, Story, Spike}` | **Childless container-type** | **Move to `$CLAIMED` as lifecycle repair — do NOT dispatch** |
|
|
173
173
|
| no open children AND `type ∈ {Bug, Task, Sub-task, Improvement}` (or no `type:` label) | **Leaf work unit** | **Proceed to 3b claim** |
|
|
174
174
|
|
|
175
|
-
The childless-parent exception is narrow: childlessness enables
|
|
175
|
+
The childless-parent exception is narrow: childlessness enables direct build-agent dispatch **only** for types that are leaf work units to begin with. A childless Epic/Story/Spike is an incomplete decomposition, not an implementable unit — it is moved out of the ready pickup queue for repair/rollup and never dispatched.
|
|
176
176
|
|
|
177
|
-
**
|
|
177
|
+
**Lifecycle repair (default action for a flagged container).** Move the issue out of the pickup queue by removing `$READY` and adding `$CLAIMED`, post a single lifecycle-repair comment, and record the issue under "Repaired (container)" in the summary. Do NOT invoke `lisa:github-agent`. Keep the comment idempotent — skip posting if an identical `[claude-build-intake]` lifecycle-repair comment already exists on the issue, so a re-entrant cycle doesn't spam it.
|
|
178
178
|
|
|
179
179
|
```bash
|
|
180
|
-
gh issue
|
|
180
|
+
gh issue edit <number> --repo <org>/<repo> --remove-label "$READY" --add-label "$CLAIMED"
|
|
181
|
+
gh issue comment <number> --repo <org>/<repo> --body "[claude-build-intake] Lifecycle repair: this issue carried the build-ready role ($READY) but is a parent/container with open child work (or a childless Epic/Story/Spike). I moved it to $CLAIMED without invoking the build agent. For parent/container issues, $CLAIMED means rollup/build-lane progress through child/leaf work; direct implementation must happen on leaf issues. Build-ready is leaf-only per leaf-only-lifecycle — move $READY onto its leaf children, or decompose/reclassify a childless Epic/Story/Spike."
|
|
181
182
|
```
|
|
182
183
|
|
|
183
184
|
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.
|
|
184
185
|
|
|
186
|
+
**Active dependency hold gate.** After the leaf-only gate passes, but still before the claim relabel, parse explicit blocker relationships from the issue body and durable Lisa relationship sections. Support these forms at minimum:
|
|
187
|
+
|
|
188
|
+
- `Blocked by: #123`
|
|
189
|
+
- `Blocked by: #123, #456`
|
|
190
|
+
- `Blocked by: owner/repo#123`
|
|
191
|
+
- `Blocked by: https://github.com/owner/repo/issues/123`
|
|
192
|
+
|
|
193
|
+
Resolve local `#123` references against the candidate issue's repo. Resolve qualified refs and GitHub issue URLs against their named repo. For each blocker, read the blocker issue's status labels with `gh issue view <number> --repo <owner>/<repo> --json labels,state`.
|
|
194
|
+
|
|
195
|
+
Default cleared blocker labels for GitHub build intake are:
|
|
196
|
+
|
|
197
|
+
- `status:code-review`
|
|
198
|
+
- `status:on-dev`
|
|
199
|
+
- `status:on-stg`
|
|
200
|
+
- `status:done`
|
|
201
|
+
|
|
202
|
+
A blocker is active if it is open and has no cleared status label. Treat `status:ready`, `status:in-progress`, missing status labels, and inaccessible blockers as active. Closed blockers are cleared. If any blocker is active, skip the candidate without changing lifecycle labels, without posting "Claimed", and without invoking `lisa:github-agent`. Record it under "Skipped (active blockers)" in the summary and include the active blocker refs. Keep any dependency-hold comment idempotent with a `[claude-build-intake]` prefix.
|
|
203
|
+
|
|
185
204
|
#### 3b. Claim
|
|
186
205
|
|
|
187
206
|
```bash
|
|
@@ -251,8 +270,10 @@ Cycle completed: <ISO timestamp>
|
|
|
251
270
|
Issues processed: <n>
|
|
252
271
|
- $DONE (build complete, PR ready): <n>
|
|
253
272
|
- <org>/<repo>#<number> <title> → PR <URL>
|
|
254
|
-
-
|
|
255
|
-
- <org>/<repo>#<number> <title> — build-ready on a parent
|
|
273
|
+
- Repaired (container — leaf-only-lifecycle): <n>
|
|
274
|
+
- <org>/<repo>#<number> <title> — build-ready on a parent/container; moved $READY → $CLAIMED without invoking lisa:github-agent; lifecycle-repair comment posted
|
|
275
|
+
- Skipped (active blockers): <n>
|
|
276
|
+
- <org>/<repo>#<number> <title> — waiting on <blocker refs>
|
|
256
277
|
- Blocked (pre-flight verify failed): <n>
|
|
257
278
|
- <org>/<repo>#<number> <title> — see issue comments
|
|
258
279
|
- Held (triage found ambiguities): <n>
|
|
@@ -265,9 +286,10 @@ Total PRs opened: <n>
|
|
|
265
286
|
|
|
266
287
|
## Idempotency & safety
|
|
267
288
|
|
|
268
|
-
- **Leaf-only claim gate runs first**: Phase 3a classifies each candidate before any claim; a container with open child work (or a childless Epic/Story/Spike) is
|
|
269
|
-
- **
|
|
270
|
-
- **
|
|
289
|
+
- **Leaf-only claim gate runs first**: Phase 3a classifies each candidate before any leaf claim; a container with open child work (or a childless Epic/Story/Spike) is moved `$READY` → `$CLAIMED` as lifecycle repair and never dispatched. The lifecycle-repair comment is idempotent — a re-entrant cycle does not re-post it.
|
|
290
|
+
- **Dependency hold runs before leaf claim**: explicit `Blocked by:` relationships are resolved after container repair is ruled out but before `$READY → $CLAIMED`; active blockers leave the leaf candidate in `$READY` and are reported as skipped, not blocked.
|
|
291
|
+
- **Claim-first ordering**: `$CLAIMED` set BEFORE `lisa:github-agent` invocation for leaves; containers are also moved to `$CLAIMED` to leave the ready pickup queue, but are not dispatched.
|
|
292
|
+
- **No writes outside the lifecycle**: this skill only relabels `$READY → $CLAIMED` and `$CLAIMED → $DONE`. For containers, `$READY → $CLAIMED` is a lifecycle repair, not a direct build claim. Every other label change is owned by `lisa:github-agent`.
|
|
271
293
|
- **Terminal native closure**: after `$CLAIMED → $DONE`, close the GitHub issue only when `$DONE` is the true terminal done value per `leaf-only-lifecycle`; intermediate env labels stay open.
|
|
272
294
|
- **Failure isolation**: per-issue exceptions caught and recorded; the cycle continues.
|
|
273
295
|
- **Single cycle per repo**: do not run two `lisa:github-build-intake` cycles in parallel against the same repo — concurrent claims could race. The scheduling layer is responsible for serialization.
|
|
@@ -290,8 +312,8 @@ If the repo has not adopted the `status:*` label namespace, this skill cannot ru
|
|
|
290
312
|
|
|
291
313
|
## Rules
|
|
292
314
|
|
|
293
|
-
- **
|
|
294
|
-
- Never relabel an issue the cycle
|
|
315
|
+
- **Dispatch leaves only.** Per the `leaf-only-lifecycle` rule, never dispatch a container — an issue with open child work, or a childless Epic/Story/Spike — even if it carries the build-ready role. Move it `$READY → $CLAIMED` as lifecycle repair (Phase 3a); never silently implement a container.
|
|
316
|
+
- Never relabel an issue outside the cycle's allowed transitions. The `$CLAIMED` label is the signature of cycle ownership for leaves, and the parent/container progress state for lifecycle repairs.
|
|
295
317
|
- Never bypass `lisa:github-agent` to do build work directly. `lisa:github-agent` owns the per-issue lifecycle.
|
|
296
318
|
- Never auto-transition past `$DONE`. Downstream labels (terminal `status:done`, etc.) are owned by QA / PM / merge automation.
|
|
297
319
|
- Never close a GitHub issue at intermediate env states (`status:on-dev`, `status:on-stg`, or configured equivalents). Native close happens only at the terminal `done` value.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: tracker-build-intake
|
|
3
|
-
description: "Vendor-neutral wrapper for the build-queue batch scanner. Reads `tracker` from .lisa.config.json (default: jira) 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 enforces the claim-time arm of the `leaf-only-lifecycle` rule —
|
|
3
|
+
description: "Vendor-neutral wrapper for the build-queue batch scanner. Reads `tracker` from .lisa.config.json (default: jira) 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 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/Story/Spike) 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
|
|
|
@@ -27,7 +27,7 @@ The vendor scanners also own the terminal native-closure step from `leaf-only-li
|
|
|
27
27
|
This shim is dispatch only — it does not reclassify or re-gate items — but the contract it forwards is part of the build-intake API, so it is documented here once and the three vendor scanners implement it identically. Per the vendor-neutral `leaf-only-lifecycle` rule, **build intake claims only independently implementable leaf work units**:
|
|
28
28
|
|
|
29
29
|
- A **leaf work unit** (Bug, Task, Sub-task, Improvement with no open child work) is claimed and built.
|
|
30
|
-
- A **container** — anything with open child work, or a childless Epic/Story/Spike — that still carries a stale build-ready role is **never
|
|
30
|
+
- A **container** — anything with open child work, or a childless Epic/Story/Spike — that still carries a stale build-ready role is **never dispatched**. The GitHub scanner moves it out of the pickup queue by replacing `status:ready` with `status:in-progress` and posting an idempotent lifecycle-repair comment; other vendor scanners skip or safe-block according to their native lifecycle semantics.
|
|
31
31
|
|
|
32
32
|
This is the claim-time arm of the rule. Its siblings are the write-time labeling (`lisa:tracker-write` → the vendor `*-write-*` skills apply build-ready to leaves only) and the validate-time S15 gate (`lisa:tracker-validate` → the vendor `*-validate-*` skills FAIL a build-ready container). All three arms cite `leaf-only-lifecycle` so no vendor drifts. Each vendor scanner implements the gate against its own hierarchy:
|
|
33
33
|
|
|
@@ -55,6 +55,6 @@ Intermediate env states are not native closure. A vendor scanner that resolves `
|
|
|
55
55
|
|
|
56
56
|
- Single cycle per invocation — the vendor skill processes the current `Ready` set and exits.
|
|
57
57
|
- The vendor skills run their own pre-flight checks (JIRA workflow transitions for the JIRA path; label namespace adoption for the GitHub and Linear paths) before processing items. Never bypass.
|
|
58
|
-
- **Leaf-only
|
|
58
|
+
- **Leaf-only dispatch, every vendor.** Per the `leaf-only-lifecycle` rule, each vendor scanner dispatches leaf work units only and moves or safe-blocks a container (open child work, or a childless Epic/Story/Spike) carrying a stale build-ready role according to its lifecycle semantics. This shim does not re-implement the gate — it relies on the vendor scanner's Phase 3a — but the contract is uniform across `jira`, `github`, and `linear` so behavior never drifts by tracker.
|
|
59
59
|
- **Terminal native closure, every capable vendor.** Per the same rule, each vendor scanner finalizes native open/closed state only at the true terminal `done` value. This shim never performs native closure itself, but callers can rely on the dispatched vendor scanner to apply the contract.
|
|
60
60
|
- Never run two intake cycles concurrently against overlapping queues — the scheduling layer is responsible for serialization.
|