@onlooker-community/ecosystem 0.34.0 → 0.43.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 (112) hide show
  1. package/.claude/skills/writing-tests/SKILL.md +27 -0
  2. package/.claude-plugin/plugin.json +1 -1
  3. package/.github/workflows/release.yml +14 -14
  4. package/.release-please-manifest.json +7 -7
  5. package/AGENTS.md +116 -0
  6. package/CHANGELOG.md +175 -0
  7. package/CLAUDE.md +5 -0
  8. package/docs/lesson-promotion-pipeline.md +6 -6
  9. package/docs/superpowers/plans/2026-08-10-lesson-confirmation.md +1273 -0
  10. package/docs/superpowers/plans/2026-08-11-lesson-judging.md +1232 -0
  11. package/docs/superpowers/plans/2026-08-11-lesson-unconfirm.md +458 -0
  12. package/docs/superpowers/plans/2026-08-12-author-key.md +567 -0
  13. package/docs/superpowers/plans/2026-08-13-approved-pool.md +747 -0
  14. package/docs/superpowers/plans/2026-08-13-librarian-cluster.md +392 -0
  15. package/docs/superpowers/plans/2026-08-14-criterion-scores-consumers.md +1374 -0
  16. package/docs/superpowers/plans/2026-08-14-criterion-scores-schema.md +277 -0
  17. package/docs/superpowers/plans/2026-08-16-cartographer-undocumented-entity.md +741 -0
  18. package/docs/superpowers/specs/2026-08-10-lesson-confirmation-design.md +213 -0
  19. package/docs/superpowers/specs/2026-08-11-lesson-judging-design.md +267 -0
  20. package/docs/superpowers/specs/2026-08-11-lesson-unconfirm-design.md +152 -0
  21. package/docs/superpowers/specs/2026-08-12-author-key-design.md +317 -0
  22. package/docs/superpowers/specs/2026-08-13-approved-pool-design.md +232 -0
  23. package/docs/superpowers/specs/2026-08-14-criterion-scores-design.md +254 -0
  24. package/docs/superpowers/specs/2026-08-16-cartographer-undocumented-entity-design.md +249 -0
  25. package/package.json +2 -2
  26. package/plugins/assayer/.claude-plugin/plugin.json +1 -1
  27. package/plugins/assayer/CHANGELOG.md +7 -0
  28. package/plugins/assayer/scripts/lib/assayer-config.sh +6 -0
  29. package/plugins/cartographer/.claude-plugin/plugin.json +1 -1
  30. package/plugins/cartographer/CHANGELOG.md +54 -0
  31. package/plugins/cartographer/README.md +56 -1
  32. package/plugins/cartographer/config.json +7 -1
  33. package/plugins/cartographer/scripts/hooks/cartographer-post-write.sh +4 -4
  34. package/plugins/cartographer/scripts/hooks/cartographer-session-start.sh +7 -4
  35. package/plugins/cartographer/scripts/lib/cartographer-collect.sh +8 -1
  36. package/plugins/cartographer/scripts/lib/cartographer-config.sh +26 -0
  37. package/plugins/cartographer/scripts/lib/cartographer-events.sh +90 -0
  38. package/plugins/cartographer/scripts/lib/cartographer-filter.sh +105 -0
  39. package/plugins/cartographer/scripts/lib/cartographer-omission.sh +130 -0
  40. package/plugins/cartographer/scripts/lib/cartographer-resolve.sh +132 -0
  41. package/plugins/cartographer/scripts/run-audit.sh +136 -53
  42. package/plugins/cartographer/skills/cartographer/SKILL.md +33 -9
  43. package/plugins/curator/.claude-plugin/plugin.json +1 -1
  44. package/plugins/curator/CHANGELOG.md +7 -0
  45. package/plugins/curator/scripts/lib/curator-emit.sh +2 -1
  46. package/plugins/historian/.claude-plugin/plugin.json +1 -1
  47. package/plugins/historian/CHANGELOG.md +7 -0
  48. package/plugins/historian/scripts/lib/historian-emit.sh +2 -1
  49. package/plugins/librarian/.claude-plugin/plugin.json +1 -1
  50. package/plugins/librarian/CHANGELOG.md +71 -0
  51. package/plugins/librarian/config.json +30 -1
  52. package/plugins/librarian/docs/adr/002-agent-definitions-are-shared-assets.md +82 -0
  53. package/plugins/librarian/scripts/hooks/librarian-session-end.sh +28 -0
  54. package/plugins/librarian/scripts/hooks/librarian-session-start.sh +42 -12
  55. package/plugins/librarian/scripts/lib/librarian-author-key.sh +279 -0
  56. package/plugins/librarian/scripts/lib/librarian-cli.sh +346 -2
  57. package/plugins/librarian/scripts/lib/librarian-emit.sh +2 -1
  58. package/plugins/librarian/scripts/lib/librarian-lesson-judge.sh +349 -0
  59. package/plugins/librarian/scripts/lib/librarian-lesson-promote.sh +225 -0
  60. package/plugins/librarian/scripts/lib/librarian-lesson-review.sh +312 -0
  61. package/plugins/librarian/scripts/lib/librarian-lesson-rubric.sh +56 -0
  62. package/plugins/librarian/scripts/lib/librarian-lesson-storage.sh +82 -13
  63. package/plugins/librarian/scripts/lib/librarian-lesson-transform.sh +6 -1
  64. package/plugins/librarian/scripts/lib/librarian-lesson-validate.sh +131 -62
  65. package/plugins/librarian/skills/librarian/SKILL.md +98 -1
  66. package/plugins/tribunal/.claude-plugin/plugin.json +1 -1
  67. package/plugins/tribunal/CHANGELOG.md +63 -0
  68. package/plugins/tribunal/agents/tribunal-judge-adversarial.md +34 -0
  69. package/plugins/tribunal/agents/tribunal-judge-security.md +33 -0
  70. package/plugins/tribunal/agents/tribunal-judge-standard.md +12 -0
  71. package/plugins/tribunal/config.json +1 -0
  72. package/plugins/tribunal/scripts/lib/tribunal-aggregate.sh +154 -9
  73. package/plugins/tribunal/scripts/lib/tribunal-gate.sh +195 -16
  74. package/plugins/tribunal/skills/tribunal/SKILL.md +5 -3
  75. package/scripts/lib/prompt-rules.sh +6 -1
  76. package/test/bats/archivist-inject.bats +1 -1
  77. package/test/bats/assayer-extract.bats +2 -2
  78. package/test/bats/bursar-session-start.bats +3 -3
  79. package/test/bats/cartographer-config.bats +43 -0
  80. package/test/bats/cartographer-events.bats +267 -0
  81. package/test/bats/cartographer-filter.bats +169 -0
  82. package/test/bats/cartographer-lock.bats +3 -3
  83. package/test/bats/cartographer-omission.bats +202 -0
  84. package/test/bats/cartographer-resolve.bats +287 -0
  85. package/test/bats/cartographer-run-audit.bats +325 -0
  86. package/test/bats/compass-sanitizer.bats +11 -11
  87. package/test/bats/compass-transcript.bats +2 -2
  88. package/test/bats/config.bats +15 -15
  89. package/test/bats/curator-session-start.bats +10 -3
  90. package/test/bats/emit-payload-default.bats +52 -0
  91. package/test/bats/governor-ledger.bats +1 -1
  92. package/test/bats/historian-prompt-submit.bats +1 -1
  93. package/test/bats/inspector-post-write-hook.bats +4 -4
  94. package/test/bats/librarian-author-key.bats +477 -0
  95. package/test/bats/librarian-cli.bats +16 -16
  96. package/test/bats/librarian-lesson-judge.bats +884 -0
  97. package/test/bats/librarian-lesson-promote.bats +552 -0
  98. package/test/bats/librarian-lesson-review.bats +900 -0
  99. package/test/bats/librarian-lesson-transform.bats +17 -3
  100. package/test/bats/librarian-session-end.bats +161 -0
  101. package/test/bats/librarian-session-start.bats +36 -2
  102. package/test/bats/lineage-config.bats +1 -1
  103. package/test/bats/lineage-redact.bats +5 -5
  104. package/test/bats/session-tracker.bats +4 -4
  105. package/test/bats/tribunal-aggregate.bats +354 -1
  106. package/test/bats/tribunal-gate.bats +631 -0
  107. package/test/bats/tribunal-judge-agents.bats +119 -0
  108. package/test/bats/tribunal-jury.bats +1 -1
  109. package/test/bats/turn-tracker.bats +1 -1
  110. package/test/bats/warden-sanitizer.bats +3 -3
  111. package/test/bats/worktree-tracker.bats +2 -2
  112. package/test/node/lesson-validate-agreement.test.mjs +35 -6
