@codyswann/lisa 2.237.0 → 2.239.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/dist/core/learnings-writer.d.ts +22 -0
  2. package/dist/core/learnings-writer.d.ts.map +1 -1
  3. package/dist/core/learnings-writer.js +51 -8
  4. package/dist/core/learnings-writer.js.map +1 -1
  5. package/dist/core/learnings.d.ts +1 -1
  6. package/dist/core/learnings.d.ts.map +1 -1
  7. package/dist/core/learnings.js +1 -1
  8. package/dist/core/learnings.js.map +1 -1
  9. package/package.json +1 -1
  10. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  11. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  12. package/plugins/lisa/.codex-plugin/skills/lisa-atlassian-access/SKILL.md +12 -1
  13. package/plugins/lisa/.codex-plugin/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
  14. package/plugins/lisa/.codex-plugin/skills/lisa-git-submit-pr/SKILL.md +3 -2
  15. package/plugins/lisa/.codex-plugin/skills/lisa-github-build-intake/SKILL.md +5 -1
  16. package/plugins/lisa/.codex-plugin/skills/lisa-implement/SKILL.md +2 -0
  17. package/plugins/lisa/.codex-plugin/skills/lisa-jira-build-intake/SKILL.md +5 -1
  18. package/plugins/lisa/.codex-plugin/skills/lisa-linear-access/SKILL.md +54 -0
  19. package/plugins/lisa/.codex-plugin/skills/lisa-linear-build-intake/SKILL.md +5 -1
  20. package/plugins/lisa/.codex-plugin/skills/lisa-persist-learning/SKILL.md +145 -0
  21. package/plugins/lisa/.codex-plugin/skills/lisa-persist-learning/agents/openai.yaml +4 -0
  22. package/plugins/lisa/agents/learning-judge.md +119 -0
  23. package/plugins/lisa/commands/persist-learning.md +6 -0
  24. package/plugins/lisa/rules/eager/rejection-detection.md +40 -0
  25. package/plugins/lisa/rules/reference/rejection-detection.md +103 -0
  26. package/plugins/lisa/skills/lisa-atlassian-access/SKILL.md +12 -1
  27. package/plugins/lisa/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
  28. package/plugins/lisa/skills/lisa-git-submit-pr/SKILL.md +3 -2
  29. package/plugins/lisa/skills/lisa-github-build-intake/SKILL.md +5 -1
  30. package/plugins/lisa/skills/lisa-implement/SKILL.md +2 -0
  31. package/plugins/lisa/skills/lisa-jira-build-intake/SKILL.md +5 -1
  32. package/plugins/lisa/skills/lisa-linear-access/SKILL.md +54 -0
  33. package/plugins/lisa/skills/lisa-linear-build-intake/SKILL.md +5 -1
  34. package/plugins/lisa/skills/lisa-persist-learning/SKILL.md +145 -0
  35. package/plugins/lisa/skills/lisa-persist-learning/agents/openai.yaml +4 -0
  36. package/plugins/lisa-agy/agents/learning-judge.md +119 -0
  37. package/plugins/lisa-agy/commands/lisa/persist-learning.md +6 -0
  38. package/plugins/lisa-agy/plugin.json +1 -1
  39. package/plugins/lisa-agy/skills/lisa-atlassian-access/SKILL.md +12 -1
  40. package/plugins/lisa-agy/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
  41. package/plugins/lisa-agy/skills/lisa-git-submit-pr/SKILL.md +3 -2
  42. package/plugins/lisa-agy/skills/lisa-github-build-intake/SKILL.md +5 -1
  43. package/plugins/lisa-agy/skills/lisa-implement/SKILL.md +2 -0
  44. package/plugins/lisa-agy/skills/lisa-jira-build-intake/SKILL.md +5 -1
  45. package/plugins/lisa-agy/skills/lisa-linear-access/SKILL.md +54 -0
  46. package/plugins/lisa-agy/skills/lisa-linear-build-intake/SKILL.md +5 -1
  47. package/plugins/lisa-agy/skills/lisa-persist-learning/SKILL.md +145 -0
  48. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  49. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  50. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  51. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  52. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  54. package/plugins/lisa-copilot/agents/learning-judge.agent.md +119 -0
  55. package/plugins/lisa-copilot/commands/lisa/persist-learning.md +6 -0
  56. package/plugins/lisa-copilot/rules/eager/rejection-detection.md +40 -0
  57. package/plugins/lisa-copilot/rules/reference/rejection-detection.md +103 -0
  58. package/plugins/lisa-copilot/skills/lisa-atlassian-access/SKILL.md +12 -1
  59. package/plugins/lisa-copilot/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
  60. package/plugins/lisa-copilot/skills/lisa-git-submit-pr/SKILL.md +3 -2
  61. package/plugins/lisa-copilot/skills/lisa-github-build-intake/SKILL.md +5 -1
  62. package/plugins/lisa-copilot/skills/lisa-implement/SKILL.md +2 -0
  63. package/plugins/lisa-copilot/skills/lisa-jira-build-intake/SKILL.md +5 -1
  64. package/plugins/lisa-copilot/skills/lisa-linear-access/SKILL.md +54 -0
  65. package/plugins/lisa-copilot/skills/lisa-linear-build-intake/SKILL.md +5 -1
  66. package/plugins/lisa-copilot/skills/lisa-persist-learning/SKILL.md +145 -0
  67. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-cursor/agents/learning-judge.md +119 -0
  69. package/plugins/lisa-cursor/commands/lisa/persist-learning.md +6 -0
  70. package/plugins/lisa-cursor/rules/rejection-detection-reference.mdc +108 -0
  71. package/plugins/lisa-cursor/rules/rejection-detection.mdc +45 -0
  72. package/plugins/lisa-cursor/skills/lisa-atlassian-access/SKILL.md +12 -1
  73. package/plugins/lisa-cursor/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
  74. package/plugins/lisa-cursor/skills/lisa-git-submit-pr/SKILL.md +3 -2
  75. package/plugins/lisa-cursor/skills/lisa-github-build-intake/SKILL.md +5 -1
  76. package/plugins/lisa-cursor/skills/lisa-implement/SKILL.md +2 -0
  77. package/plugins/lisa-cursor/skills/lisa-jira-build-intake/SKILL.md +5 -1
  78. package/plugins/lisa-cursor/skills/lisa-linear-access/SKILL.md +54 -0
  79. package/plugins/lisa-cursor/skills/lisa-linear-build-intake/SKILL.md +5 -1
  80. package/plugins/lisa-cursor/skills/lisa-persist-learning/SKILL.md +145 -0
  81. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  83. package/plugins/lisa-expo-agy/plugin.json +1 -1
  84. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  85. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  86. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  87. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  88. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  89. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  90. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  91. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  92. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  93. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  94. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  95. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  96. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  97. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  98. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  99. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  100. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  101. package/plugins/lisa-phaser/.claude-plugin/plugin.json +1 -1
  102. package/plugins/lisa-phaser/.codex-plugin/plugin.json +1 -1
  103. package/plugins/lisa-phaser-agy/plugin.json +1 -1
  104. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +1 -1
  105. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +1 -1
  106. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  107. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  108. package/plugins/lisa-rails-agy/plugin.json +1 -1
  109. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  110. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  111. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  112. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  113. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  114. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  115. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  116. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  117. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  118. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  119. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  120. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  121. package/plugins/src/base/agents/learning-judge.md +119 -0
  122. package/plugins/src/base/commands/persist-learning.md +6 -0
  123. package/plugins/src/base/rules/eager/rejection-detection.md +40 -0
  124. package/plugins/src/base/rules/reference/rejection-detection.md +103 -0
  125. package/plugins/src/base/skills/lisa-atlassian-access/SKILL.md +12 -1
  126. package/plugins/src/base/skills/lisa-drive-pr-to-merge/SKILL.md +62 -8
  127. package/plugins/src/base/skills/lisa-git-submit-pr/SKILL.md +3 -2
  128. package/plugins/src/base/skills/lisa-github-build-intake/SKILL.md +5 -1
  129. package/plugins/src/base/skills/lisa-implement/SKILL.md +2 -0
  130. package/plugins/src/base/skills/lisa-jira-build-intake/SKILL.md +5 -1
  131. package/plugins/src/base/skills/lisa-linear-access/SKILL.md +54 -0
  132. package/plugins/src/base/skills/lisa-linear-build-intake/SKILL.md +5 -1
  133. package/plugins/src/base/skills/lisa-persist-learning/SKILL.md +145 -0
