@codyswann/lisa 2.116.2 → 2.118.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 (83) hide show
  1. package/dist/codex/hooks-installer.js +60 -16
  2. package/dist/codex/hooks-installer.js.map +1 -1
  3. package/dist/codex/scripts/inject-rules.sh +14 -2
  4. package/package.json +3 -2
  5. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  6. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  7. package/plugins/lisa/hooks/inject-rules.sh +14 -3
  8. package/plugins/lisa/rules/eager/base-rules.md +70 -0
  9. package/plugins/lisa/rules/eager/coding-philosophy.md +27 -0
  10. package/plugins/lisa/rules/eager/config-resolution.md +28 -0
  11. package/plugins/lisa/rules/eager/documentation-source-paths.md +13 -0
  12. package/plugins/lisa/rules/eager/empirical-inquiry.md +22 -0
  13. package/plugins/lisa/rules/eager/intent-routing.md +18 -0
  14. package/plugins/lisa/rules/eager/leaf-only-lifecycle.md +39 -0
  15. package/plugins/lisa/rules/eager/prd-lifecycle-rollup.md +31 -0
  16. package/plugins/lisa/rules/eager/repo-scope-split.md +39 -0
  17. package/plugins/lisa/rules/eager/security-audit-handling.md +29 -0
  18. package/plugins/lisa/rules/eager/usage-accounting.md +28 -0
  19. package/plugins/lisa/rules/eager/verification.md +21 -0
  20. package/plugins/lisa/rules/eager/wiki-knowledge-source.md +16 -0
  21. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  22. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  23. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  24. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  25. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  26. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  27. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  28. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  29. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  30. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  31. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  32. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  33. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  34. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  35. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  36. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  37. package/plugins/lisa-wiki/scripts/ensure-gitignore.mjs +131 -0
  38. package/plugins/lisa-wiki/skills/lisa-wiki-setup/SKILL.md +13 -4
  39. package/plugins/lisa-wiki/templates/wrapper-gitignore.txt +19 -0
  40. package/plugins/src/base/hooks/inject-rules.sh +14 -3
  41. package/plugins/src/base/rules/eager/base-rules.md +70 -0
  42. package/plugins/src/base/rules/eager/coding-philosophy.md +27 -0
  43. package/plugins/src/base/rules/eager/config-resolution.md +28 -0
  44. package/plugins/src/base/rules/eager/documentation-source-paths.md +13 -0
  45. package/plugins/src/base/rules/eager/empirical-inquiry.md +22 -0
  46. package/plugins/src/base/rules/eager/intent-routing.md +18 -0
  47. package/plugins/src/base/rules/eager/leaf-only-lifecycle.md +39 -0
  48. package/plugins/src/base/rules/eager/prd-lifecycle-rollup.md +31 -0
  49. package/plugins/src/base/rules/eager/repo-scope-split.md +39 -0
  50. package/plugins/src/base/rules/eager/security-audit-handling.md +29 -0
  51. package/plugins/src/base/rules/eager/usage-accounting.md +28 -0
  52. package/plugins/src/base/rules/eager/verification.md +21 -0
  53. package/plugins/src/base/rules/eager/wiki-knowledge-source.md +16 -0
  54. package/plugins/src/wiki/scripts/ensure-gitignore.mjs +131 -0
  55. package/plugins/src/wiki/skills/lisa-wiki-setup/SKILL.md +13 -4
  56. package/plugins/src/wiki/templates/wrapper-gitignore.txt +19 -0
  57. package/scripts/check-rules-pairing.sh +91 -0
  58. /package/plugins/lisa/rules/{base-rules.md → reference/base-rules.md} +0 -0
  59. /package/plugins/lisa/rules/{coding-philosophy.md → reference/coding-philosophy.md} +0 -0
  60. /package/plugins/lisa/rules/{config-resolution.md → reference/config-resolution.md} +0 -0
  61. /package/plugins/lisa/rules/{documentation-source-paths.md → reference/documentation-source-paths.md} +0 -0
  62. /package/plugins/lisa/rules/{empirical-inquiry.md → reference/empirical-inquiry.md} +0 -0
  63. /package/plugins/lisa/rules/{intent-routing.md → reference/intent-routing.md} +0 -0
  64. /package/plugins/lisa/rules/{leaf-only-lifecycle.md → reference/leaf-only-lifecycle.md} +0 -0
  65. /package/plugins/lisa/rules/{prd-lifecycle-rollup.md → reference/prd-lifecycle-rollup.md} +0 -0
  66. /package/plugins/lisa/rules/{repo-scope-split.md → reference/repo-scope-split.md} +0 -0
  67. /package/plugins/lisa/rules/{security-audit-handling.md → reference/security-audit-handling.md} +0 -0
  68. /package/plugins/lisa/rules/{usage-accounting.md → reference/usage-accounting.md} +0 -0
  69. /package/plugins/lisa/rules/{verification.md → reference/verification.md} +0 -0
  70. /package/plugins/lisa/rules/{wiki-knowledge-source.md → reference/wiki-knowledge-source.md} +0 -0
  71. /package/plugins/src/base/rules/{base-rules.md → reference/base-rules.md} +0 -0
  72. /package/plugins/src/base/rules/{coding-philosophy.md → reference/coding-philosophy.md} +0 -0
  73. /package/plugins/src/base/rules/{config-resolution.md → reference/config-resolution.md} +0 -0
  74. /package/plugins/src/base/rules/{documentation-source-paths.md → reference/documentation-source-paths.md} +0 -0
  75. /package/plugins/src/base/rules/{empirical-inquiry.md → reference/empirical-inquiry.md} +0 -0
  76. /package/plugins/src/base/rules/{intent-routing.md → reference/intent-routing.md} +0 -0
  77. /package/plugins/src/base/rules/{leaf-only-lifecycle.md → reference/leaf-only-lifecycle.md} +0 -0
  78. /package/plugins/src/base/rules/{prd-lifecycle-rollup.md → reference/prd-lifecycle-rollup.md} +0 -0
  79. /package/plugins/src/base/rules/{repo-scope-split.md → reference/repo-scope-split.md} +0 -0
  80. /package/plugins/src/base/rules/{security-audit-handling.md → reference/security-audit-handling.md} +0 -0
  81. /package/plugins/src/base/rules/{usage-accounting.md → reference/usage-accounting.md} +0 -0
  82. /package/plugins/src/base/rules/{verification.md → reference/verification.md} +0 -0
  83. /package/plugins/src/base/rules/{wiki-knowledge-source.md → reference/wiki-knowledge-source.md} +0 -0