@@ -160,6 +160,33 @@ _seed_artifact() {
160
160
  }
161
161
  ```
162
162
 
163
+ ## Gate every assertion: non-final `[[ ]]` needs `|| return 1`
164
+
165
+ `bats` resolves `#!/usr/bin/env bash`, which on macOS is the system bash 3.2.
166
+ Under 3.2 a failing **non-final** `[[ ]]` does **not** fail the test body —
167
+ execution continues and the test reports `ok`. Single-bracket `[ ]`, failing
168
+ commands, and failing command substitutions all gate correctly even there; the
169
+ defect is specific to `[[ ]]`. Under bash 5.x (what CI runs) it gates properly,
170
+ so a broken assertion passes locally and only CI would catch it.
171
+
172
+ Only the **last** assertion in a test body is safe, because a body's exit
173
+ status is its last command. Any `[[ ]]` before that needs explicit gating:
174
+
175
+ ```bash
176
+ @test "example" {
177
+ [[ "$output" == *"expected"* ]] || return 1 # non-final — must gate
178
+ [ "$status" -eq 0 ] # final — gates on its own
179
+ }
180
+ ```
181
+
182
+ Do **not** "fix" this by swapping to `[ ]`. Most of these assertions rely on
183
+ `[[ ]]`-only behavior — `==` glob patterns, `=~` regex, internal `&&`/`||` —
184
+ and a blanket swap silently changes what they test.
185
+
186
+ When you add an assertion, break it on purpose once and confirm the test fails.
187
+ A test that passes whether or not the code is correct is worse than no test,
188
+ because it reports coverage that does not exist.
189
+
163
190
  ## Anti-patterns
164
191
 
165
192
  Don't hand-roll these — each has bitten the suite before:
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ecosystem",
3
- "version": "0.34.0",
3
+ "version": "0.43.0",
4
4
  "description": "Observability substrate for Claude Code. Provides the shared $ONLOOKER_DIR storage root (default $HOME/.onlooker), canonical schema-validated event emission, session and tool tracking hooks, and prompt rules. Required by all other Onlooker plugins.",
