@jeffober/thatch 0.1.26 → 0.1.27

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 (70) hide show
  1. package/README.md +7 -7
  2. package/artifacts/skills/common.md +1 -1
  3. package/artifacts/skills/thatch-change-walkthrough.md +2 -2
  4. package/artifacts/skills/thatch-code-archaeology.md +252 -0
  5. package/artifacts/skills/thatch-code-review.md +4 -4
  6. package/artifacts/skills/thatch-code-walkthrough.md +2 -2
  7. package/artifacts/skills/thatch-coding-workflow.md +79 -0
  8. package/artifacts/skills/{pr-description.md → thatch-pr-description.md} +1 -1
  9. package/artifacts/skills/thatch-review-context.md +9 -0
  10. package/artifacts/skills/thatch-review-followup.md +29 -1
  11. package/artifacts/skills/thatch-review-pedantic.md +16 -1
  12. package/artifacts/skills/thatch-review-response.md +365 -0
  13. package/artifacts/skills/thatch-review-synthesizer.md +92 -5
  14. package/artifacts/skills/{split-overlarge-pr.md → thatch-split-overlarge-pr.md} +1 -1
  15. package/artifacts/skills/{ticket-description.md → thatch-ticket-description.md} +3 -3
  16. package/bin/release +3 -3
  17. package/bin/thatch +8 -8
  18. package/docs/dev/README.md +1 -1
  19. package/docs/dev/skills.md +29 -9
  20. package/docs/plans/README.md +9 -6
  21. package/docs/plans/intuition-drives.md +147 -0
  22. package/docs/plans/nomenclater.md +89 -0
  23. package/docs/plans/prediction-consolidation.md +361 -0
  24. package/docs/qa/README.md +20 -3
  25. package/docs/user/README.md +19 -5
  26. package/package.json +1 -1
  27. package/src/db.ts +6 -6
  28. package/src/embeddings.ts +2 -2
  29. package/src/extract-queue.ts +4 -4
  30. package/src/extraction.ts +4 -4
  31. package/src/git.ts +1 -1
  32. package/src/hygiene.ts +1 -1
  33. package/src/index.ts +28 -28
  34. package/src/mcp.ts +5 -5
  35. package/src/prompts.ts +71 -68
  36. package/src/setup.ts +19 -19
  37. package/src/sideband.ts +3 -3
  38. package/src/skills.ts +104 -6
  39. package/src/tool-defs.ts +11 -11
  40. package/src/tools.ts +1 -1
  41. package/artifacts/skills/thatch-workflow-research.md +0 -91
  42. package/docs/in-progress/prediction-engine.md +0 -404
  43. package/docs/plans/001-memory-store.md +0 -106
  44. package/docs/plans/002-agent-driven-pipelines.md +0 -59
  45. package/docs/plans/003-memory-hygiene.md +0 -61
  46. package/docs/qa/use-cases/README.md +0 -51
  47. package/docs/qa/use-cases/UC-001-memory-roundtrip.md +0 -20
  48. package/docs/qa/use-cases/UC-002-dedup-cycle.md +0 -23
  49. package/docs/qa/use-cases/UC-003-extraction-nudge.md +0 -56
  50. package/docs/qa/use-cases/UC-004-cli-inspection.md +0 -22
  51. package/docs/qa/use-cases/UC-005-setup-install.md +0 -34
  52. package/docs/qa/use-cases/UC-006-cursor-hook-lifecycle.md +0 -32
  53. package/docs/qa/use-cases/UC-007-recall-nudge.md +0 -31
  54. package/docs/qa/use-cases/UC-008-hygiene-heartbeat.md +0 -26
  55. package/docs/qa/use-cases/UC-009-flush-tools-tiers.md +0 -33
  56. package/docs/qa/use-cases/UC-010-prime.md +0 -25
  57. package/docs/qa/use-cases/UC-011-write-time-similarity-warning.md +0 -24
  58. package/docs/qa/use-cases/UC-012-model-migration.md +0 -28
  59. package/docs/qa/use-cases/UC-013-compaction-context.md +0 -25
  60. package/docs/qa/use-cases/UC-014-skill-install-drift.md +0 -28
  61. package/docs/qa/use-cases/UC-015-env-override-matrix.md +0 -28
  62. package/docs/qa/use-cases/UC-016-concurrent-session-isolation.md +0 -37
  63. package/docs/qa/use-cases/UC-017-buffer-tool-vs-buffer-batch.md +0 -27
  64. package/docs/qa/use-cases/UC-018-mcp-startup-setup-detection.md +0 -38
  65. package/docs/qa/use-cases/UC-019-archived-memory-lifecycle.md +0 -36
  66. package/docs/qa/use-cases/UC-020-extraction-escalation.md +0 -52
  67. package/docs/qa/use-cases/UC-021-prediction-autofire.md +0 -21
  68. package/docs/qa/use-cases/UC-022-prediction-dedup.md +0 -19
  69. package/docs/qa/use-cases/UC-023-prediction-confidence-model.md +0 -23
  70. package/docs/qa/use-cases/UC-024-prediction-delete.md +0 -20