@@ -186,6 +186,10 @@ This gate never blocks a legitimate flat Task/Bug: those have no open children a
186
186
 
187
187
  #### 3b. Claim
188
188
 
189
+ **Rejection detection runs first — before the relabel below.** Per the vendor-neutral `rejection-detection` rule (cite the slug; do not restate its classification table), classify this Issue at the **top of 3b, BEFORE** the `$READY → $CLAIMED` relabel — after the relabel the current-lane signal is gone. Read the Issue's history via `lisa-linear-access operation: history id: <ISSUE-ID>`, keyed on `status:*` **label** history (Linear build lanes are label-driven; resolve `addedLabelIds`/`removedLabelIds` against `list-issue-labels`), and classify it `rejection-reclaim | forward-only | never-left-ready | unknown` (a `rejection-reclaim` is the configured `$READY` label re-added after a later-lane label). Label names come from `.lisa.config.json`, never hardcoded. A failing/absent history yields `unknown` and the claim proceeds — detection never blocks the build. Issues carrying a learning marker (`[lisa-learning-drop]` / `[lisa-learning-pr]` / `[lisa-learning-upstream-handoff]`) or the `learning:needs-triage` label are never rejection triggers (no learning-about-learning). Carry the classification into the relabel and lifecycle below.
190
+
191
+ **On `rejection-reclaim`, reflect before re-implementing** (per `rejection-detection`): read the rejection evidence through the access layer — the Issue comments posted after the backward transition (the QA rejection comment) via `lisa-linear-access operation: list-comments` and the review threads on the rejected PR — assemble ONE candidate learning (rule, why, provenance linking the rejection comment + rejected PR, evidence links, scope hint, triggering issue, fingerprint `sll4-sha1(rule\ntriggering_issue)[:12]`), and route it to the `lisa-persist-learning` skill. If that skill is absent, record the candidate via `lisa-linear-access operation: save-comment` as a comment carrying a **visible prose line plus** the marker (a bare marker renders as an empty bubble) — `Recorded a candidate learning from this rejection (queued for the judgment gate): <one-line candidate rule>.` then `<!-- [lisa-rejection-candidate] key=<issue>-<transition-ts> -->` — and proceed. Dedupe on `<issue>-<backward-transition-timestamp>` — a second re-claim produces no duplicate. Unreadable/absent evidence → no candidate, still implement.
192
+
189
193
  Update labels via `lisa-linear-access operation: save-issue`: remove `$READY`, add `$CLAIMED`. Resolve label IDs via `list_issue_labels` (create `$CLAIMED` if missing).