@@ -0,0 +1,39 @@
1
+ # Repo Scope & Work-Time Splitting (load-bearing)
2
+
3
+ **Leaf work units are single-repo.** A leaf is an individually implementable ticket with no children — types **Bug, Task, Sub-task, Improvement**. Each names exactly one repo. **Epic, Story, Spike** are coordination containers and may span repos.
4
+
5
+ Enforced at four points: gate **S10** (`*-validate-*`, write time), `task-decomposition` step 1.5 (PRD-decomposition time), claim-time repo scoping (`*-build-intake`), and the work-time split procedure (an existing ticket about to be implemented).
6
+
7
+ ## Choose the right strategy
8
+
9
+ - **Decomposition-time (no tickets exist yet):** use `task-decomposition` step 1.5 — one work unit per repo under a parent Story.
10
+ - **Work-time (a ticket already exists):** narrow the original to one repo, spin off a sibling per additional repo, link by dependency. Do NOT invent a new parent — siblings inherit the original's existing parent.
11
+
12
+ ## Work-time split (pre-flight gate, agent-performed)
13
+
14
+ 1. **Detect repos.** Parse description + AC + approach, confirm against actual code surfaces. If single-repo, no split.
15
+ 2. **Pick the keeper.** Default: the original keeps the consumer / user-facing repo.
16
+ 3. **Create one sibling per extra repo**, cloning metadata (re-prefix summary, scope AC, carry parent, env, sign-in).
17
+ 4. **Link by dependency.** Producer **blocks** consumer (`is blocked by` on consumer / `blocks` on producer). No clear direction → `relates to`.
18
+ 5. **Narrow the original.** Edit summary prefix, Repository section, AC; remove cross-repo references.
19
+ 6. **Comment** on the original noting the split, linking each sibling.
20
+ 7. **Re-validate.** Run `tracker-verify` (S10) on the original and every sibling. All must PASS single-repo.
21
+ 8. **Proceed in dependency order.** Producer siblings first.
22
+
23
+ ## When to BLOCK instead of split
24
+
25
+ Fall back to the standard BLOCK + reassign-to-Reporter path when:
26
+
27
+ - Repos cannot be determined confidently from ticket + code.
28
+ - Splitting would strand stakeholder context only the reporter can re-scope.
29
+ - Required clone metadata (parent, env, credentials) is itself missing.
30
+
31
+ ## Claim-time repo scoping (build-intake)
32
+
33
+ A tracker can oversee multiple repos. Build-intake claims only current-repo tickets. Resolve current repo per `config-resolution` (config `repo` → `github.repo` → git remote basename). For each ready candidate:
34
+
35
+ 1. **Read `repo:<name>` label.** Wrong repo → skip. Current repo → leaf-only gate + claim. Unlabeled → determine + stamp + re-apply.
36
+ 2. **Multi-repo leaf → split, never claim.** Each split sibling is created build-ready and stamped with its own `repo:<name>`.
37
+ 3. **Wrong-repo single-repo leaf → skip** (label keeps it cheap next cycle).
38
+
39
+ Vendor mechanics (JIRA/GitHub/Linear) and full procedure: [reference/repo-scope-split.md](../reference/repo-scope-split.md).
@@ -0,0 +1,29 @@
1
+ # Security Audit Handling (load-bearing)
2
+
3
+ If `git push` fails because the pre-push hook reports security vulnerabilities, follow the rules below. **Never use `--no-verify`** to bypass the security audit.
4
+
5
+ ## Core rule
6
+
7
+ Override the actually-vulnerable **leaf package**, not its parent. The audit chain shows `parent › intermediate › vulnerable` — only the vulnerable leaf needs the override.
8
+
9
+ **Never override a parent package to force a lower major version.** Other packages may depend on the newer major; a forced downgrade breaks them.
10
+
11
+ Before adding any override, verify:
12
+ - You are targeting the actually-vulnerable package, not a parent in the chain.
13
+ - The override is compatible with all dependents (check via `bun why <pkg>` or `npm ls <pkg>`).
14
+ - The override does not downgrade across a major version boundary other deps require.
15
+
16
+ ## Node.js (GHSA)
17
+
18
+ 1. Note GHSA ID, package, advisory URL.
19
+ 2. If a patched version exists: add a resolution AND override in `package.json` for the leaf package, regenerate the lockfile, commit, retry.
20
+ 3. If no patch but safe (transitive, no untrusted input, dev/build only): add an exclusion to `audit.ignore.local.json` with `{"id", "package", "reason"}`, commit, retry.
21
+
22
+ ## Rails (bundler-audit)
23
+
24
+ 1. Note advisory ID, gem, URL.
25
+ 2. If direct dep with patch: update Gemfile constraint, `bundle update <gem>`, commit, retry.
26
+ 3. If transitive with patch: `bundle update <gem>` to bump the lockfile only, commit, retry.
27
+ 4. If no patch but safe: document the exception, retry.
28
+
29
+ Full procedure with examples: [reference/security-audit-handling.md](../reference/security-audit-handling.md).
@@ -0,0 +1,28 @@
1
+ # Usage Accounting (load-bearing)
2
+
3
+ Lisa attaches AI usage and cost telemetry to every artifact it creates/updates. The format is a single canonical managed section.
4
+
5
+ ## Managed section
6
+
7
+ Every artifact with inline body content gets exactly one section:
8
+
9
+ ```markdown
10
+ ## Lisa Usage
11
+ ```
12
+
13
+ **Canonical. Rewrite in place; never append a second usage section.** If the host can't safely edit body, write the same section in a comment and treat that comment as the managed artifact for future rewrites.
14
+
15
+ ## Required field semantics
16
+
17
+ Each direct entry records ONE logical Lisa run on ONE artifact. `entry_id` is the stable dedupe key — rewriting the same logical run with the same `entry_id` updates in place; a different run gets a different `entry_id`.
18
+
19
+ - **`source`**: `observed` (runtime supplied) / `estimated` (derived from trustworthy metadata + pricing contract) / `unavailable`.
20
+ - **`pricing_status`**: same trinary plus `missing` (cost not known but should be).
21
+ - **Absence ≠ zero.** `null` means unknown; `0` means explicitly zero. Always write the entry — never silently omit.
22
+ - Do NOT replace observed counts with estimates.
23
+
24
+ ## Rollup
25
+
26
+ Container artifacts (Epic, PRD, etc.) roll up usage from their direct children. Roll-up is recursive — a parent's `## Lisa Usage` aggregates its descendants' direct entries. Re-writes are idempotent: re-running an intake or lifecycle skill must not duplicate entries.
27
+
28
+ Full schema (all 17 fields, pricing semantics, rollup math, idempotent-rewrite rules): [reference/usage-accounting.md](../reference/usage-accounting.md).
@@ -0,0 +1,21 @@
1
+ # Empirical Verification (load-bearing)
2
+
3
+ **Verification is not linting, typechecking, or testing.** Those are *quality checks* — necessary prerequisites, but NOT verification.
4
+
5
+ **Verification is using the resulting software the way a user would** — interacting with the UI, calling the API, running the CLI, observing behavior. Tests pass in isolation; verification proves the system works as a whole.
6
+
7
+ ## Mandatory
8
+
9
+ - **Never claim success without runtime evidence.** "The code looks correct" is not evidence.
10
+ - **If all you did was run tests, typecheck, and lint — you have NOT verified.**
11
+ - **Before starting implementation, state your verification plan** — how you will USE the resulting software to prove it works. A plan that only lists `test`/`typecheck`/`lint` commands is not a plan. Do not begin until confirmed.
12
+ - **After verifying empirically, codify it as a regression test** via the `codify-verification` skill — Playwright for UI, integration test for API/DB/auth, benchmark for performance. Codification is mandatory for every verification type except PR/Documentation/Deploy and Investigate-Only spikes.
13
+ - **Every PR must include reviewer replay steps** — the exact human steps to use the software and confirm the change works. Not test commands. If a reviewer can't reproduce from the PR description alone, the PR is incomplete.
14
+
15
+ ## Roles
16
+
17
+ - **Builder agent** — implements the change.
18
+ - **Verifier agent** — acts as the end user / API client / operator. Independent from Builder when possible.
19
+ - **Human overseer** — approves risky operations and anything agents cannot fully verify.
20
+
21
+ Full operational contract (verification types, evidence formats, escalation protocol): [reference/verification.md](../reference/verification.md).
@@ -0,0 +1,16 @@
1
+ # Wiki as Knowledge Source (load-bearing)
2
+
3
+ If the project has an LLM Wiki (a `wiki/` directory with `index.md`), treat it as the canonical source of durable project knowledge.
4
+
5
+ Before researching background, conventions, ownership, architecture, glossary, or "how/why does X work here":
6
+
7
+ 1. **Consult the wiki first.** Start from `wiki/index.md` or use the wiki query skill (`/lisa-wiki-query`).
8
+ 2. **Use what the wiki says** as the authoritative answer when it covers the question — do not re-derive it from raw sources.
9
+ 3. **Fall back to primary sources** (code, tickets, commit history, external docs) only when the wiki is silent, ambiguous, or contradicted by what you observe.
10
+ 4. **Surface gaps.** If the wiki is wrong, stale, or missing knowledge that belongs there, flag it — and where the workflow supports it, capture the correction via `/lisa-wiki-ingest`.
11
+
12
+ The wiki documents knowledge; it does NOT override executable behavior. When wiki and running code disagree about what the system does, trust the code and treat the wiki as out of date.
13
+
14
+ If the project has no `wiki/`, this rule does not apply.
15
+
16
+ Full prose: [reference/wiki-knowledge-source.md](../reference/wiki-knowledge-source.md).
@@ -0,0 +1,131 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * ensure-gitignore.mjs — merge the lisa-wiki gitignore block into the project's
4
+ * `.gitignore`, idempotently. Dependency-free.
5
+ *
6
+ * The block is delimited by `# BEGIN: AI GUARDRAILS WIKI` and
7
+ * `# END: AI GUARDRAILS WIKI` markers (see templates/wrapper-gitignore.txt).
8
+ * Behavior matches the base lisa plugin's copy-contents strategy
9
+ * (src/strategies/copy-contents.ts):
10
+ *
11
+ * - If the file is missing, create it with just the block.
12
+ * - If the block markers exist, replace the block in place.
13
+ * - If the markers don't exist, append the block to the end (preserving a
14
+ * trailing newline).
15
+ *
16
+ * Patterns outside the marker block are NEVER touched. Re-running produces no
17
+ * spurious diff once the file is in sync.
18
+ *
19
+ * Usage: node ensure-gitignore.mjs [--cwd <project-dir>] [--dry-run]
20
+ * default cwd: process.cwd()
21
+ * --dry-run prints the proposed merge result to stdout instead of writing
22
+ *
23
+ * Exit code 0 = ok (file was created, updated, or already in sync).
24
+ * Exit code 1 = error (e.g. template missing).
25
+ */
26
+ import fs from "node:fs";
27
+ import path from "node:path";
28
+ import { fileURLToPath } from "node:url";
29
+
30
+ const BEGIN_MARKER = "# BEGIN: AI GUARDRAILS WIKI";
31
+ const END_MARKER = "# END: AI GUARDRAILS WIKI";
32
+
33
+ function fail(msg) {
34
+ console.error(`✗ ${msg}`);
35
+ process.exit(1);
36
+ }
37
+
38
+ const scriptDir = path.dirname(fileURLToPath(import.meta.url));
39
+ const pluginRoot = path.dirname(scriptDir);
40
+ const templatePath = path.join(
41
+ pluginRoot,
42
+ "templates",
43
+ "wrapper-gitignore.txt"
44
+ );
45
+
46
+ const argv = process.argv.slice(2);
47
+ const cwdIndex = argv.indexOf("--cwd");
48
+ const projectDir =
49
+ cwdIndex !== -1 && argv[cwdIndex + 1]
50
+ ? path.resolve(argv[cwdIndex + 1])
51
+ : process.cwd();
52
+ const dryRun = argv.includes("--dry-run");
53
+
54
+ if (!fs.existsSync(templatePath)) {
55
+ fail(`template not found: ${templatePath}`);
56
+ }
57
+
58
+ const templateRaw = fs.readFileSync(templatePath, "utf8");
59
+ const block = extractBlock(templateRaw);
60
+ if (!block) {
61
+ fail(
62
+ `template at ${templatePath} does not contain the expected marker pair (${BEGIN_MARKER} / ${END_MARKER})`
63
+ );
64
+ }
65
+
66
+ const gitignorePath = path.join(projectDir, ".gitignore");
67
+ const existing = fs.existsSync(gitignorePath)
68
+ ? fs.readFileSync(gitignorePath, "utf8")
69
+ : null;
70
+
71
+ const merged = mergeBlock(existing, block);
72
+
73
+ if (existing !== null && merged === existing) {
74
+ console.log(`✓ .gitignore already in sync (${gitignorePath})`);
75
+ process.exit(0);
76
+ }
77
+
78
+ if (dryRun) {
79
+ process.stdout.write(merged);
80
+ process.exit(0);
81
+ }
82
+
83
+ fs.writeFileSync(gitignorePath, merged);
84
+ const verb = existing === null ? "created" : "updated";
85
+ console.log(`✓ ${verb} ${gitignorePath}`);
86
+ process.exit(0);
87
+
88
+ /**
89
+ * Pull the block (markers included) out of arbitrary text. Returns null when
90
+ * the marker pair is missing or out of order.
91
+ */
92
+ function extractBlock(text) {
93
+ const startIdx = text.indexOf(BEGIN_MARKER);
94
+ if (startIdx === -1) return null;
95
+ const endStart = text.indexOf(END_MARKER, startIdx + BEGIN_MARKER.length);
96
+ if (endStart === -1) return null;
97
+ const endIdx = endStart + END_MARKER.length;
98
+ return text.slice(startIdx, endIdx);
99
+ }
100
+
101
+ /**
102
+ * Merge a freshly-rendered block into the destination file content.
103
+ * - existing === null → return the block alone (file will be created)
104
+ * - existing has the markers → replace the block in place
105
+ * - existing lacks the markers → append the block at the end
106
+ * Always normalizes to exactly one trailing newline.
107
+ */
108
+ function mergeBlock(existing, freshBlock) {
109
+ if (existing === null) {
110
+ return `${freshBlock.trimEnd()}\n`;
111
+ }
112
+
113
+ const startIdx = existing.indexOf(BEGIN_MARKER);
114
+ if (startIdx !== -1) {
115
+ const endStart = existing.indexOf(
116
+ END_MARKER,
117
+ startIdx + BEGIN_MARKER.length
118
+ );
119
+ if (endStart !== -1) {
120
+ const endIdx = endStart + END_MARKER.length;
121
+ const before = existing.slice(0, startIdx);
122
+ const after = existing.slice(endIdx);
123
+ const trimmedAfter = after.startsWith("\n") ? after : `\n${after}`;
124
+ return `${before}${freshBlock.trimEnd()}${trimmedAfter}`;
125
+ }
126
+ }
127
+
128
+ // No marker pair in the destination — append.
129
+ const base = existing.endsWith("\n") ? existing : `${existing}\n`;
130
+ return `${base}\n${freshBlock.trimEnd()}\n`;
131
+ }
@@ -30,13 +30,22 @@ never overwrites human-authored content.
30
30
  3. **Contract.** Render `wiki/schema/llm-wiki-contract.md` from the plugin templates + config via