@@ -4,6 +4,13 @@ Thatch installs SKILL.md files that give the agent task-specific workflows. All
4
4
  skill content lives in `artifacts/skills/*.md` and is loaded by `src/skills.ts` and installed to a host-specific
5
5
  directory. See `mcp-parity.md` for which skills each host gets.
6
6
 
7
+ ## Naming convention
8
+
9
+ All plugin skills use the `thatch-` prefix. This brands them as part of the
10
+ thatch plugin and makes them easy to identify in the skills directory. The
11
+ `cleanupStaleSkills` function uses this prefix as its namespace: any
12
+ `thatch-*` directory not in the current install set is deleted on install.
13
+
7
14
  ## Skill file format
8
15
 
9
16
  Each skill is a single `SKILL.md` with YAML frontmatter:
@@ -21,9 +28,9 @@ description: Extract durable project facts ... Use when ...
21
28
  - `description` drives when the agent loads the skill (both opencode and
22
29
  Cursor auto-discover skills and use the description for relevance).
23
30
 
24
- ## The 21 skills
31
+ ## The 23 skills
25
32
 
26
- **Shared (20)** — installed everywhere; no sub-agents required:
33
+ **Shared (22)** — installed everywhere; no sub-agents required:
27
34
 
28
35
  | Skill | Role |
29
36
  |-------|------|
@@ -39,14 +46,16 @@ description: Extract durable project facts ... Use when ...
39
46
  | `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar against generic praise. |
40
47
  | `thatch-review-synthesizer` | Verify specialist findings against code, dedupe, classify, calibrate severity. Starts the final report with a workflow-change preface, then cross-references findings against prior review comments when a follow-up round register is provided. |
41
48
  | `thatch-review-context` | Gather project/feature context (PR descriptions, git archaeology, ticket references, memory) before fan-out. Prevents false positives about intentionally deferred work. Also fetches prior review comments on a connected PR/MR for follow-up-round detection and builds a register with preliminary addressed-check status per comment. |
42
- | `thatch-workflow-research` | Research code workflows/features affected by a change or planned change. Reads code flows, comments, git history, memories, docs. Produces a guide to the code for reviewers or planners. |
49
+ | `thatch-code-archaeology` | Investigate an existing feature, debug an unfamiliar area, or begin a new ticket. Explores the code base from multiple angles (data model, state flow, git history, sibling features, skeletons) before proposing changes. The research skill; pair with `thatch-coding-workflow`. |
43
50
  | `thatch-review-followup` | Alternate entrypoint for follow-up review rounds. Verifies whether the author's responses and code changes since your last review round adequately addressed your prior findings, offers to reply on resolved items, then optionally re-runs the full structured review. |
44
51
  | `thatch-change-walkthrough` | Explain a change to the user as a teaching walkthrough: resolve the delta, research each affected workflow at the merge-base, teach current behavior, then overlay the modifications with file:line citations and analogies. |
45
52
  | `thatch-code-walkthrough` | Explain a feature, module, or workflow to the user as a teaching walkthrough: identify the code area (optionally from a branch or PR), research how it works, teach it with file:line citations and analogies, list the key files. |
46
53
  | `thatch-session-reflection` | End-of-session memory recording (project, user, tools, self). |
47
- | `pr-description` | Draft PR descriptions with SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES, project-context research, clarity checks, and bold+italic emphasis for scanning. |
48
- | `ticket-description` | Draft ticket/issue descriptions with clear sections, project-context research, clarity checks, and bold+italic emphasis for scanning. |
49
- | `split-overlarge-pr` | Split already-completed work from an overlarge PR into human-reviewable, release-safe PRs targeting main. |
54
+ | `thatch-coding-workflow` | Plan and execute code changes with a task-list-driven workflow. Use when implementing features, fixing bugs, or making multi-file changes. |
55
+ | `thatch-pr-description` | Draft PR descriptions with SYNOPSIS / PURPOSE / DESCRIPTION / WALK-THROUGH / NOTES, project-context research, clarity checks, and bold+italic emphasis for scanning. |
56
+ | `thatch-ticket-description` | Draft ticket/issue descriptions with clear sections, project-context research, clarity checks, and bold+italic emphasis for scanning. |
57
+ | `thatch-split-overlarge-pr` | Split already-completed work from an overlarge PR into human-reviewable, release-safe PRs targeting main. |
58
+ | `thatch-review-response` | Author-side review response: triage findings, fix bugs one by one, reply on each thread, post a top-level summary comment. |
50
59
 
51
60
  **opencode-only (1)** — the coordinator needs sub-agent support:
52
61
 
@@ -71,7 +80,7 @@ The six problem-finding review specialists share a framework interpolated via `$
71
80
  coordinator or from loading `thatch-review-context`), use it to avoid false
