You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+31-2Lines changed: 31 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -328,10 +328,39 @@ Buddy was a Tamagotchi-style virtual pet — a companion you hatch and tend to.
328
328
- The raw `<claudesay>` tag appears in the terminal scrollback before the bubble renders (Claude streams it before the Stop hook fires).
329
329
- Figures do not render in CI, `--print` mode, or non-interactive SSH sessions.
330
330
- Per-turn reminder adds ~20 tokens per turn.
331
+
-**Stop-hook bubble reflects only the final assistant text block of a turn.** The Stop hook reads `.last_assistant_message` and grabs the last `<claudesay>` tag in it (`hooks/scripts/stop.sh`, `tail -1`). If Claude emits multiple conversational text messages in one turn (text → tool → text → tool → text), only the tag in the last block renders.
331
332
332
-
## Compatibility
333
+
**Why we stop here:** the injected protocol (`hooks/scripts/session-start.sh`) instructs Claude to emit a single tag *at the very end*, with room for ~120 chars / 1-2 sentences in first person covering the whole turn. One well-written bubble usually describes the turn in full, making multi-bubble rendering redundant for the intended use case.
333
334
334
-
Stacks naturally with the [caveman plugin](https://github.com/JuliusBrussee/caveman). Caveman compresses the main response; claudesay bubbles the separately-written tag. No conflict. `caveman-lite` recommended as a complementary install.
335
+
**If you want to render a bubble per mid-turn text block**, parse `transcript_path` (available on Stop hook input JSON). The transcript is JSONL, one message per line. Assistant entries look like:
A turn spans **multiple** assistant entries (one per LLM call, split by tool boundaries). Each has its own `.message.content` array of blocks — `thinking`, `text`, `tool_use`. Steps:
346
+
347
+
1. Walk JSONL backwards from EOF.
348
+
2. Stop at the most recent `type:"user"` entry whose content is not a `tool_result` — that marks the start of the current turn.
349
+
3. For each assistant entry after that boundary, extract `.message.content[] | select(.type=="text") | .text`.
350
+
4. Run the existing `<claudesay>` regex over each block; render matches sequentially, or combine into one multi-line bubble.
351
+
352
+
Sketch (`jq`):
353
+
354
+
```bash
355
+
jq -r '
356
+
select(.type=="assistant")
357
+
| .message.content[]?
358
+
| select(.type=="text")
359
+
| .text
360
+
'"$TRANSCRIPT_PATH"
361
+
```
362
+
363
+
Add guards for missing/malformed/large transcripts. The protocol would also need updating to permit (and describe) mid-turn tags. Not shipped — contributions welcome.
| happy-a |`( ^ᵕ^ )`| Normal success (variant A) |
183
-
| happy-b |`( ᵕ‿ᵕ )`| Normal success (variant B) |
184
-
| excited |`( ^▽^ )`| Big win |
185
-
| excited-b |`( ≧▽≦ )`| Very excited |
186
-
| thinking |`( ._. )`| In progress / uncertain |
187
-
| focused |`( -.- )`| Running a tool |
188
-
| upset |`( >_< )`| Warning or partial failure |
189
-
| error |`( x_x )`| Actual error |
218
+
| Mood | Face | When used |
219
+
|---------|----------|--------------------------|
220
+
| happy-a |`( ^ᵕ^ )`| Normal success (variant A) |
221
+
| happy-b |`( ᵕ‿ᵕ )`| Normal success (variant B) |
222
+
| excited |`( ^▽^ )`| Big win |
223
+
| excited-b |`( ≧▽≦ )`| Very excited |
224
+
| thinking |`( ._. )`| In progress / uncertain |
225
+
| focused |`( -.- )`| Running a tool |
226
+
| upset |`( >_< )`| Warning or partial failure |
227
+
| error |`( x_x )`| Actual error |
190
228
191
229
Positive moods rotate between variants on each render to avoid repetition.
192
230
193
231
### Tool Props (PreToolUse)
194
232
195
233
Each tool entry has a `side` field (`left`/`right`) controlling which hand holds the prop. "Reaching out" tools (searching, reading, fetching) use the left hand; "doing" tools (editing, running, spawning) use the right.
| Custom character missing a mood | Fall back to default character expression |
285
-
| Custom character missing `CHAR_HAND_LEFT` or `CHAR_HAND_RIGHT`| Fall back to `m` for each |
286
-
| Tool entry has no `side` or side is `—`| No prop shown, both hands rendered normally |
287
-
|`jq` not installed |`/claudesay on` preflight check detects this and prints install instructions; hooks exit 0 silently if somehow reached |
288
-
| Flag absent | All hooks exit at line 2 — zero overhead |
289
-
290
-
---
291
-
292
-
## Caveman Compatibility
293
-
294
-
`claudesay` stacks naturally with the caveman plugin. Caveman compresses the main response body; `claudesay` bubbles the separately-written summary tag. No conflict. README recommends `caveman-lite` as a complementary install.
0 commit comments