31
31
  `scripts/render-contract.mjs`, stamping the `kernelVersion`. This snapshot keeps the wiki
32
32
  self-describing without the plugin installed.
33
- 4. **Pointers.** Ensure `AGENTS.md` / `CLAUDE.md` point at the contract + plugin (thin pointers only).
34
- 5. **Staff.** For each `config.staff[]` entry (the standard roster by default), generate the role's
33
+ 4. **Gitignore.** Merge the lisa-wiki gitignore block into the project's `.gitignore` via
34
+ `scripts/ensure-gitignore.mjs`. The block (delimited by `# BEGIN: AI GUARDRAILS WIKI` /
35
+ `# END: AI GUARDRAILS WIKI`) covers transient per-session worktrees and Lisa backup snapshots
36
+ (`.claude/worktrees/`, `.codex/worktrees/`, `.lisabak/`). Idempotent: re-running produces no
37
+ diff once the block is present. The block coexists with the base lisa plugin's
38
+ `# BEGIN: AI GUARDRAILS` block — both can be installed without overwriting each other because
39
+ the copy-contents strategy keys on the marker suffix. Wiki-wrapper repos (mode `wrapper` /
40
+ `standalone`) typically don't enable the base lisa plugin, so this step is the only path by
41
+ which they get the worktree-ignore patterns.
42
+ 5. **Pointers.** Ensure `AGENTS.md` / `CLAUDE.md` point at the contract + plugin (thin pointers only).
43
+ 6. **Staff.** For each `config.staff[]` entry (the standard roster by default), generate the role's
35
44
  `wiki/staff/<role>.md` page and its dual-runtime subagents by delegating to `lisa-wiki-add-role`