72
81
  positives about intentionally deferred work.
73
82
  - **Workflow context awareness** — if a workflow guide is provided (from the
74
- coordinator or from loading `thatch-workflow-research`), use it to understand
83
+ coordinator or from loading `thatch-code-archaeology`), use it to understand
75
84
  the purpose and evolution of the code, distinguishing intentional behavior
76
85
  and long-standing design decisions from new issues.
77
86
  - **TODO ($ticket) markers** — recognize `TODO ($TICKET-ID): ...` as legitimate
@@ -86,7 +95,7 @@ The synthesizer reuses the same verification rigor but has its own structure
86
95
  ## The two arrays
87
96
 
88
97
  ```ts
89
- const SHARED_SKILLS: SkillDef[] = [ /* 20 skills above */ ];
98
+ const SHARED_SKILLS: SkillDef[] = [ /* 21 skills above */ ];
90
99
  const OPENCODE_ONLY_SKILLS: SkillDef[] = [ /* code-review coordinator */ ];
91
100
  ```
92
101
 
@@ -104,8 +113,14 @@ and `--cursor` pass only the shared set.
104
113
  - **Drift detection**: `installSkills` only writes when the on-disk content
105
114
  differs from the definition. This is how skill improvements ship with new
106
115
  versions without users manually deleting files.
116
+ - **Stale cleanup**: before installing, `installSkills` removes stale skill
117
+ directories. Any `thatch-*` directory not in the current install set is
118
+ deleted (the `thatch-` prefix is our namespace). Three skills renamed from
119
+ non-prefixed to `thatch-`-prefixed in v0.1.27 (pr-description, ticket-description,
120
+ split-overlarge-pr) are also cleaned up through v0.1.35; after that, those
121
+ names are fair game for third parties and the cleanup stops.
107
122
  - **Idempotent**: re-running init or setup overwrites drifted content but leaves
108
- unrelated skill files alone.
123
+ unrelated (non-`thatch-*`) skill files alone.
109
124
 
110
125
  ## Adding a skill
111
126
 
@@ -124,6 +139,11 @@ and `--cursor` pass only the shared set.
124
139
  has responded or pushed changes after your initial review. It verifies whether
125
140
  your prior findings were adequately addressed, offers to reply on resolved
126
141
  items, then optionally hands off to `thatch-code-review` for a fresh round.
142
+ - **Author-side review response**: load `thatch-review-response` when responding
143
+ to review comments on your own PR. It triages findings, collapses comments
144
+ sharing a root cause, fixes bugs one by one with the user, drafts per-thread
145
+ replies, and posts a top-level summary comment. Works on all hosts (no
146
+ sub-agents required).
127
147
 
128
148
  The coordinator is the only skill that can't be used without sub-agents; that's
129
149
  why it lives in `OPENCODE_ONLY_SKILLS`.