5
5
  "author": {
6
6
  "name": "Onlooker Community",
@@ -7,26 +7,16 @@ on:
7
7
  permissions:
8
8
  contents: write
9
9
  pull-requests: write
10
+ id-token: write
10
11
 
11
12
  jobs:
12
13
  release-please:
13
14
  runs-on: ubuntu-latest
14
15
  steps:
15
- # Force release-please's intermediate PR-branch commits to be authored
16
- # by github-actions[bot] instead of inheriting whatever identity the
17
- # PAT owner happens to have configured on their local machine. The
18
- # squash-merge of the release PR already attributes the merge to the
19
- # PAT owner correctly, but the intermediate commits would otherwise
20
- # leak the maintainer's hostname-shaped author email.
21
- - name: Configure bot identity
22
- run: |
23
- git config --global user.name 'github-actions[bot]'
24
- git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com'
25
-
26
16
  - uses: googleapis/release-please-action@v4
27
17
  id: release
28
18
  with:
29
- token: ${{ secrets.RELEASE_PLEASE_TOKEN }}
19
+ token: ${{ secrets.GITHUB_TOKEN }}
30
20
 
31
21
  # Only publish to npm when the ecosystem (root) package was released.
32
22
  # Archivist (and future sibling plugins) are distributed via the Claude
@@ -49,7 +39,17 @@ jobs:
49
39
  - run: npm ci
50
40
  if: ${{ contains(fromJSON(steps.release.outputs.paths_released || '[]'), '.') }}
51
41
 
52
- - run: npm publish
42
+ # --provenance is what makes the id-token: write permission above do
43
+ # anything. Without it npm never requests an OIDC token and the publish
44
+ # authenticates with NPM_TOKEN alone — a classic automation token, which
45
+ # this package's 2FA policy rejects with a 403. The permission has been
46
+ # granted since #175 and inert ever since, so every release from 0.35.0
47
+ # on tagged cleanly and never reached npm.
48
+ #
49
+ # --access public is a no-op on an already-public package; it is here for
50
+ # parity with onlooker-community/schema's publish-npm.yml, the one
51
+ # configuration in this org that publishes successfully.
52
+ - run: npm publish --provenance --access public
53
53
  if: ${{ contains(fromJSON(steps.release.outputs.paths_released || '[]'), '.') }}
54
54
  env:
55
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
55
+ NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,18 +1,18 @@
1
1
  {
2
- ".": "0.34.0",
2
+ ".": "0.43.0",
3
3
  "plugins/archivist": "0.3.1",
4
- "plugins/tribunal": "1.1.2",
4
+ "plugins/tribunal": "1.2.7",
5
5
  "plugins/echo": "0.3.1",
6
- "plugins/cartographer": "0.3.1",
6
+ "plugins/cartographer": "0.6.0",
7
7
  "plugins/governor": "0.3.2",
8
8
  "plugins/compass": "0.4.1",
9
9
  "plugins/scribe": "0.4.2",
10
10
  "plugins/counsel": "0.5.1",
11
11
  "plugins/warden": "0.3.1",
12
- "plugins/librarian": "0.7.0",
13
- "plugins/curator": "0.2.2",
14
- "plugins/historian": "0.3.2",
15
- "plugins/assayer": "1.1.2",
12
+ "plugins/librarian": "0.13.2",
13
+ "plugins/curator": "0.2.3",
14
+ "plugins/historian": "0.3.3",
15
+ "plugins/assayer": "1.1.3",
16
16
  "plugins/bursar": "0.3.0",
17
17
  "plugins/lineage": "0.2.2",
18
18
  "plugins/inspector": "0.3.2"
package/AGENTS.md CHANGED
@@ -47,6 +47,122 @@ cp -rf source dest # NOT: cp -r source dest
47
47
  - `apt-get` - use `-y` flag
48
48
  - `brew` - use `HOMEBREW_NO_AUTO_UPDATE=1` env var
49
49
 
50
+ <!-- The sections below are mirrored from CLAUDE.md. The two files are
51
+ independent — not symlinked, not sharing an inode — so an edit to the
52
+ repository's conventions must land in both or agents get different
53
+ instructions depending on which file their harness reads. Claude Code
54
+ reads CLAUDE.md; Codex and several other tools read this one. -->
55
+
56
+ ## Repository layout
57
+
58
+ ```
59
+ ecosystem/ ← substrate plugin (always-on observability)
60
+ hooks/ ← session, tool, and prompt hooks
61
+ scripts/lib/ ← shared bash helpers and the canonical event emitter
62
+ skills/ ← user-invocable slash commands
63
+ config.json ← ecosystem defaults
64
+
65
+ plugins/
66
+ archivist/ ← session memory across context truncation
67
+ bursar/ ← multi-session, per-project budget rollup (governor's cross-session view)
68
+ cartographer/ ← instruction-file auditor (CLAUDE.md, AGENTS.md, rules/)
69
+ compass/ ← pre-write alignment gate (design phase)
70
+ echo/ ← prompt-change regression detection
71
+ governor/ ← resource governance and budget enforcement
72
+ inspector/ ← per-edit lint and typecheck gate
73
+ lineage/ ← per-change provenance ("why does this line exist?")
74
+ tribunal/ ← multi-agent quality gate (Actor → Jury → Meta-Judge → Gate)
75
+
76
+ docs/
77
+ architecture.md ← how plugins compose and share the event bus
78
+ adr/ ← ecosystem-level architectural decisions
79
+
80
+ scripts/lib/onlooker-event.mjs ← canonical event builder; all plugins route through this
81
+ ~/.onlooker/ ← shared runtime storage (logs, plugin artifacts)
82
+ ```
83
+
84
+ ## Plugin map
85
+
86
+ | Plugin | Hook surface | When it fires |
87
+ |--------|-------------|---------------|
88
+ | ecosystem | SessionStart/End, PreToolUse, PostToolUse, PostToolUseFailure, UserPromptSubmit, UserPromptExpansion, PreCompact, PostCompact, TaskCreated, TaskCompleted, WorktreeCreate, WorktreeRemove | Always — substrate |
89
+ | archivist | PreCompact, SessionStart | Extracts decisions/dead-ends on compaction; reinjects at next SessionStart |
90
+ | cartographer | SessionStart, PostToolUse (Write, Edit, MultiEdit) | Audits instruction files on session start and after instruction-file writes |
91
+ | compass | PreToolUse (Write, Edit, MultiEdit, Bash) | Before any write — alignment check |
92
+ | echo | Stop | Regression-tests prompt changes after each agent stop |
93
+ | governor | SessionStart, PreToolUse (Task), PostToolUse (Task), Stop | Budget gates on subagent spawns; tracks spend per session |
94
+ | tribunal | Stop + skill invocation | Post-task quality gate; also invokable via `/tribunal` |
95
+ | warden | PostToolUse (WebFetch, Read), PreToolUse (Write, Edit, MultiEdit, Bash), SessionStart + skill invocation | Scans ingested content for injection; closes a content gate that blocks write-class tools until cleared via `/warden` |
96
+ | assayer | Stop | Verifies the agent's final-message claims against actual command results in the transcript; advisory |
97
+ | bursar | SessionStart, SessionEnd | Rolls each session's spend into a per-project ledger on SessionEnd; surfaces "this project burned $X this week" at SessionStart. Governor is per-session; bursar is the cross-session rollup |
98
+ | lineage | PostToolUse (Edit, Write, MultiEdit) + skill invocation | Records per-change provenance (session_id/turn + redacted, size-capped snippets) into a per-project ledger; `/lineage <file>:<line>` answers "why does this line exist?" by joining records to historian transcripts to recover prompt context |
99
+ | inspector | PostToolUse (Write, Edit, MultiEdit) | Per-edit verification: runs the project's configured lint + typecheck commands on just the touched file and emits `inspector.check.*` / `inspector.run.completed`. Surfaces issues to the agent for the next turn. Cheaper than the planned proctor (which runs the full project verify at Stop); complements assayer (which catches claims the agent makes without running anything) |
100
+ | librarian | SessionEnd, SessionStart + skill invocation | Consolidation layer between archivist's per-session artifacts and the user's durable typed memory store. At SessionEnd, decides which decisions/dead-ends deserve to outlive the session, classifies them into user/feedback/project/reference, and queues them as proposals; at SessionStart, surfaces a one-line pointer to the queue. Propose-only (its ADR-001) — auto-promotion is opt-in. Also owns the lesson-promotion pipeline under `lessons/`, walked via `/librarian lessons` |
101
+ | historian | SessionEnd, UserPromptSubmit | Episodic memory. Chunks and sanitizes the transcript at SessionEnd into `$ONLOOKER_DIR/historian/<project-key>/sessions/`; on UserPromptSubmit, embeds the prompt and retrieves similar past chunks. Lineage joins these transcripts to recover the prompt context behind a change |
102
+ | counsel | SessionStart + skill invocation | Weekly synthesis across every plugin's event log. Produces a structured improvement brief and injects it at SessionStart when the last one is stale; `/counsel` on demand |
103
+ | curator | SessionStart | Maintenance for the typed auto-memory store. Runs four cheap heuristic checks (date_decayed, path_broken, broken_index, orphaned_memory) inside a wall-clock budget and surfaces findings as a one-line pointer. Never edits the memory store directly. The `/curator review` walkthrough and the LLM contradiction sweep are both deferred — see the plugin's README |
104
+ | scribe | SessionStart, UserPromptSubmit, Stop | Intent documentation from agent activity: captures why changes were made — problem context, decisions, tradeoffs — and distills them into readable artifacts at session end |
105
+
106
+ Plugins communicate by emitting events to the JSONL log — they do not call each other directly. All plugins depend on the ecosystem substrate; no plugin depends on another plugin directly.
107
+
108
+ ## Compass plugin (design phase)
109
+
110
+ Compass is the pre-write alignment gate. It has no implementation yet. Design lives in `plugins/compass/docs/design.md`.
111
+
112
+ **What it does:** Fires on `PreToolUse` for write-class tools. Samples N=5 parallel Haiku evaluators to score intent clarity. Blocks when `confidence < 0.65 OR stddev > 0.20` and surfaces a clarification prompt.
113
+
114
+ **Critical architectural decision (ADR-001):** The evaluator must see the **prior assistant turn** alongside the current context — not the current context alone. Evaluating a reply in isolation produces a systematic false-positive class: a user answering an agent's enumerated question ("the internal one") looks ambiguous without the question that prompted it.
115
+
116
+ The pipeline is:
117
+
118
+ ```
119
+ Trigger Gate → Transcript Reader → Symbolic Skip Layer → Sanitizer → N=5 Evaluators → Gate
120
+ ```
121
+
122
+ - **Transcript reader** resolves `prior_assistant_turn` from `transcript_path` in the hook JSON payload (same field tribunal-stop-gate.sh reads). Reads one turn back from that file (already committed before `PreToolUse` fires — no timing-skew risk). If `transcript_path` is absent or unreadable, proceeds with an empty prior turn.
123
+ - **Symbolic skip layer** short-circuits to `confident` when the prior turn is an enumerated question and the current context is an option reference, without an LLM call. Controlled by `skip_patterns.reply_to_question.enabled` (default `true`).
124
+ - **Evaluator prompt** uses a structured pair: `<prior_assistant_turn>` and `<context_excerpt>` as separate XML-delimited slots. The convergence question is: *"Given the prior assistant turn as context, would two independent readers converge on the same interpretation of this write?"*
125
+
126
+ See `plugins/compass/docs/adr/001-evaluate-prompts-in-context.md` for the full decision record.
127
+
128
+ ## Adding a new plugin
129
+
130
+ 1. Create `plugins/<name>/` with `.claude-plugin/plugin.json`, `config.json`, `hooks/hooks.json`.
131
+ 2. Use `scripts/lib/onlooker-event.mjs` for all event emission — never write directly to the JSONL log.
132
+ 3. Store runtime artifacts under `${ONLOOKER_DIR:-$HOME/.onlooker}/<name>/<project-key>/`. Always use `$ONLOOKER_DIR` — never hardcode `~/.onlooker` — so the test suite's isolated temp home is respected.
133
+ 4. Derive the project key via `tribunal_project_key` (or equivalent) — first 12 hex chars of SHA256(`remote:<origin-url>`), falling back to SHA256(`root:<repo-root>`) for repos without a remote. See `plugins/tribunal/scripts/lib/tribunal-project-key.sh`.
134
+ 5. Register event types in `@onlooker-community/schema` before emitting them. The runtime emitter is dependency-free and **fails open**: it validates against the schema package only when that package is resolvable (dev, CI, tests) and emits unconditionally otherwise, because installed marketplace plugins ship no `node_modules`. Schema drift is caught in CI against the published schemas at `schema.onlooker.dev`. See [ADR-005](docs/adr/005-runtime-emitter-fails-open.md).
135
+ 6. Fail-soft when `~/.onlooker/` is absent — plugins must not block a session they were not invited to.
136
+
137
+ ## Development
138
+
139
+ ```bash
140
+ mise install # installs all tools declared in mise.toml
141
+ npm ci
142
+ npm test # bats + schema validation
143
+ npm run test:ci # shellcheck + bats + schema + lint
144
+ ```
145
+
146
+ Tests use an isolated temp home; nothing writes to your real `~/.onlooker/`.
147
+
148
+ ## Git workflow
149
+
150
+ **Always open a PR — never push directly to `main`.** Even though bypass rights allow direct pushes, this repo uses release-please for automated changelogs and versioning, so every change must travel through a PR to be picked up correctly. CI also runs on PRs before merge, catching failures before they land.
151
+
152
+ Workflow:
153
+ 1. Create a feature branch: `git switch -c <type>/<short-description>`
154
+ 2. Commit using `/commit`
155
+ 3. Push the branch and open a PR using `/git-workflow:pr`
156
+ 4. Wait for CI to pass before merging
157
+
158
+ ## Conventions
159
+
160
+ - All hooks are bash scripts. No Python, no Node entry points in hook scripts (they may shell out to `node` for event emission or heavy lifting).
161
+ - Hook scripts source shared helpers from `scripts/lib/` (or the plugin's own `scripts/lib/`).
162
+ - Event types follow `<plugin>.<noun>.<verb>` — e.g. `compass.check.skipped`, `tribunal.gate.blocked`.
163
+ - ULIDs everywhere for IDs (not UUIDs). Each plugin ships its own `*_ulid` helper (e.g. `archivist-ulid.sh`, `tribunal-ulid.sh`); there is no shared ecosystem helper. Copy `plugins/tribunal/scripts/lib/tribunal-ulid.sh` as a starting point and rename the function prefix.
164
+ - Config defaults live in `config.json`. User overrides go in `~/.claude/settings.json` (global) or `.claude/settings.json` (per-project) under the plugin's namespace key (e.g. `"compass"`, `"tribunal"`). See ADR-004.
165
+
50
166
  <!-- BEGIN BEADS INTEGRATION v:1 profile:minimal hash:970c3bf2 -->
51
167
  ## Beads Issue Tracker
52
168
 
package/CHANGELOG.md CHANGED
@@ -1,5 +1,180 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.43.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.42.2...ecosystem-v0.43.0) (2026-08-19)
4
+
5
+
6
+ ### Features
7
+
8
+ * **cartographer:** announce a finding when its drift is gone :wave: ([#186](https://github.com/onlooker-community/ecosystem/issues/186)) ([f2b57f6](https://github.com/onlooker-community/ecosystem/commit/f2b57f67b3e09f7ec624bce0bb4a306c4e20df8b))
9
+
10
+ ## [0.42.2](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.42.1...ecosystem-v0.42.2) (2026-08-19)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **release:** publish with provenance so npm stops refusing us :unlock: ([#184](https://github.com/onlooker-community/ecosystem/issues/184)) ([0921118](https://github.com/onlooker-community/ecosystem/commit/0921118401a4c165ba07471a5d573dbe21a35119))
16
+
17
+ ## [0.42.1](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.42.0...ecosystem-v0.42.1) (2026-08-19)
18
+
19
+
20
+ ### Bug Fixes
21
+
22
+ * **cartographer:** refuse a typeless finding out loud :loudspeaker: ([#182](https://github.com/onlooker-community/ecosystem/issues/182)) ([35ee0af](https://github.com/onlooker-community/ecosystem/commit/35ee0af055fd360a70a77d6ef036bbeb91dcc945))
23
+
24
+ ## [0.42.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.41.3...ecosystem-v0.42.0) (2026-08-18)
25
+
26
+
27
+ ### Features
28
+
29
+ * **cartographer:** narrow an audit by finding type or subtree :mag: ([#177](https://github.com/onlooker-community/ecosystem/issues/177)) ([94764df](https://github.com/onlooker-community/ecosystem/commit/94764dfc8386521a06c8234bc506cb51a667588d))
30
+
31
+
32
+ ### Bug Fixes
33
+
34
+ * **librarian:** put budget skips on the bus at last :satellite: ([#180](https://github.com/onlooker-community/ecosystem/issues/180)) ([bc91749](https://github.com/onlooker-community/ecosystem/commit/bc917495dab053cba825ea28ccdd1993fdacb3e9))
35
+ * **librarian:** stop stage 5 from holding a session open :hourglass: ([#178](https://github.com/onlooker-community/ecosystem/issues/178)) ([4f12a1e](https://github.com/onlooker-community/ecosystem/commit/4f12a1ee25300e0dc372542814e0922df5dbd335))
36
+
37
+ ## [0.41.3](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.41.2...ecosystem-v0.41.3) (2026-08-17)
38
+
39
+
40
+ ### Bug Fixes
41
+
42
+ * **cartographer:** make the audit read the settings you gave it :gear: ([#174](https://github.com/onlooker-community/ecosystem/issues/174)) ([dc57731](https://github.com/onlooker-community/ecosystem/commit/dc5773165fe561f77e87101ed1fbe6e13bb34c34))
43
+ * **release:** drop git config --global and switch to GITHUB_TOKEN with id-token:write ([#175](https://github.com/onlooker-community/ecosystem/issues/175)) ([b70668b](https://github.com/onlooker-community/ecosystem/commit/b70668b90cff7d33e012363ede673b0c3e9da29f))
44
+
45
+ ## [0.41.2](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.41.1...ecosystem-v0.41.2) (2026-08-17)
46
+
47
+
48
+ ### Bug Fixes
49
+
50
+ * **cartographer:** let a finding you fixed finally go away :wastebasket: ([#172](https://github.com/onlooker-community/ecosystem/issues/172)) ([c8fdcf4](https://github.com/onlooker-community/ecosystem/commit/c8fdcf40b711b68ee5d90e2c4b6408ea38926900))
51
+
52
+ ## [0.41.1](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.41.0...ecosystem-v0.41.1) (2026-08-17)
53
+
54
+
55
+ ### Bug Fixes
56
+
57
+ * **cartographer:** put its events on the bus for the first time :mega: ([#170](https://github.com/onlooker-community/ecosystem/issues/170)) ([91be8d2](https://github.com/onlooker-community/ecosystem/commit/91be8d2c9f171006db12842f3e582d001f9d4e27))
58
+
59
+ ## [0.41.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.40.8...ecosystem-v0.41.0) (2026-08-16)
60
+
61
+
62
+ ### Features
63
+
64
+ * **cartographer:** detect what no instruction file mentions :eyes: ([#168](https://github.com/onlooker-community/ecosystem/issues/168)) ([31efb7b](https://github.com/onlooker-community/ecosystem/commit/31efb7b035665d5a49a37c1e1af21f519850f7bd))
65
+
66
+ ## [0.40.8](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.40.7...ecosystem-v0.40.8) (2026-08-16)
67
+
68
+
69
+ ### Bug Fixes
70
+
71
+ * **tribunal:** let every blocking arm name the floor it tripped over :label: ([#166](https://github.com/onlooker-community/ecosystem/issues/166)) ([1819b5f](https://github.com/onlooker-community/ecosystem/commit/1819b5f7ad0348584bcb0e72e28c9af153ba3a4d))
72
+
73
+ ## [0.40.7](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.40.6...ecosystem-v0.40.7) (2026-08-16)
74
+
75
+
76
+ ### Bug Fixes
77
+
78
+ * **tribunal:** stop a low criterion from hiding why the panel failed :arrows_counterclockwise: ([#164](https://github.com/onlooker-community/ecosystem/issues/164)) ([a3ec128](https://github.com/onlooker-community/ecosystem/commit/a3ec128f1e2e723e02396580b9ffbcff26f0787f))
79
+
80
+ ## [0.40.6](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.40.5...ecosystem-v0.40.6) (2026-08-16)
81
+
82
+
83
+ ### Bug Fixes
84
+
85
+ * **tribunal:** a floor you cannot read is a floor you cannot clear :lock: ([#162](https://github.com/onlooker-community/ecosystem/issues/162)) ([4ff2ec0](https://github.com/onlooker-community/ecosystem/commit/4ff2ec0f772af51ad4b5ea631ae2d3c68d229499))
86
+
87
+ ## [0.40.5](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.40.4...ecosystem-v0.40.5) (2026-08-16)
88
+
89
+
90
+ ### Bug Fixes
91
+
92
+ * **tribunal:** refuse a score that is not on the scale it claims :straight_ruler: ([#160](https://github.com/onlooker-community/ecosystem/issues/160)) ([bab2855](https://github.com/onlooker-community/ecosystem/commit/bab28558a68402c1dd67623f469467fd99302ba6))
93
+
94
+ ## [0.40.4](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.40.3...ecosystem-v0.40.4) (2026-08-16)
95
+
96
+
97
+ ### Bug Fixes
98
+
99
+ * **tribunal:** stop a verdict nobody scored from voting to approve :no_entry: ([#158](https://github.com/onlooker-community/ecosystem/issues/158)) ([1d6c2dc](https://github.com/onlooker-community/ecosystem/commit/1d6c2dc9c8f5833891732dc7e6637c496ba81f6f))
100
+
101
+ ## [0.40.3](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.40.2...ecosystem-v0.40.3) (2026-08-15)
102
+
103
+
104
+ ### Bug Fixes
105
+
106
+ * **librarian:** make proposals the sole dedup source, and say so :broom: ([#156](https://github.com/onlooker-community/ecosystem/issues/156)) ([729d9ea](https://github.com/onlooker-community/ecosystem/commit/729d9ea3e328c2734712cfc5adf556c6798334aa))
107
+
108
+ ## [0.40.2](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.40.1...ecosystem-v0.40.2) (2026-08-15)
109
+
110
+
111
+ ### Bug Fixes
112
+
113
+ * **tribunal:** drop scoreless verdicts instead of averaging them in :bug: ([#154](https://github.com/onlooker-community/ecosystem/issues/154)) ([f546757](https://github.com/onlooker-community/ecosystem/commit/f5467574f08094b0369f0bd699983cb41ded2cc3))
114
+
115
+ ## [0.40.1](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.40.0...ecosystem-v0.40.1) (2026-08-15)
116
+
117
+
118
+ ### Bug Fixes
119
+
120
+ * **tribunal:** close two ways a criterion floor could still be escaped :relieved: ([#152](https://github.com/onlooker-community/ecosystem/issues/152)) ([5b2ddee](https://github.com/onlooker-community/ecosystem/commit/5b2ddee8a787ba0f3e8656a6522b12f348f74859))
121
+
122
+ ## [0.40.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.39.1...ecosystem-v0.40.0) (2026-08-15)
123
+
124
+
125
+ ### Features
126
+
127
+ * **tribunal,librarian:** make rubric weights and min_pass floors real :straight_ruler: ([#150](https://github.com/onlooker-community/ecosystem/issues/150)) ([f8f8e28](https://github.com/onlooker-community/ecosystem/commit/f8f8e28b60f6d13d5a2a54e26ca284137b77f99a))
128
+
129
+ ## [0.39.1](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.39.0...ecosystem-v0.39.1) (2026-08-14)
130
+
131
+
132
+ ### Bug Fixes
133
+
134
+ * **librarian:** close four follow-up defects from the promotion epic :broom: ([#148](https://github.com/onlooker-community/ecosystem/issues/148)) ([895df74](https://github.com/onlooker-community/ecosystem/commit/895df7430fa8ba75976d38964d061c21bff785d3))
135
+
136
+ ## [0.39.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.38.0...ecosystem-v0.39.0) (2026-08-13)
137
+
138
+
139
+ ### Features
140
+
141
+ * **librarian:** land judged lessons in the approved pool :package: ([#146](https://github.com/onlooker-community/ecosystem/issues/146)) ([f7adc72](https://github.com/onlooker-community/ecosystem/commit/f7adc7263a985d4cb7695b46d6f9dbab77dce587))
142
+
143
+ ## [0.38.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.37.0...ecosystem-v0.38.0) (2026-08-13)
144
+
145
+
146
+ ### Features
147
+
148
+ * **librarian:** derive an author identity that cannot be linked across scopes :closed_lock_with_key: ([#144](https://github.com/onlooker-community/ecosystem/issues/144)) ([29b3042](https://github.com/onlooker-community/ecosystem/commit/29b3042ef6cd6e7582206cfea6fcf37ebe661021))
149
+
150
+ ## [0.37.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.36.0...ecosystem-v0.37.0) (2026-08-12)
151
+
152
+
153
+ ### Features
154
+
155
+ * **librarian:** judge lessons before they leave the machine :balance_scale: ([#142](https://github.com/onlooker-community/ecosystem/issues/142)) ([a877527](https://github.com/onlooker-community/ecosystem/commit/a87752714961613b6b2bb768239c666f78d950f8))
156
+
157
+ ## [0.36.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.35.0...ecosystem-v0.36.0) (2026-08-11)
158
+
159
+
160
+ ### Features
161
+
162
+ * **librarian:** let a human take back a lesson confirmation :leftwards_arrow_with_hook: ([#139](https://github.com/onlooker-community/ecosystem/issues/139)) ([a4c4ac8](https://github.com/onlooker-community/ecosystem/commit/a4c4ac8ed5b79f5596f4e22abd1d23a8b0d3e834))
163
+
164
+ ## [0.35.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.34.1...ecosystem-v0.35.0) (2026-08-11)
165
+
166
+
167
+ ### Features
168
+
169
+ * **librarian:** let a human decide what leaves the machine :raised_hand: ([#137](https://github.com/onlooker-community/ecosystem/issues/137)) ([16d7673](https://github.com/onlooker-community/ecosystem/commit/16d76734833aee9c8818f84c1c1f704be4cdfc33))
170
+
171
+ ## [0.34.1](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.34.0...ecosystem-v0.34.1) (2026-08-10)
172
+
173
+
174
+ ### Bug Fixes
175
+
176
+ * make the local bats suite tell the truth :mag: ([#135](https://github.com/onlooker-community/ecosystem/issues/135)) ([f0763e0](https://github.com/onlooker-community/ecosystem/commit/f0763e09f3caf2d39c89f28befd12567af0af845))
177
+
3
178
  ## [0.34.0](https://github.com/onlooker-community/ecosystem/compare/ecosystem-v0.33.1...ecosystem-v0.34.0) (2026-08-09)
4
179
 
5
180
 
package/CLAUDE.md CHANGED
@@ -44,6 +44,11 @@ scripts/lib/onlooker-event.mjs ← canonical event builder; all plugins route t
44
44
  | bursar | SessionStart, SessionEnd | Rolls each session's spend into a per-project ledger on SessionEnd; surfaces "this project burned $X this week" at SessionStart. Governor is per-session; bursar is the cross-session rollup |
45
45
  | lineage | PostToolUse (Edit, Write, MultiEdit) + skill invocation | Records per-change provenance (session_id/turn + redacted, size-capped snippets) into a per-project ledger; `/lineage <file>:<line>` answers "why does this line exist?" by joining records to historian transcripts to recover prompt context |
46
46
  | inspector | PostToolUse (Write, Edit, MultiEdit) | Per-edit verification: runs the project's configured lint + typecheck commands on just the touched file and emits `inspector.check.*` / `inspector.run.completed`. Surfaces issues to the agent for the next turn. Cheaper than the planned proctor (which runs the full project verify at Stop); complements assayer (which catches claims the agent makes without running anything) |
47
+ | librarian | SessionEnd, SessionStart + skill invocation | Consolidation layer between archivist's per-session artifacts and the user's durable typed memory store. At SessionEnd, decides which decisions/dead-ends deserve to outlive the session, classifies them into user/feedback/project/reference, and queues them as proposals; at SessionStart, surfaces a one-line pointer to the queue. Propose-only (its ADR-001) — auto-promotion is opt-in. Also owns the lesson-promotion pipeline under `lessons/`, walked via `/librarian lessons` |
48
+ | historian | SessionEnd, UserPromptSubmit | Episodic memory. Chunks and sanitizes the transcript at SessionEnd into `$ONLOOKER_DIR/historian/<project-key>/sessions/`; on UserPromptSubmit, embeds the prompt and retrieves similar past chunks. Lineage joins these transcripts to recover the prompt context behind a change |
49
+ | counsel | SessionStart + skill invocation | Weekly synthesis across every plugin's event log. Produces a structured improvement brief and injects it at SessionStart when the last one is stale; `/counsel` on demand |
50
+ | curator | SessionStart | Maintenance for the typed auto-memory store. Runs four cheap heuristic checks (date_decayed, path_broken, broken_index, orphaned_memory) inside a wall-clock budget and surfaces findings as a one-line pointer. Never edits the memory store directly. The `/curator review` walkthrough and the LLM contradiction sweep are both deferred — see the plugin's README |
51
+ | scribe | SessionStart, UserPromptSubmit, Stop | Intent documentation from agent activity: captures why changes were made — problem context, decisions, tradeoffs — and distills them into readable artifacts at session end |
47
52
 
48
53
  Plugins communicate by emitting events to the JSONL log — they do not call each other directly. All plugins depend on the ecosystem substrate; no plugin depends on another plugin directly.
49
54
 
@@ -175,9 +175,9 @@ From [CLAUDE.md](../CLAUDE.md) — these differ from the onlooker repo:
175
175
  - **Event names** follow `<plugin>.<noun>.<verb>`. Likely additions here:
176
176
  `librarian.lesson.proposed`, `librarian.lesson.approved`,
177
177
  `librarian.lesson.declined`, `tribunal.lesson.judged`.
178
- - **ULIDs, not UUIDs**, and each plugin ships its own helper. Librarian will need
179
- one for lesson ids if it does not have one — copy
180
- `plugins/tribunal/scripts/lib/tribunal-ulid.sh` and rename the prefix.
178
+ - **ULIDs, not UUIDs**, and each plugin ships its own helper. Librarian already
179
+ has one — `plugins/librarian/scripts/lib/librarian-ulid.sh`, exposing
180
+ `librarian_ulid`. Use it for lesson ids rather than adding a second generator.
181
181
  - **Config defaults** live in the plugin's `config.json`; user overrides go under
182
182
  the plugin's namespace key in settings. See ADR-004.
183
183
 
@@ -201,9 +201,9 @@ what still needs independent judging.
201
201
  - **Where the human confirmation surfaces.** Librarian already has a proposal
202
202
  queue and a SessionStart surfacer for memory promotions. Reuse it, or keep
203
203
  lesson proposals separate so the two kinds of confirmation are not confused?
204
- - **`author_key` derivation.** The contract pins the format — 32 hex,
205
- `HMAC(user_secret, scope)` but nothing derives it yet. Where does
206
- `user_secret` live, and how is it created on first use?
204
+ - **`author_key` derivation.** Resolved: `user_secret` lives at
205
+ `$ONLOOKER_DIR/author/user_secret`, created on first use, never
206
+ project-keyed. See `docs/superpowers/specs/2026-08-12-author-key-design.md`.
207
207
  - **Whether the transform self-validates** against the published JSON Schema
208
208
  before writing to the pool, or leaves all validation to ingest. Validating
209
209
  locally catches a bad transform earlier; it also means fetching and caching