@jeffober/thatch 0.1.26 → 0.1.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -7
- package/artifacts/skills/common.md +1 -1
- package/artifacts/skills/thatch-change-walkthrough.md +2 -2
- package/artifacts/skills/thatch-code-archaeology.md +252 -0
- package/artifacts/skills/thatch-code-review.md +4 -4
- package/artifacts/skills/thatch-code-walkthrough.md +2 -2
- package/artifacts/skills/thatch-coding-workflow.md +79 -0
- package/artifacts/skills/thatch-fact-extractor.md +2 -2
- package/artifacts/skills/{pr-description.md → thatch-pr-description.md} +1 -1
- package/artifacts/skills/thatch-review-context.md +9 -0
- package/artifacts/skills/thatch-review-followup.md +29 -1
- package/artifacts/skills/thatch-review-pedantic.md +16 -1
- package/artifacts/skills/thatch-review-response.md +365 -0
- package/artifacts/skills/thatch-review-synthesizer.md +92 -5
- package/artifacts/skills/{split-overlarge-pr.md → thatch-split-overlarge-pr.md} +1 -1
- package/artifacts/skills/{ticket-description.md → thatch-ticket-description.md} +3 -3
- package/bin/release +3 -3
- package/bin/thatch +11 -10
- package/docs/dev/README.md +7 -6
- package/docs/dev/mcp-parity.md +1 -1
- package/docs/dev/skills.md +29 -9
- package/docs/plans/README.md +9 -6
- package/docs/plans/intuition-drives.md +147 -0
- package/docs/plans/nomenclater.md +89 -0
- package/docs/plans/prediction-consolidation.md +361 -0
- package/docs/qa/README.md +20 -3
- package/docs/user/README.md +19 -5
- package/package.json +1 -1
- package/src/db.ts +6 -6
- package/src/embeddings.ts +2 -2
- package/src/extract-queue.ts +4 -4
- package/src/extraction.ts +4 -4
- package/src/git.ts +1 -1
- package/src/hygiene.ts +1 -1
- package/src/index.ts +40 -34
- package/src/mcp.ts +34 -6
- package/src/prompts.ts +96 -85
- package/src/setup.ts +19 -19
- package/src/sideband.ts +3 -3
- package/src/skills.ts +104 -6
- package/src/tool-defs.ts +93 -14
- package/src/tools.ts +12 -2
- package/artifacts/skills/thatch-workflow-research.md +0 -91
- package/docs/in-progress/prediction-engine.md +0 -404
- package/docs/plans/001-memory-store.md +0 -106
- package/docs/plans/002-agent-driven-pipelines.md +0 -59
- package/docs/plans/003-memory-hygiene.md +0 -61
- package/docs/qa/use-cases/README.md +0 -51
- package/docs/qa/use-cases/UC-001-memory-roundtrip.md +0 -20
- package/docs/qa/use-cases/UC-002-dedup-cycle.md +0 -23
- package/docs/qa/use-cases/UC-003-extraction-nudge.md +0 -56
- package/docs/qa/use-cases/UC-004-cli-inspection.md +0 -22
- package/docs/qa/use-cases/UC-005-setup-install.md +0 -34
- package/docs/qa/use-cases/UC-006-cursor-hook-lifecycle.md +0 -32
- package/docs/qa/use-cases/UC-007-recall-nudge.md +0 -31
- package/docs/qa/use-cases/UC-008-hygiene-heartbeat.md +0 -26
- package/docs/qa/use-cases/UC-009-flush-tools-tiers.md +0 -33
- package/docs/qa/use-cases/UC-010-prime.md +0 -25
- package/docs/qa/use-cases/UC-011-write-time-similarity-warning.md +0 -24
- package/docs/qa/use-cases/UC-012-model-migration.md +0 -28
- package/docs/qa/use-cases/UC-013-compaction-context.md +0 -25
- package/docs/qa/use-cases/UC-014-skill-install-drift.md +0 -28
- package/docs/qa/use-cases/UC-015-env-override-matrix.md +0 -28
- package/docs/qa/use-cases/UC-016-concurrent-session-isolation.md +0 -37
- package/docs/qa/use-cases/UC-017-buffer-tool-vs-buffer-batch.md +0 -27
- package/docs/qa/use-cases/UC-018-mcp-startup-setup-detection.md +0 -38
- package/docs/qa/use-cases/UC-019-archived-memory-lifecycle.md +0 -36
- package/docs/qa/use-cases/UC-020-extraction-escalation.md +0 -52
- package/docs/qa/use-cases/UC-021-prediction-autofire.md +0 -21
- package/docs/qa/use-cases/UC-022-prediction-dedup.md +0 -19
- package/docs/qa/use-cases/UC-023-prediction-confidence-model.md +0 -23
- package/docs/qa/use-cases/UC-024-prediction-delete.md +0 -20
package/docs/dev/mcp-parity.md
CHANGED
|
@@ -22,7 +22,7 @@ This document maps the feature parity and documents the remaining gaps.
|
|
|
22
22
|
| **System prompt** (store names, usage rules) | `experimental.chat.system.transform` — dynamic, repo baked in at runtime | CLAUDE.md static text appended by `thatch setup`; repo auto-detected by the MCP server at startup | AGENTS.md static text appended by `thatch setup`; repo auto-detected at startup | **Approximate** — static text persists through compaction, so the agent retains the usage instructions, but the dynamic per-turn refresh is lost |
|
|
23
23
|
| **Session-start reminder** (recall nudge + hygiene heartbeat) | `session.created` event → `client.session.prompt` injects a synthetic message | `SessionStart` hook → `thatch reminder`; stdout becomes context | `sessionStart` hook → `thatch reminder --json`; output is `additional_context` JSON | **Full** |
|
|
24
24
|
| **Compaction context** (re-familiarize after compaction) | `experimental.session.compacting` hook appends context to the compaction output | `PostCompact` hook — side-effects only, **cannot inject context** | No equivalent hook | **Gapped** — see below |
|
|
25
|
-
| **Extraction** (buffer tool calls, extract durable facts) | `tool.execute.after` buffers non-thatch, non-skill, non-task tool calls in-process; **direct extraction** is the primary path — when the parent session goes idle with pending buffer entries, the plugin creates a child session via the SDK (`client.session.create` with `parentID`) and prompts it
|
|
25
|
+
| **Extraction** (buffer tool calls, extract durable facts) | `tool.execute.after` buffers non-thatch, non-skill, non-task tool calls in-process; **direct extraction** is the primary path — when the parent session goes idle with pending buffer entries, the plugin creates a child session via the SDK (`client.session.create` with `parentID`) and prompts it to call `get_extraction_payload` (nudge suppressed via the `extracting` set); the `chat.message` nudge path is a **fallback** used when direct extraction throws | `PostToolBatch` → `thatch buffer-batch` (file-backed JSONL queue); `UserPromptSubmit` → `thatch flush-tools` peeks the queue and prints the nudge with session ID + fetch tool name (does not drain — the queue persists until a memory write or `extraction_done`) | `postToolUse` → `thatch buffer-tool` (single-tool, file-backed queue); `beforeSubmitPrompt` → `thatch flush-tools --json` | **Partial** — opencode uses direct extraction (parent idle → child session) as the primary path, with the nudge as fallback; MCP hosts are nudge-only. Both paths use `get_extraction_payload` to fetch the queued interactions as a tool response, keeping the full payload out of the main session's context window. Nudge timing differs: the nudge arrives at the **start** of the next turn in Claude Code/Cursor; opencode's direct extraction fires at **end of turn** (session idle), and the nudge fallback fires at the start of the next turn like MCP |
|
|
26
26
|
| **Extraction feedback** (toast notifications) | `client.tui.showToast` fires when the extraction child goes idle — shows `[thatch] new: N, updated: M, deleted: K` (success) or `extraction complete — nothing to save` (info); best-effort, silently ignored in headless mode | No TUI connection — MCP hosts have no equivalent | No TUI connection | **Gapped** — MCP hosts cannot show toast notifications |
|
|
27
27
|
| **Prompt-aware recall nudge** | `chat.message` hook embeds the prompt with the in-process warm model, searches `db.search()`, pushes a nudge part if matches ≥ threshold | `UserPromptSubmit` hook → `thatch flush-tools` connects to the MCP server's sideband socket; the warm server embeds + searches; hook prints the nudge or falls back to the write nudge | `beforeSubmitPrompt` hook → `thatch flush-tools --json` (same sideband path) | **Full** — sideband socket gives cold hook processes access to the warm MCP server's model |
|
|
28
28
|
| **Prediction auto-fire** (user decision model) | `chat.message` hook scores the prompt embedding against prediction matchers; injects a `[thatch] User decision model` nudge alongside the recall nudge (separate synthetic part, same embedding call) | `UserPromptSubmit` hook → `thatch flush-tools` fires prediction query via the sideband socket's `predictions` method in parallel with the recall nudge | `beforeSubmitPrompt` hook → `thatch flush-tools --json` (same sideband path) | **Full** — same `scorePredictionNudge` entry point in both paths |
|
package/docs/dev/skills.md
CHANGED
|
@@ -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
|
|
31
|
+
## The 23 skills
|
|
25
32
|
|
|
26
|
-
**Shared (
|
|
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-
|
|
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
|
-
| `
|
|
48
|
-
| `
|
|
49
|
-
| `
|
|
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-
|
|
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[] = [ /*
|
|
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`.
|
package/docs/plans/README.md
CHANGED
|
@@ -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
|
-
|
|
7
|
+
Plans are temporary. When a plan is fully implemented, it **graduates**:
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|