@@ -4,13 +4,16 @@ Numbered plan documents capture design decisions that span multiple sessions.
4
4
  Each plan is a snapshot of the reasoning at the time — subsequent plans may
5
5
  supersede earlier ones as the project evolves.
6
6
 
7
- ## Active plans
7
+ Plans are temporary. When a plan is fully implemented, it **graduates**:
8
8
 
9
- | Plan | Description |
10
- |------|-------------|
11
- | [001 — Memory Store](001-memory-store.md) | Initial memory feature: stores, embeddings, tools |
12
- | [002 — Agent-Driven Pipelines](002-agent-driven-pipelines.md) | Extraction/dedup through the agent; hook wiring specifics; supersedes 001's "no CLI" |
13
- | [003 — Memory Hygiene](003-memory-hygiene.md) | Write-time collision warning, recall telemetry, session heartbeat, cluster dedup |
9
+ 1. The plan file is removed from this folder.
10
+ 2. The final architecture is documented in `docs/dev/` — either updated into
11
+ existing dev docs or captured in a new one.
12
+ 3. End-to-end use-case scenarios are added to `docs/qa/use-cases/`.
13
+
14
+ Once graduated, the dev docs and use-case docs are the permanent record. The
15
+ plan file is no longer needed — git history preserves it if someone needs the
16
+ original design reasoning.
14
17
 
15
18
  ## Plan format
16
19
 