190
194
 
191
195
  **Assign to the authenticated user when the Issue is unassigned.** A claim must be attributable. If the Issue has no assignee, set its `assigneeId` to the authenticated viewer (resolve the viewer's id via the Linear MCP identity — e.g. `get_user` for the current actor) through `lisa-linear-access operation: save-issue`. Leave an already-assigned Issue's assignee untouched — never reassign work that already has an owner.
@@ -205,7 +209,7 @@ After the claim succeeds, run the per-Issue lifecycle defined by the `linear-age
205
209
  - `lisa-linear-verify` — pre-flight quality gate, including the draft-then-block procedure on FAIL
206
210
  - `lisa-ticket-triage` — analytical triage gate (a `BLOCKED` verdict stops the cycle with findings posted)
207
211
  - Intent determination from the type label
208
- 2. **Dispatch the flow in-session:** when the gates pass, invoke the lifecycle skill via the Skill tool — `lisa-implement <ISSUE-ID>` for Build / Fix / Improve / Investigate-Only (or `lisa-plan` for an Epic-equivalent) — passing the full context bundle from the read step. `lisa-implement`'s own orchestration preamble then creates the per-item agent team (input-resolver, Roster Decision, specialist fanout) exactly as a direct invocation would.
212
+ 2. **Dispatch the flow in-session:** when the gates pass, invoke the lifecycle skill via the Skill tool — `lisa-implement <ISSUE-ID>` for Build / Fix / Improve / Investigate-Only (or `lisa-plan` for an Epic-equivalent) — passing the full context bundle from the read step. **When 3b classified this Issue `rejection-reclaim`, the context bundle passed to `lisa-implement` MUST include the rejection evidence summary** (what was rejected, the defect the QA comment named, the approach named as wrong) — reuse the evidence already read in 3b, do not fetch it twice — so the plan can address it per `rejection-detection`; absence of evidence never blocks. `lisa-implement`'s own orchestration preamble then creates the per-item agent team (input-resolver, Roster Decision, specialist fanout) exactly as a direct invocation would.
209
213
  3. **Milestone sync and evidence** (`lisa-linear-sync`, `lisa-linear-evidence`) happen at the milestones the `linear-agent` workflow defines, within the dispatched flow.
210
214
 
211
215
  If you are somehow running this skill as a spawned teammate inside an existing team (nested misrouting — Intake keeps this chain in the lead session), do NOT run the lifecycle inline and do NOT spawn named peers. Return this payload to the lead so the lead session can run this Phase 3c in-session:
@@ -0,0 +1,145 @@
1
+ ---
2
+ name: lisa-persist-learning
3
+ description: This skill should be used when a candidate learning (from a failure signal, rejection, or debrief) needs to be judged and routed. It computes a stable fingerprint, runs the candidate through the hostile-default learning-judge gate, and performs exactly the verdict's side effects — a dropped-with-reason note on the triggering issue (drop), an upstream handoff marker (lisa-upstream), or a confidence-routed pull request that touches only the learnings surface (durable-learning). Idempotent via marker dedupe; headless-safe; never blocks the primary build flow.
4
+ ---
5
+
6
+ # Persist Learning
7
+
8
+ Route ONE candidate learning through the judgment gate and act on the verdict. Candidate: $ARGUMENTS
9
+
10
+ Most candidates are dropped — that is the gate working, not a failure. Nothing is ever silent (every drop leaves a visible note), and no learning content ever reaches the learnings surface outside a pull request.
11
+
12
+ ## Candidate Input
13
+
14
+ Accept the candidate as JSON or `key=value` fields:
15
+
16
+ - `rule` — the proposed learning (must fit the executable contract: ≤240 chars, ≤2 lines)
17
+ - `why` — the causal claim
18
+ - `provenance` — stable refs (issues/PRs/commits/comments), ≤20
19
+ - `evidence_links` — concrete evidence refs available for citation
20
+ - `scope_hint` — `project` | `upstream` (a hint; the judge decides)
21
+ - `triggering_issue` — the issue/work item whose failure produced this candidate (required)
22
+ - `fingerprint` — optional; computed below when absent
23
+
24
+ ## Phase 0 — Fingerprint (stable dedupe key)
25
+
26
+ Every marker and branch below keys off one deterministic fingerprint:
27
+
28
+ ```text
29
+ fingerprint = "sll4-" + first 12 hex chars of sha1(normalized_rule + "\n" + triggering_issue)
30
+ normalized_rule = rule lowercased, all whitespace runs collapsed to single spaces, trimmed
31
+ ```
32
+
33
+ ```bash
34
+ NORM=$(printf '%s' "$RULE" | tr '[:upper:]' '[:lower:]' | tr -s '[:space:]' ' ' | sed 's/^ *//; s/ *$//')
35
+ FP="sll4-$(printf '%s\n%s' "$NORM" "$TRIGGERING_ISSUE" | shasum -a 1 | cut -c1-12)"
36
+ ```
37
+
38
+ (Use `sha1sum` where `shasum` is unavailable.) The same rule for the same triggering issue always produces the same fingerprint, so re-runs dedupe instead of duplicating comments, PRs, or branches.
39
+
40
+ ## Phase 1 — Judge (mandatory, never skipped)
41
+
42
+ Invoke the `learning-judge` agent (via the Agent/Task tool with `subagent_type: "learning-judge"` — the same invoke pattern `learner` uses for `skill-evaluator`) with the full candidate including the fingerprint. It returns a verdict: `classification`, `cited_evidence[]`, `rationale`, `confidence` (durable only), `disposition`.
43
+
44
+ **Respect the verdict — do not override it.** Never re-run the judge hoping for a different answer, and never persist anything the judge did not classify `durable-learning`.
45
+
46
+ ## Phase 2 — Route by disposition
47
+
48
+ All issue/PR comments below follow the marker-dedupe discipline from `lisa-github-write-prd` Phase 2, each with its own producer tag: match on the **marker, never the title or text**; **exactly one marker per body**; **never write a markerless body** (it breaks all future dedupe); include the eventual-consistency guard — when the `gh` search index is stale, also enumerate the bodies directly (`gh issue view <n> --json comments --jq '.comments[].body'` or `gh pr list --json number,body`) and grep for the marker before deciding to create.
49
+
50
+ ### `drop` (classification `one-off` or `misunderstanding/spec-gap`)
51
+
52
+ Post **one** comment on the triggering issue and write **nothing** — zero bytes — to the learnings surface (not a stub, not a placeholder):
53
+
54
+ ```markdown
55
+ <!-- [lisa-learning-drop] key=<fingerprint> -->
56
+ Dropped (<classification> — <plain-language gloss>): <reason>.
57
+ ```
58
+
59
+ The note is one line naming the classification (with its fixed plain-language gloss) and the reason, readable by a non-technical operator. Use exactly these glosses per class:
60
+
61
+ | Classification | Gloss |
62
+ |----------------|-------|
63
+ | `one-off` | a one-time fluke, not a recurring pattern |
64
+ | `misunderstanding/spec-gap` | traced to an unclear requirement, not a durable lesson |
65
+ | `lisa-upstream` | root cause is Lisa itself; routed upstream |
66
+
67
+ (The `lisa-upstream` gloss is used by the handoff note below, not by a drop note.) Dedupe before posting: if any comment on the triggering issue already carries `[lisa-learning-drop] key=<fingerprint>`, do not post again — report the existing note.
68
+
69
+ ### `handoff-upstream` (classification `lisa-upstream`)
70
+
71
+ Emit the handoff marker only — file **nothing** (no upstream issue, no local rule; the upstream filing flow [SLL-5] consumes this marker later):
72
+
73
+ ```markdown
74
+ <!-- [lisa-learning-upstream-handoff] key=<fingerprint> -->
75
+ Upstream handoff (lisa-upstream — root cause is Lisa itself; routed upstream): <reason>. Nothing persisted locally; upstream filing is a separate flow.
76
+ ```
77
+
78
+ Same one-comment marker dedupe on the triggering issue.
79
+
80
+ ### `persist` (classification `durable-learning`)
81
+
82
+ Continue to Phase 3.
83
+
84
+ ## Phase 3 — Persist via PR (durable-learning only)
85
+
86
+ No learning content is ever committed without a PR — there is no other write path, and the PR must touch **only** the learnings surface (any other changed file is a bug).
87
+
88
+ 1. **PR dedupe.** Search all PRs for the marker `[lisa-learning-pr] key=<fingerprint>` in the body (`gh pr list --state all --search '"<marker>" in:body' --json number,url`), with the stale-index guard above. If one exists, reference it and stop — never open a duplicate.
89
+ 2. **Resolve the learnings surface path — never hardcode it.** The canonical path is `resolveProjectLearningsFile` from `@codyswann/lisa/learnings`: the `PROJECT_LEARNINGS.md` sibling of the configured `.lisa.config.json` `projectRulesFile` (default `.claude/rules/PROJECT_LEARNINGS.md`):
90
+
91
+ ```bash
92
+ LEARNINGS_FILE=$(node -e 'import("@codyswann/lisa/learnings").then(async m => { const c = await m.readProjectConfig(process.cwd()); console.log(m.resolveProjectLearningsFile(c)); })')
93
+ ```
94
+
95
+ 3. **Consolidation check (mandatory before writing).** Parse the existing entries (`parseLearningsFile` from `@codyswann/lisa/learnings`) and look for entries related to the new rule (same failure class, overlapping topic, or near-duplicate wording). Then write through the executable contract — **never hand-edit the markdown**:
96
+ - **Related entry found** → consolidate via `persistConsolidatedLearning(projectRoot, entry, { supersede: [<related ids>] })`, merging the old entry's still-true content into the new rule. Never append a near-duplicate sibling — a sibling is a bug that fails review.
97
+ - **No related entry** → append via `persistLearningEntry(projectRoot, entry)` and state in the PR body why appending was correct.
98
+ - Entry mapping: `id` = the fingerprint; `rule`/`why`/`provenance` from the candidate; `first_learned` = `last_confirmed` = today (ISO date; on consolidation keep the superseded entry's earliest `first_learned`); `confidence` = the judge's `high`/`low`. The writer re-asserts the entry and token budgets — an over-budget failure means consolidate harder or drop, never truncate by hand.
99
+ 4. **Branch + commit.** Work on branch `learning/<fingerprint>`. Commit only the learnings file; verify with `git diff --name-only` that the diff touches nothing else.
100
+ 5. **PR body.** Exactly one marker line plus the reviewable story:
101
+
102
+ ```markdown
103
+ <!-- [lisa-learning-pr] key=<fingerprint> -->
104
+
105
+ ## Learning
106
+ <rule> — <judge rationale>
107
+
108
+ ## Provenance
109
+ - Triggering issue: <ref>
110
+ - Ancestor issue/PR (the past failure this is round 2 of): <ref or none found>
111
+ - Rejection comments that produced the candidate: <refs or none>
112
+ - Cited evidence (from the judge): <refs>
113
+
114
+ ## Consolidation decision
115
+ <"Superseded entry id(s) X, Y: <why they merged>" | "Appended: no related entry exists — <one-line search summary>">
116
+ ```
117
+
118
+ For a **low-confidence** PR, the body must additionally end with this fixed decision-framing line so the human at the gate knows exactly what merging means:
119
+
120
+ ```markdown
121
+ **Merge** to adopt this rule into every future session for all six coding agents; **close** to discard it.
122
+ ```
123
+
124
+ 6. **Confidence routing.**
125
+ - **`high`** → submit through `lisa-git-submit-pr` with its defaults: auto-merge ON, merging through the project's normal gates.
126
+ - **`low`** → submit through `lisa-git-submit-pr` with `auto_merge=false` (drives the PR to green-and-open `awaiting-human`, never merging — even on repos that disallow auto-merge). Then apply the human-triage label, creating it idempotently first (the `lisa-drive-pr-to-merge` label pattern — `|| true` tolerates only already-exists, so verify):
127
+
128
+ ```bash
129
+ gh label create "learning:needs-triage" \
130
+ --description "Low-confidence learning PR awaiting human triage" \
131
+ --color FBCA04 || true
132
+ gh label list --search "learning:needs-triage" --json name \
133
+ --jq '[.[].name] | contains(["learning:needs-triage"])' # must print true
134
+ gh pr edit <pr> --add-label "learning:needs-triage"
135
+ ```
136
+
137
+ A low-confidence PR sitting OPEN with green checks and `autoMergeRequest: null` is this mode's **success** state — a human merges or closes it. All pending low-confidence learning PRs are findable by filtering on the `learning:needs-triage` label (`gh pr list --label "learning:needs-triage"`).
138
+
139
+ ## Rules
140
+
141
+ - **Headless-safe**: no interactive prompts; must run identically under an intake cron.
142
+ - **Never block the build**: if judging or persistence fails, report the failure and let the primary flow continue — shipping the triggering issue always outranks recording a learning about it.
143
+ - **No learning loops about learning**: never feed this skill a candidate whose triggering artifact is itself learning machinery (a `[lisa-learning-*]`-marked comment, learning PR, or handoff); the judge's Step 0 guard backstops this.
144
+ - **Idempotent**: re-running with the same candidate posts no duplicate comment, opens no duplicate PR, and writes no duplicate entry — the fingerprint and markers guarantee it.
145
+ - **One write path**: the learnings surface changes only through `persistLearningEntry` / `persistConsolidatedLearning` inside a PR. Never hand-edit the file, never commit it to the default branch directly.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Expo and React Native-specific skills, agents, rules, and MCP servers.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-expo",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Expo/React Native-specific skills, agents, rules, and MCP servers",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Harper/Fabric-specific Lisa rules for TypeScript component apps.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-harper-fabric",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Harper/Fabric-specific rules for TypeScript component apps",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "NestJS-specific skills and migration write-protection hooks.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-nestjs",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "NestJS-specific skills (GraphQL, TypeORM) and hooks (migration write-protection)",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
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.237.0",
3
+ "version": "2.239.0",
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"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-openclaw",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
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.237.0",
3
+ "version": "2.239.0",
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.237.0",
3
+ "version": "2.239.0",
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-phaser",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-phaser",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Phaser 4 game-development rules for TypeScript projects",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.237.0",
3
+ "version": "2.239.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"