36
45
  (running the subagents is out of scope).
37
- 6. **README.** Apply the chosen README mode (ingest the old README first; `rich` keeps install/usage +
46
+ 7. **README.** Apply the chosen README mode (ingest the old README first; `rich` keeps install/usage +
38
47
  adds the onboarding line; `stub` is the minimal pointer; `preserve` leaves it).
39
- 7. **Verify.** Run `lisa-wiki-doctor` and report the verdict + any blocking items.
48
+ 8. **Verify.** Run `lisa-wiki-doctor` and report the verdict + any blocking items.
40
49
 
41
50
  ## Standard roster
42
51
  The default operating team seeded into `config.staff[]` for every new wiki (Chief of Staff plus six
@@ -0,0 +1,19 @@
1
+ # BEGIN: AI GUARDRAILS WIKI
2
+ # Managed by the lisa-wiki kernel. Do not edit between these markers — re-run
3
+ # /lisa-wiki:setup (or the equivalent script) to update. Patterns outside the
4
+ # block are preserved untouched. The "WIKI" suffix lets this block coexist
5
+ # with the base lisa plugin's "# BEGIN: AI GUARDRAILS" block when both are
6
+ # installed (the copy-contents strategy keys on the marker suffix).
7
+
8
+ # Claude Code per-session git worktrees. Each Claude session that needs an
9
+ # isolated working copy spawns one under .claude/worktrees/ (via
10
+ # `git worktree add`). They are transient, large (often hundreds of MB each),
11
+ # and per-developer; they must never be committed.
12
+ /.claude/worktrees/
13
+
14
+ # Codex CLI per-session worktrees (Codex equivalent of the above).
15
+ /.codex/worktrees/
16
+
17
+ # Lisa backup snapshots (created by `lisa` runs).
18
+ /.lisabak/
19
+ # END: AI GUARDRAILS WIKI
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env bash
2
+ # Fails if any plugin's rules/eager/X.md is missing its rules/reference/X.md
3
+ # pair (or vice versa). The eager/reference split documents the contract that
4
+ # every eager head points at a reference body for the long-form detail; an
5
+ # unpaired file means either a head without a body (broken breadcrumb) or a
6
+ # body without a head (orphaned, never injected).
7
+ #
8
+ # Bootstrap files are exempt: rules/eager/00-bootstrap.md (and any other file
9
+ # matching rules/eager/00-*.md) is allowed to have no reference pair. The
10
+ # leading "00-" prefix marks files that are eager-only by design.
11
+ #
12
+ # Skip rule: a rule may opt out of pairing by listing its basename in
13
+ # rules/.pair-exempt — one filename per line, comments start with `#`. Use
14
+ # sparingly; the default expectation is that every eager file pairs.
15
+ set -euo pipefail
16
+
17
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
18
+ ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)"
19
+ cd "$ROOT_DIR"
20
+
21
+ failed=0
22
+
23
+ check_plugin() {
24
+ local rules_dir="$1"
25
+ local eager_dir="$rules_dir/eager"
26
+ local reference_dir="$rules_dir/reference"
27
+
28
+ # Skip plugins that haven't adopted the split yet (no eager/ subdir).
29
+ [ -d "$eager_dir" ] || return 0
30
+
31
+ # Build the opt-out list, if present.
32
+ local exempt_file="$rules_dir/.pair-exempt"
33
+ local exempt_pattern=""
34
+ if [ -f "$exempt_file" ]; then
35
+ exempt_pattern="$(grep -v '^[[:space:]]*#' "$exempt_file" | grep -v '^[[:space:]]*$' || true)"
36
+ fi
37
+
38
+ # Every eager/X.md (except 00-bootstrap-style files and explicit exemptions)
39
+ # must have a reference/X.md pair.
40
+ while IFS= read -r eager_file; do
41
+ local base
42
+ base="$(basename "$eager_file")"
43
+ # Built-in exemption for bootstrap files.
44
+ case "$base" in
45
+ 00-*) continue ;;
46
+ esac
47
+ # User-declared exemptions.
48
+ if [ -n "$exempt_pattern" ] && echo "$exempt_pattern" | grep -qxF "$base"; then
49
+ continue
50
+ fi
51
+ if [ ! -f "$reference_dir/$base" ]; then
52
+ echo "✗ Missing reference body for eager rule: $eager_file" >&2
53
+ echo " Expected: $reference_dir/$base" >&2
54
+ failed=1
55
+ fi
56
+ done < <(find "$eager_dir" -maxdepth 1 -type f -name '*.md' | sort)
57
+
58
+ # Every reference/X.md must have an eager/X.md pair (catch orphans on the
59
+ # other side: a reference body with no breadcrumb pointing to it is dead).
60
+ if [ -d "$reference_dir" ]; then
61
+ while IFS= read -r ref_file; do
62
+ local base
63
+ base="$(basename "$ref_file")"
64
+ if [ -n "$exempt_pattern" ] && echo "$exempt_pattern" | grep -qxF "$base"; then
65
+ continue
66
+ fi
67
+ if [ ! -f "$eager_dir/$base" ]; then
68
+ echo "✗ Orphaned reference body (no eager head): $ref_file" >&2
69
+ echo " Expected: $eager_dir/$base" >&2
70
+ failed=1
71
+ fi
72
+ done < <(find "$reference_dir" -maxdepth 1 -type f -name '*.md' | sort)
73
+ fi
74
+ }
75
+
76
+ # Check every plugins/*/rules and plugins/src/*/rules directory.
77
+ while IFS= read -r rules_dir; do
78
+ check_plugin "$rules_dir"
79
+ done < <(find "$ROOT_DIR/plugins" -type d -name rules | sort)
80
+
81
+ if [ "$failed" -ne 0 ]; then
82
+ echo "" >&2
83
+ echo " Every rules/eager/X.md must have a paired rules/reference/X.md" >&2
84
+ echo " (and vice versa) so the eager head's breadcrumb to the full" >&2
85
+ echo " reference body resolves. To exempt a file, either name it" >&2
86
+ echo " 00-*.md (bootstrap convention) or list its basename in" >&2
87
+ echo " <plugin>/rules/.pair-exempt (one per line)." >&2
88
+ exit 1
89
+ fi
90
+
91
+ echo "✓ Every eager rule has its paired reference body (and vice versa)."