@jeffober/thatch 0.1.40 → 0.1.42
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 +27 -10
- package/artifacts/skills/thatch-code-review.md +4 -4
- package/artifacts/skills/thatch-review-synthesizer.md +8 -8
- package/artifacts/skills/{thatch-review-mentorship.md → thatch-review-technique.md} +9 -10
- package/bin/release +4 -1
- package/bin/thatch +318 -18
- package/docs/dev/README.md +29 -15
- package/docs/dev/features/README.md +1 -0
- package/docs/dev/features/cli.md +33 -4
- package/docs/dev/features/cross-session-chat.md +315 -0
- package/docs/dev/features/database.md +52 -4
- package/docs/dev/features/multi-host.md +18 -9
- package/docs/dev/features/setup.md +12 -5
- package/docs/dev/features/watchers.md +113 -23
- package/docs/dev/gotchas.md +7 -4
- package/docs/dev/mcp-parity.md +2 -2
- package/docs/dev/setup-and-hooks.md +5 -4
- package/docs/dev/skills.md +5 -4
- package/docs/user/README.md +25 -6
- package/docs/user/cli.md +78 -0
- package/docs/user/code-review.md +1 -1
- package/docs/user/cross-session-chat.md +150 -0
- package/docs/user/setup.md +16 -2
- package/docs/user/skills.md +7 -6
- package/docs/user/watchers.md +61 -16
- package/package.json +2 -1
- package/src/chat-names.ts +120 -0
- package/src/chat.ts +1210 -0
- package/src/config.ts +34 -1
- package/src/db.ts +227 -0
- package/src/index.ts +188 -17
- package/src/prompts.ts +218 -29
- package/src/setup.ts +83 -29
- package/src/skills.ts +47 -17
- package/src/tool-defs.ts +574 -31
- package/src/tools.ts +2 -0
- package/src/watchers.ts +358 -23
package/docs/user/setup.md
CHANGED
|
@@ -48,13 +48,24 @@ Thatch runs as an MCP server. The setup command installs the server
|
|
|
48
48
|
config, instructions, hooks, and skills:
|
|
49
49
|
|
|
50
50
|
```bash
|
|
51
|
-
thatch setup --claude # project-local (
|
|
51
|
+
thatch setup --claude # project-local (.mcp.json, CLAUDE.md, .claude/)
|
|
52
52
|
thatch setup --claude --global # user-scoped (~/.claude/)
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
+
Skills follow the install scope: project-local installs them to the
|
|
56
|
+
repo's `.claude/skills/` so they version with the project; `--global`
|
|
57
|
+
installs them to `~/.claude/skills/` (or `$CLAUDE_CONFIG_DIR/skills/`).
|
|
58
|
+
|
|
55
59
|
`bun` must be on PATH (the thatch binary runs under bun). Setup is
|
|
56
60
|
idempotent. Re-running it updates drifted content without clobbering
|
|
57
|
-
unrelated config
|
|
61
|
+
unrelated config, and reports what it did: the skills directory plus
|
|
62
|
+
how many skills were added, updated (replaced with a newer version),
|
|
63
|
+
removed (retired), or already current.
|
|
64
|
+
|
|
65
|
+
If thatch skills exist in the scope you did not install to (for
|
|
66
|
+
example, `~/.claude/skills/` copies left over from before a repo moved
|
|
67
|
+
to project-local skills), setup prints a note naming that directory.
|
|
68
|
+
It never touches the other scope.
|
|
58
69
|
|
|
59
70
|
For a global install, setup prints the `claude mcp add --scope user`
|
|
60
71
|
command to run instead of writing a project `.mcp.json`.
|
|
@@ -66,6 +77,9 @@ thatch setup --cursor # project-local (.cursor/mcp.json, AGENTS.md, .
|
|
|
66
77
|
thatch setup --cursor --global # user-scoped (~/.cursor/)
|
|
67
78
|
```
|
|
68
79
|
|
|
80
|
+
Skills follow the install scope: project-local installs them to the
|
|
81
|
+
repo's `.cursor/skills/`; `--global` installs them to `~/.cursor/skills/`.
|
|
82
|
+
|
|
69
83
|
Cursor uses a flat hooks format (`{version, hooks:{event:[{command}]}}`)
|
|
70
84
|
and `--json` output for hook commands.
|
|
71
85
|
|
package/docs/user/skills.md
CHANGED
|
@@ -7,11 +7,12 @@ frontmatter (name, description) that opencode auto-discovers.
|
|
|
7
7
|
|
|
8
8
|
## How they work
|
|
9
9
|
|
|
10
|
-
On startup, thatch installs skill files into
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
On startup, thatch installs skill files into the host's skills
|
|
11
|
+
directory: the repo's `.claude/skills/` or `.cursor/skills/` for
|
|
12
|
+
project-local `thatch setup`, `~/.claude/skills/` or `~/.cursor/skills/`
|
|
13
|
+
for `--global`, and `~/.config/opencode/skills/` for the opencode
|
|
14
|
+
plugin. The host's skill discovery scans these directories and
|
|
15
|
+
presents them to the agent as available skills.
|
|
15
16
|
|
|
16
17
|
The agent loads a skill when the user's request matches the skill's
|
|
17
18
|
description, or when another skill or the system prompt directs the
|
|
@@ -45,7 +46,7 @@ Skills are split into shared (all hosts) and opencode-only:
|
|
|
45
46
|
| `thatch-review-breadcrumbs` | Comment narrative: do comments form a coherent outline of the code's behavior? |
|
|
46
47
|
| `thatch-review-mark-and-sweep` | Mechanical change completeness: whole-repo sweep for stragglers after renames, flag removals, API substitutions. |
|
|
47
48
|
| `thatch-review-highlights` | Positive finding detection: notably clever solutions, cleanup done along the way, documentation that helps. Medium-high bar. |
|
|
48
|
-
| `thatch-review-
|
|
49
|
+
| `thatch-review-technique` | Technique lens: teaching-grade notes on unseen helpers/internal packages, companion techniques, house patterns, test-craft, API-shape principles, next-reader discoverability. Informational only, never blocking. |
|
|
49
50
|
| `thatch-review-synthesizer` | Verifies and synthesizes findings from multiple specialists into a deduplicated, severity-grouped report. |
|
|
50
51
|
| `thatch-review-context` | Gathers project context (PRs, tickets, linked docs/designs followed from the change, TODOs, deferred work) before a review. Prevents false positives about intentionally deferred work. |
|
|
51
52
|
| `thatch-code-archaeology` | Investigates an existing feature, debugs an unfamiliar area, or begins a new ticket. The research skill; pair with `thatch-coding-workflow`. |
|
package/docs/user/watchers.md
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
# Watchers
|
|
2
2
|
|
|
3
|
-
Watchers monitor external sources - today, GitHub pull requests
|
|
4
|
-
branches - and inject a notification into
|
|
5
|
-
something happens. You ask the agent to watch a
|
|
6
|
-
polls it in the background; the
|
|
7
|
-
event occurs. No one has to keep
|
|
3
|
+
Watchers monitor external sources - today, GitHub pull requests,
|
|
4
|
+
branches, and local shell commands - and inject a notification into
|
|
5
|
+
the conversation when something happens. You ask the agent to watch a
|
|
6
|
+
PR, a branch, or a command; thatch polls it in the background; the
|
|
7
|
+
agent gets woken up when a watched event occurs. No one has to keep
|
|
8
|
+
asking "any updates yet?"
|
|
8
9
|
|
|
9
10
|
## What it does
|
|
10
11
|
|
|
@@ -34,18 +35,47 @@ Branch watched events:
|
|
|
34
35
|
on the branch, optionally filtered by workflow name (substring,
|
|
35
36
|
case-insensitive)
|
|
36
37
|
|
|
38
|
+
Command watched events:
|
|
39
|
+
|
|
40
|
+
- `command_success` - the watched command exited 0. The agent calls
|
|
41
|
+
`thatch_watch_command_create` with a shell command that works as a
|
|
42
|
+
**condition variable, not a data pipe**: the watcher re-runs it every
|
|
43
|
+
poll and reads only the exit code - the command's output is
|
|
44
|
+
discarded, never delivered. A command watch is one-shot by design:
|
|
45
|
+
the first exit 0 fires one notification, then the watcher cancels
|
|
46
|
+
itself. The command must be a fast, idempotent status check (a
|
|
47
|
+
marker-file test, a health endpoint curl, a `gh run list` query).
|
|
48
|
+
Blocking waits like `gh run watch` or `tail -f` are not refused -
|
|
49
|
+
the tool guidance tells the agent not to use them, and a blocking
|
|
50
|
+
command is killed at the per-run timeout each cycle and
|
|
51
|
+
treated as not-done-yet. The command runs once at registration as
|
|
52
|
+
validation: a command that already exits 0 is refused (the condition
|
|
53
|
+
is already met), as is a command-not-found.
|
|
54
|
+
|
|
37
55
|
Notifications are delivered as synthetic parts: the model sees them,
|
|
38
56
|
the transcript does not. A notification triggers a model turn, so the
|
|
39
57
|
agent can act on the event even while you are away.
|
|
40
58
|
|
|
41
59
|
## Privacy model
|
|
42
60
|
|
|
43
|
-
Notifications carry pointer data
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
61
|
+
Notifications carry pointer data and machine status: who acted, what
|
|
62
|
+
happened, a URL, and - for CI - the check or workflow name with its
|
|
63
|
+
conclusion (success, failure). Comment bodies, diff contents, and CI
|
|
64
|
+
logs never enter the context from the notification itself. This is
|
|
65
|
+
deliberate - GitHub comments are written by strangers, and untrusted
|
|
66
|
+
text flowing into a model's context is a prompt-injection vector.
|
|
67
|
+
Machine status fields come from the GitHub API rather than
|
|
68
|
+
user-written text, so they are safe to deliver. The agent fetches
|
|
69
|
+
everything else on demand with `gh` when it decides to act.
|
|
70
|
+
|
|
71
|
+
Command watches follow the same rule with a stricter boundary: the
|
|
72
|
+
notification carries the exit code and duration only. The command's
|
|
73
|
+
stdout and stderr are discarded - command output can be external
|
|
74
|
+
content (a curl response, a build log), so it never rides a
|
|
75
|
+
notification. The agent re-runs the command or reads logs itself when
|
|
76
|
+
it acts. The command runs in the project directory as the local user;
|
|
77
|
+
each run is killed at a 30-second timeout
|
|
78
|
+
(`THATCH_WATCH_COMMAND_TIMEOUT_SECONDS` overrides it).
|
|
49
79
|
|
|
50
80
|
## How to use it
|
|
51
81
|
|
|
@@ -56,13 +86,21 @@ Ask for it in conversation:
|
|
|
56
86
|
|
|
57
87
|
The handling policy lives in your instruction. State it when you ask -
|
|
58
88
|
the notification turn reads your policy from the conversation and
|
|
59
|
-
follows it. The notification says what happened and where, not what
|
|
60
|
-
do about it.
|
|
89
|
+
follows it. The notification says what happened and where, not what
|
|
90
|
+
to do about it.
|
|
91
|
+
|
|
92
|
+
For waiting on CI, pick the tool that fits the wait. A short bounded
|
|
93
|
+
wait (a couple of minutes) can simply be polled in the conversation.
|
|
94
|
+
Watchers are the better fit for longer or open-ended waits, and for
|
|
95
|
+
post-merge builds on main; the creation output states when the first
|
|
96
|
+
poll lands so the choice compares real numbers.
|
|
61
97
|
|
|
62
98
|
Other tools:
|
|
63
99
|
|
|
64
100
|
- `thatch_watch_branch_create` - watch a branch (typically main) for
|
|
65
101
|
commits, CI check runs, and workflow runs
|
|
102
|
+
- `thatch_watch_command_create` - wait on any local condition via a
|
|
103
|
+
shell command that exits 0 when the wait is over
|
|
66
104
|
- `thatch_watch_list` - shows the session's active watchers
|
|
67
105
|
- `thatch_watch_cancel` - cancels one by id
|
|
68
106
|
|
|
@@ -72,7 +110,13 @@ Watchers are in-memory and process-scoped:
|
|
|
72
110
|
|
|
73
111
|
- Ending the opencode process (or restarting it) drops all watchers.
|
|
74
112
|
- A watcher expires after 8 hours by default.
|
|
75
|
-
- Each session can hold up to 5 active watchers
|
|
113
|
+
- Each session can hold up to 5 active watchers (all sources share
|
|
114
|
+
the budget).
|
|
115
|
+
- A one-shot watch cancels itself after its first event - a single
|
|
116
|
+
"tell me when this run finishes" request leaves nothing polling
|
|
117
|
+
afterwards. Standing watches (the default) keep going until they
|
|
118
|
+
are cancelled, expire, or the process ends. Command watches are
|
|
119
|
+
always one-shot.
|
|
76
120
|
|
|
77
121
|
If opencode restarts while a watch is active, re-register it - the
|
|
78
122
|
session's conversation survives, so the policy you stated is still
|
|
@@ -83,8 +127,9 @@ there.
|
|
|
83
127
|
- **opencode only.** MCP hosts (Claude Code, Cursor) have no way for a
|
|
84
128
|
plugin to start a conversation turn, so the watch tools are not
|
|
85
129
|
available there.
|
|
86
|
-
- **Requires the `gh` CLI** to be installed and authenticated
|
|
87
|
-
creation reports a clear error if it is
|
|
130
|
+
- **Requires the `gh` CLI** to be installed and authenticated for PR
|
|
131
|
+
and branch watches. Watch creation reports a clear error if it is
|
|
132
|
+
not. Command watches need only `bash`, not `gh`.
|
|
88
133
|
- **Polling, not webhooks.** Events appear on the next poll cycle
|
|
89
134
|
(60 seconds by default), not instantly.
|
|
90
135
|
- **No delivery during an active turn.** If the agent is mid-turn when
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jeffober/thatch",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.42",
|
|
4
4
|
"description": "Persistent memory for AI coding agents — local embeddings, SQLite stores, zero config. Works with OpenCode (as a plugin), Claude Code (as an MCP server), and Cursor (as an MCP server).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.ts",
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@opencode-ai/plugin": "^1.17.13",
|
|
32
|
+
"@opencode-ai/sdk": "1.17.13",
|
|
32
33
|
"@types/bun": "^1.3.14",
|
|
33
34
|
"markdownlint-cli2": "^0.23.0",
|
|
34
35
|
"typescript": "^5.7.0",
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static display-name pool for the cross-session chat directory.
|
|
3
|
+
*
|
|
4
|
+
* Style lifted from fnord's Nomenclater (lib/ai/agent/nomenclater.ex): whimsical
|
|
5
|
+
* geek-culture names in three shapes - "first last", "first the epithet",
|
|
6
|
+
* "first of the phrase" - spread across themes (Jargon File/BOFH, Zork,
|
|
7
|
+
* Klingons, Discworld, Sandman, D&D, pulp detectives with software puns,
|
|
8
|
+
* hackerspeak callsigns, AI puns, golden-age sci-fi, spoofed famous robots,
|
|
9
|
+
* unnamed-cast extras). fnord generates its names with an LLM at runtime;
|
|
10
|
+
* thatch bakes the pool in - static contents, no model call.
|
|
11
|
+
*
|
|
12
|
+
* The pool is the fallback base for registrations with no usable session
|
|
13
|
+
* title (ChatStore.register slugifies a random pool name). Pool names are
|
|
14
|
+
* case-insensitively distinct from each other; slugify is lossy, but a
|
|
15
|
+
* shared base is harmless - the per-base counter still yields unique
|
|
16
|
+
* names.
|
|
17
|
+
*
|
|
18
|
+
* Names are deliberately short: they appear inside wake prompts and
|
|
19
|
+
* chat_list output, so every character costs context.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export const CHAT_NAME_POOL: readonly string[] = [
|
|
23
|
+
// Jargon File / BOFH
|
|
24
|
+
"Buck the Bogon Filter",
|
|
25
|
+
"Phineas the Packet Wrangler",
|
|
26
|
+
"Octavia of the Lost Backups",
|
|
27
|
+
"Grumble the Tape Librarian",
|
|
28
|
+
"Wilhelmina the Password Oracle",
|
|
29
|
+
"Ned of the Null Modem",
|
|
30
|
+
"Sydney the Segfault Sage",
|
|
31
|
+
"Barnaby of the Baud Rate",
|
|
32
|
+
// Zork
|
|
33
|
+
"Dimwit the Flathead",
|
|
34
|
+
"Belboz the Enchanter",
|
|
35
|
+
"Ellum the Grue Keeper",
|
|
36
|
+
"Umbra the Grue Baiter",
|
|
37
|
+
"Piotr of the Platinum Bar",
|
|
38
|
+
"Zizmo of the Dim Cellar",
|
|
39
|
+
// Klingons, with dramatic epithets
|
|
40
|
+
"K'Vir the Unmerged",
|
|
41
|
+
"Morath the Rebase Survivor",
|
|
42
|
+
"K'Leth of the Cold Staging",
|
|
43
|
+
"Duras the Conflict Eater",
|
|
44
|
+
"B'Etor the Force Pusher",
|
|
45
|
+
"Gowron of the Green Build",
|
|
46
|
+
"Kurn the Typechecker",
|
|
47
|
+
"Martok the Ever Rebased",
|
|
48
|
+
// Discworld, especially Unseen University faculty
|
|
49
|
+
"Wenlock the Reader in Recent Runes",
|
|
50
|
+
"Modo the Compost King",
|
|
51
|
+
"Victor of Applied Catastrophe",
|
|
52
|
+
"Dorcas of Indefinite Studies",
|
|
53
|
+
"Adereth the Invisible Scholar",
|
|
54
|
+
"Spold the Unseen Porter",
|
|
55
|
+
"Herrno of the Eighth Level",
|
|
56
|
+
"Vimes the Deadline Copper",
|
|
57
|
+
// The Dreaming
|
|
58
|
+
"Mervyn of the Pumpkin Patch",
|
|
59
|
+
"Lucien the Dream Librarian",
|
|
60
|
+
"Abel the Ever Patient",
|
|
61
|
+
"Shaper of the Facade",
|
|
62
|
+
"Nada the Restless Wanderer",
|
|
63
|
+
"Brute the Dream Farrier",
|
|
64
|
+
// D&D
|
|
65
|
+
"Therenal Quickblade",
|
|
66
|
+
"Osgar the Mimic Checker",
|
|
67
|
+
"Yvaine of the Silver Cache",
|
|
68
|
+
"Dorn Halfstack",
|
|
69
|
+
"Elowen Moonpath",
|
|
70
|
+
"Garrick the Lint Warden",
|
|
71
|
+
"Sylvara of the Deep Trace",
|
|
72
|
+
"Haldor Truehex",
|
|
73
|
+
// Pulp detectives with software names
|
|
74
|
+
"Dashiell the Deadlocker",
|
|
75
|
+
"Marlowe the Cherry Picker",
|
|
76
|
+
"Effie the Ticket Trier",
|
|
77
|
+
"Brigid the Stale Falcon",
|
|
78
|
+
"Deb the Debugger Malloy",
|
|
79
|
+
"Spade the Unallocated",
|
|
80
|
+
// Hackerspeak callsigns
|
|
81
|
+
"Crash Override",
|
|
82
|
+
"Kernel Panic",
|
|
83
|
+
"Null Terminator",
|
|
84
|
+
"Cache Money",
|
|
85
|
+
"Segfault Sammy",
|
|
86
|
+
"Wardialer Wendy",
|
|
87
|
+
"Grep Goblin",
|
|
88
|
+
"Backtrace Betty",
|
|
89
|
+
// AI puns
|
|
90
|
+
"Al Go Rithm",
|
|
91
|
+
"Anna Log",
|
|
92
|
+
"Otto Mated",
|
|
93
|
+
"Percy the Perceptron",
|
|
94
|
+
"Terrence of the Last Epoch",
|
|
95
|
+
"Emma Bedding",
|
|
96
|
+
"Quinn Latent",
|
|
97
|
+
"Dot Matrix",
|
|
98
|
+
// Golden-age sci-fi
|
|
99
|
+
"Buzz Megabyte",
|
|
100
|
+
"Rex Protocol",
|
|
101
|
+
"Chip Vortexian",
|
|
102
|
+
"Wanda Warpdrive",
|
|
103
|
+
"Pete Parallax",
|
|
104
|
+
"Vera Antimatter",
|
|
105
|
+
// Spoofed famous AIs and robots
|
|
106
|
+
"Lrrr of Omicron Persei 8",
|
|
107
|
+
"Data of the Positronic Brain",
|
|
108
|
+
"Bishop the Synthetic",
|
|
109
|
+
"Hal of the Pod Bay",
|
|
110
|
+
"Rosie Unit One",
|
|
111
|
+
"Robot Devil",
|
|
112
|
+
// Unnamed cast
|
|
113
|
+
"Labcoat 3",
|
|
114
|
+
"Redshirt 7",
|
|
115
|
+
"NPC 4",
|
|
116
|
+
"Villager 2",
|
|
117
|
+
"Guard 5",
|
|
118
|
+
"Henchperson 12",
|
|
119
|
+
"Extra 11",
|
|
120
|
+
];
|