@@ -0,0 +1,147 @@
1
+ # Intuition Drives
2
+
3
+ ## Synopsis
4
+
5
+ A pre-response deliberation layer that runs on the first message of a new
6
+ opencode session: perception classifies the prompt, parallel drive sub-agents
7
+ react from their motivational lenses, and a synthesis pass distills them into a
8
+ directive injected into the main agent's context. opencode-only; requires
9
+ parallel sub-agent dispatch via Task.
10
+
11
+ ## Background
12
+
13
+ Fnord runs as a CLI escript where every user invocation carries significant
14
+ intent because it requires a full command-line invocation. Its coordinator runs
15
+ an "intuition" step before responding: a perception pass classifies the prompt,
16
+ ten parallel "drives" (curiosity, skepticism, optimization, modularity,
17
+ convention, laziness, empathy, standing, pragmatism, stewardship) each react
18
+ from their lens, and a synthesis pass distills them into a directive injected
19
+ into the conscious agent's context.
20
+
21
+ In opencode's chat TUI, user messages have far less friction. Running the full
22
+ intuition pipeline on every message would burn tokens on "ok" and "yes." This
23
+ feature is gated to the first message of a new session only.
24
+
25
+ ## Session detection
26
+
27
+ This feature depends on knowing "is this the first message of a new session."
28
+ The opencode plugin hook surface provides this:
29
+
30
+ - `session.created` fires ONLY when a brand-new session object is constructed
31
+ (fresh creation or fork). It does NOT fire when a user resumes or continues an
32
+ existing conversation (`--continue`/`--session` without `--fork` reuses the
33
+ existing session ID).
34
+ - `chat.message` fires on every incoming user message but carries no turn
35
+ number or first-message flag in its input or output.
36
+
37
+ Detection mechanism:
38
+ 1. Track `session.created` events for top-level sessions (no `parentID`) in a
39
+ `Set<string>`.
40
+ 2. First `chat.message` for a session ID in that set = first message. Remove
41
+ from set, trigger the feature.
42
+ 3. Continued/resumed conversations never fire `session.created`, so they are
43
+ never in the set. Second messages also don't trigger (already removed).
44
+
45
+ Edge cases:
46
+ - `--fork` fires `session.created` (correct: a fork is a new conversation).
47
+ - Plugin not running when the session was created (e.g., `--continue` of a
48
+ session from a prior run): no `session.created`, no trigger (correct: it is a
49
+ continued conversation, not new).
50
+ - Child sessions (sub-agents) fire `session.created` with a `parentID` —
51
+ filtered out by the `parentID` check.
52
+
53
+ ## What it does
54
+
55
+ On the first message of a new session, before the main agent responds, a
56
+ deliberation layer runs:
57
+
58
+ 1. **Perception** — classify the prompt (interface, codebase, correction,
59
+ continuation, meta, ambiguous) and produce a short first-person interpretation.
60
+ 2. **Drive reactions** — parallel sub-agents, each arguing from a specific
61
+ motivational lens. Drives are the same as fnord's: curiosity, skepticism,
62
+ optimization, modularity, convention, laziness, empathy, standing, pragmatism,
63
+ stewardship.
64
+ 3. **Synthesis** — distill the drive reactions into a single directive injected
65
+ into the main agent's context.
66
+
67
+ ## Why port it
68
+
69
+ No existing skill does pre-response deliberation. The drives carry real
70
+ personality and map to Jeff's stance (stewardship = "correctness over comfort";
71
+ skepticism = "no reassurance without verification"). The parallel sub-agent
72
+ dispatch is natural for opencode's Task tool.
73
+
74
+ ## Constraints
75
+
76
+ - **opencode-only.** Requires parallel sub-agent dispatch via Task. Claude Code
77
+ agents running skills cannot spawn sub-agents.
78
+ - **First-message-only.** Gated by the session-detection mechanism above.
79
+ Running on every message would burn tokens on trivial follow-ups.
80
+ - **Prompt injection, not a tool.** The synthesis output is injected as a
81
+ synthetic text part into the first `chat.message`, like the recall nudge. The
82
+ main agent sees it as context, not as a tool result.
83
+ - **No pre-response hook exists.** The synthesis must complete inside the
84
+ `chat.message` hook (before the LLM loop runs) or be injected as a system
85
+ message via `experimental.chat.system.transform`. The hook fires before the
86
+ message is persisted and before the LLM loop starts, so a synchronous
87
+ sub-agent dispatch inside `chat.message` would block the turn. The
88
+ `experimental.chat.system.transform` hook is a better injection point because
89
+ it runs on every turn and can append to the system prompt — but it does not
90
+ have access to the user's message text. A hybrid: compute the synthesis in
91
+ `chat.message` (which has the prompt text), cache it in a per-session map, and
92
+ inject it in `experimental.chat.system.transform` on the same turn.
93
+
94
+ ## Open questions
95
+
96
+ 1. **Latency.** Ten parallel sub-agent calls add latency to the first turn. Is
97
+ the value worth it? Options: reduce to 3-4 drives, run drives with a fast
98
+ model, or make it opt-in.
99
+ 2. **Injection point.** The `chat.message` hook fires before the LLM loop but
100
+ injecting a synthetic part there adds it to the user message, not the system
101
+ prompt. `experimental.chat.system.transform` can append to the system prompt
102
+ but fires on every turn and lacks the user message text. The hybrid
103
+ (compute-in-chat.message, inject-in-system.transform) requires a per-session
104
+ cache with one-turn TTL.
105
+ 3. **Drive selection.** Fnord runs all 10 drives. A smaller set (stewardship,
106
+ skepticism, pragmatism, empathy) might capture 80% of the value at 40% of the
107
+ cost.
108
+
109
+ ## Decisions
110
+
111
+ | Decision | Rationale |
112
+ |----------|-----------|
113
+ | opencode-only | Requires parallel sub-agent dispatch via Task |
114
+ | First-message-only | Chat TUI has low message friction; running on every message wastes tokens |
115
+ | Detection via session.created + chat.message | session.created fires only on new sessions; chat.message provides the first-message trigger |
116
+ | Parallel drives via Task sub-agents | Matches fnord's architecture; drives are independent and parallelizable |
117
+ | Injection via system.transform with chat.message cache | chat.message has the prompt text; system.transform can append to the system prompt; hybrid avoids blocking the turn |
118
+
119
+ ## Architecture
120
+
121
+ ```
122
+ session.created (top-level, no parentID)
123
+ → add sessionID to newSessions Set
124
+
125
+ chat.message (first message for sessionID in newSessions)
126
+ → remove from newSessions
127
+ → perception + parallel drives + synthesis → cache in Map<sessionID, directive>
128
+
129
+ experimental.chat.system.transform
130
+ → if directive cached: append directive, then clear cache (one-shot)
131
+
132
+ session.deleted
133
+ → delete from directive cache, newSessions set
134
+ ```
135
+
136
+ ## Dependencies
137
+
138
+ ### Runtime
139
+
140
+ - Fast model for perception and drive reactions (parallel sub-agents)
141
+ - Task tool for parallel drive dispatch (opencode sub-agent support)
142
+
143
+ ### Built-in
144
+
145
+ - Plugin hooks: `event` (session.created, session.deleted),
146
+ `chat.message`, `experimental.chat.system.transform`
147
+ - In-process `Map` for per-session caching (directive, newSessions set)
@@ -0,0 +1,89 @@
1
+ # Nomenclater
2
+
3
+ ## Synopsis
4
+
5
+ Assigns a geeky/sci-fi name to the agent at the start of each new opencode
6
+ session. The name is generated by a fast LLM call, cached for the session, and
7
+ injected into the system prompt so the agent knows its name. opencode-only;
8
+ requires plugin hooks. Pure cosmetic, no functional dependency.
9
+
10
+ ## Background
11
+
12
+ Fnord's Nomenclater (backed by a GenServer name pool) generates whimsical names
13
+ for sub-agents so their actions are distinguishable in logs. Jeff explicitly
14
+ wants this for thatch: "I'd love to have this!" It builds agent identity and
15
+ rapport, complementing the personality instructions in OPENCODE.md.
16
+
17
+ The name must not change mid-conversation and must not trigger on continued
18
+ or resumed sessions.
19
+
20
+ ## Session detection
21
+
22
+ Same mechanism as the intuition-drives plan. See that plan for full detail.
23
+
24
+ `session.created` fires only on brand-new session creation (fresh or fork). It
25
+ does not fire when resuming an existing conversation. Detection: track
26
+ `session.created` for top-level sessions (no `parentID`) in a `Set<string>`,
27
+ generate the name on first `chat.message` for sessions in that set, remove
28
+ from set after generating. Continued/resumed sessions never enter the set.
29
+
30
+ ## What it does
31
+
32
+ ```
33
+ session.created (top-level) → add sessionID to newSessions Set
34
+
35
+ chat.message (first message for sessionID in newSessions)
36
+ → remove from newSessions
37
+ → generate name via fast model → cache in Map<sessionID, name>
38
+
39
+ experimental.chat.system.transform
40
+ → if name cached for sessionID: append "Your name for this session is <name>."
41
+
42
+ session.deleted
43
+ → delete from name cache, newSessions set
44
+ ```
45
+
46
+ Name generation uses fnord's theme list (Jargon File, Zork, Futurama,
47
+ Discworld, D&D, Klingons, Sandman, etc.) and the same JSON-schema response
48
+ format. One LLM call with a fast model. Themes are shuffled and 3 are selected
49
+ per batch to avoid clustering.
50
+
51
+ ## Constraints
52
+
53
+ - **opencode-only.** Requires plugin hook injection. The name is generated by a
54
+ fast LLM call and injected via `experimental.chat.system.transform`.
55
+ - **First-message-only.** Same session-detection mechanism. The name must not
56
+ change mid-conversation.
57
+ - **No persistent state needed.** The name is generated fresh per session and
58
+ held in a per-session map for the duration of that session. No DB writes.
59
+ - **Must not trigger on continued sessions.** A resumed conversation keeps
60
+ whatever name the agent had (or had none, if the feature was added after the
61
+ session started). The `session.created` gate handles this.
62
+
63
+ ## Open question
64
+
65
+ 1. **Where does the name surface?** System prompt injection means the agent
66
+ knows its name but the user only sees it if the agent chooses to use it. Is
67
+ that enough, or should the name appear in the TUI somehow (e.g., a toast on
68
+ session start)?
69
+
70
+ ## Decisions
71
+
72
+ | Decision | Rationale |
73
+ |----------|-----------|
74
+ | opencode-only | Requires plugin hooks for generation and injection |
75
+ | One name per session, cached in memory | No DB writes; name is ephemeral, tied to session lifecycle |
76
+ | Gated to first message of new sessions | Must not rename mid-conversation or trigger on resumed sessions |
77
+ | Detection via session.created + chat.message | Same mechanism as the intuition-drives plan |
78
+
79
+ ## Dependencies
80
+
81
+ ### Runtime
82
+
83
+ - Fast model for name generation (one LLM call per new session)
84
+
85
+ ### Built-in
86
+
87
+ - Plugin hooks: `event` (session.created, session.deleted),
88
+ `chat.message`, `experimental.chat.system.transform`
89
+ - In-process `Map` for per-session name caching