Skip to content

pg-Parunson/crier

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

crier

Your coding agent tells you when it's done — out loud, in one sentence.

한국어

crier speaking when a task finishes

▶ with sound — the chime and the voice are the whole point.

You set the agent going and switch to something else. It finishes. You don't notice. Five minutes later you tab back, read the screen, and find out it just needed you to say yes.

crier says it instead:

🔔 "Fixed the memory leak, all three tests pass. Want me to commit?"

🔔 "Delete the build folder — may I?"

🔔 "You've hit the rate limit."

Not a notification sound — a sentence you can act on without looking.

Runs entirely on your machine. No API key, no account, no per-character billing. Korean, English, Japanese.


Install

curl -fsSL https://raw.githubusercontent.com/pg-Parunson/crier/main/bootstrap.sh | sh

Then restart your agent and run crier demo to hear it.

That's it. Nothing to configure, no keys to paste. (Not on Claude Code? Add -s -- codex, -s -- gemini, or -s -- cursor to the end.)

macOS. Changed your mind? crier uninstall puts your settings back.

Make it yours (three minutes, then never again)

crier voices             # plays all ten, one after another
crier voice F2           # keep the one you liked
crier name "Sam"         # it'll use your name now and then — not every time
crier tone friendly      # plain · friendly · playful

Then go back to working normally. crier sits in the background and speaks up on its own.

When it speaks

Four moments. Everything else, it stays quiet.

It finished "All three tests pass. Want me to commit?"
It needs permission "Delete the build folder — may I?"
It broke "You've hit the rate limit."
It's been waiting "Still here whenever you're ready."

It never reads the answer aloud. That's already on your screen, and you read faster than you listen.

Start typing and it stops mid-word. You never have to wait for it to finish a sentence.

Too chatty?

crier tone plain         # fewer words
crier uninstall          # gone; settings restored from backup

To silence one kind of announcement, flip it to false under events in ~/.crier/config.json. Saves take effect immediately — no restart.


How it works — the design, and why it's built this way

What gets spoken, and what doesn't

peon-ping (4.9k★) proved the trigger model is right: hook the agent's lifecycle, make a noise. But a fixed sound only tells you something happened, never what — so you still go look. crier puts a sentence where the sound was.

Every candidate announcement faces one question: does hearing this change what you do?

Event Changes what you do?
Turn finished ✅ come back and check
Permission needed ✅ approve or don't
Request failed ✅ wait, or go do something else
Idle too long ✅ come back
Subagent started off by default

That last row is the whole design in miniature. You just pressed enter — being told "starting work" changes nothing. No rewording fixes that, because the wording isn't the problem: the event has no content.

Who writes the sentence

The agent does. crier asks it to end each reply with one spoken line:

[say] Fixed the memory leak, all three tests pass. Want me to commit?

There is no second API call and no second key. The model that just did the work — the only thing that knows what the turn was about — writes one more line. A few output tokens. If you're running a coding agent, you already have everything crier needs.

Skip that (crier prompt remove) and it falls back to a rule: the last sentence if it's a question — that's what you have to answer — otherwise the first, where the outcome gets stated. It works. The agent writes a better line than any rule can.

Permission requests borrow the model's words too. Agents already write a plain-language description next to every shell command — "Delete the build folder" beside rm -rf build. crier speaks that, so you hear "Delete the build folder — may I?" rather than "May I run rm?". Free again: the sentence was already there.

What genuinely is canned: errors (error_type is a closed enum — ten values, each with one correct rendering, so a table is the right answer, not a limitation) and idle (there is nothing to say). Both live in locales.json. The tone you pick goes into those lines and into the agent's instruction, which is why a persona costs nothing here — it's a sentence in a prompt, not a model.

Noise control

This is the part that decides whether you keep it installed. A parallel fan-out fires a hook per subagent; run ten projects at once and a naive build becomes an attack.

  1. Once per turn. Subagent announcements fire only for the turn's first agent (keyed on prompt_id). Eight agents or thirty — you hear it once, then silence until your next prompt. A cooldown alone can't do this: a heavy turn keeps spawning agents for minutes, so it would only flatten the opening burst.
  2. Cooldown (2.5s, shared across sessions) so ten projects don't talk over each other.
  3. Priority. Permission requests and errors skip the cooldown. A chatty announcement must never swallow "Drop the users table — may I?".

The chime

A voice out of nowhere makes you jump, so a bell rings first.

The chimes are synthesized at install (bin/earcons.py), never shipped as files — nothing to license, nothing to attribute. Each is a few harmonic partials under an exponential decay: a struck bell. Rising asks or announces; falling settles or warns. All under half a second.

They pay for themselves twice: the speech is synthesized while the chime rings, so the words land as it fades and you never hear the model think.

The first version sat around C6–G6, which put its second harmonic near 3 kHz — right where hearing is sharpest — and it hurt. The default now sits an octave lower and fades in over 25ms, so the note arrives rather than hits. crier chimes bell brings the bright ones back.

Why hooks, not MCP

  • A hook needs no cooperation from the model. An MCP tool only runs if the model decides to call it — so the moment it thinks "task's done," your voice loop dies silently.
  • Hooks live in the agent's settings file, which the terminal and the IDE extension share. VS Code's Claude extension can't even discover MCP servers.
  • The hook returns in ~50ms and hands playback to a detached child. Your turn never waits for a sentence to finish.
  • It writes nothing to stdout, so it cannot influence the agent's control flow. If crier breaks, your session doesn't.

The voice

Supertonic — a local ONNX model. No GPU, no network. Ten voices, 31 languages.

Korean actually works, which is worth stating because most open TTS silently doesn't. Kokoro-82M has no Korean at all — its maintainer dropped it. Chatterbox Multilingual reports 70.9% CER on Korean, a number Resemble AI publishes themselves. Piper has no ko_KR voice. XTTS-v2 speaks Korean under a non-commercial license from a company that shut down in 2024, so it can never be relicensed. Supertonic is the one that reads useEffect as "useEffect" inside a Korean sentence, instead of transliterating it into something unrecognizable.

Measured on an M-series Mac: RTF 0.159 — a 5-second sentence takes ~0.8s to synthesize. (Supertonic's marketing claims 0.012; that did not reproduce here.) Fast enough, because the chime covers it.

Agents

Agent Turn end + text Permission + which command
Claude Code
Codex CLI
Gemini CLI
Cursor

Claude Code and Codex use identical event names and payloads, so they share a hook. Gemini and Cursor say the same things in different words — announce.py normalizes them. Adding an agent is a routing-table entry in bin/wire.py, not an integration.

Agents that expose only a contentless ping (Aider) can't carry a brief. crier is the wrong tool there; use peon-ping.

Config

~/.crier/config.json — re-read on every event, so edits apply immediately.

lang tone voice call_name name_chance who it is
events.* what it speaks
cooldown_sec max_chars how much
earcons.enabled gap_ms the bell
marker the prefix the agent writes its spoken line behind

License

MIT.

Supertonic's code is MIT; its model weights are OpenRAIL-M, which carries use restrictions. crier never vendors them — they're fetched to your cache on first run, so that license lands on you directly rather than riding in on a clone.

About

Your coding agent tells you what happened — out loud, in one sentence, only when it matters. Korean/English/Japanese, fully local, no API key. Claude Code · Codex · Gemini · Cursor.

Topics

Resources

License

Stars

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors