When your AI coding session finishes, debrief uses Apple Intelligence to summarize what was accomplished and reads it aloud in the JARVIS voice — entirely on-device.
Session ends
→ last assistant message
→ Apple Intelligence (on-device, apple-fm-sdk)
→ one-sentence summary
→ JARVIS reads it aloud (Piper + afplay)
→ fallback: pyttsx3 Daniel if model not found
No cloud. No API keys. Runs on the Neural Engine.
| macOS | 26.0+ |
| Hardware | Apple Silicon (M1 or later) |
| Apple Intelligence | Enabled — System Settings → Apple Intelligence & Siri |
| Xcode | 26.0+ (install from developer.apple.com/xcode, agree to license in app) |
| Python | 3.10+ |
| jq | brew install jq |
git clone https://github.com/your-username/debrief
cd debrief
./install.shDownloads the medium JARVIS voice (~63.5 MB). For the higher quality model (~114 MB):
./install.sh --highWhat install.sh does:
- Verifies all requirements
- Creates
.venv/inside the repo - Installs
piper-tts,apple-fm-sdk,pyttsx3 - Downloads the JARVIS voice model to
models/ - Makes
hooks/tts_notify.shexecutable
# With Apple Intelligence summarization (recommended)
.venv/bin/python3 tts_demo.py \
--smart \
--text "Refactored the authentication module, added JWT support, and all 42 tests are passing."
# Plain JARVIS TTS — no summarization
.venv/bin/python3 tts_demo.py --text "Systems online. How may I assist you?"
# Force medium model even if high is present
.venv/bin/python3 tts_demo.py --medium --text "Hello."debrief works with Claude Code, Codex, and OpenCode. Pick the tools you use.
Project-scoped (fires only when working inside this repo — already configured, nothing to do):
The .claude/settings.json in this repo is ready to go.
Global (fires in every Claude Code session):
- Copy the template:
cp hooks/claude/settings.json ~/.claude/settings.json - Edit the
commandvalue — replace/PATH/TO/debriefwith the absolute path to this repo:"command": "/Users/yourname/debrief/hooks/tts_notify.sh"
- If
~/.claude/settings.jsonalready exists with other hooks, merge thehooks.Stoparray rather than overwriting the whole file.
-
Enable the hooks feature flag — add to
~/.codex/config.toml(create if it doesn't exist):[features] codex_hooks = true
A ready-made snippet is at
hooks/codex/config.toml. -
Copy the hook config:
cp hooks/codex/hooks.json ~/.codex/hooks.json -
Edit the
commandvalue:"command": "/Users/yourname/debrief/hooks/tts_notify.sh"
-
If
~/.codex/hooks.jsonalready exists, merge thehooks.Stoparray into your existing file.
- Copy the plugin:
cp hooks/opencode/tts-notify.js ~/.config/opencode/plugins/debrief-notify.js - Edit the two path constants at the top of the file:
const VENV_PYTHON = "/Users/yourname/debrief/.venv/bin/python3" const TTS_SCRIPT = "/Users/yourname/debrief/tts_demo.py"
| Model | Size | Flag |
|---|---|---|
jarvis-medium |
63.5 MB | ./install.sh (default) |
jarvis-high |
114 MB | ./install.sh --high |
Both are British English, trained to emulate JARVIS from the Iron Man films.
Source: jgkawell/jarvis on Hugging Face (MIT licensed).
debrief auto-detects whichever model is present. If both are downloaded, high is preferred. Pass --medium to tts_demo.py to force the medium model.
Apple Intelligence unavailable → speak "Task complete."
Piper model not found → pyttsx3 Daniel (en-GB, built-in)
No assistant text captured → silent (OpenCode plugin only)
Voice rate and volume — edit tts_demo.py:
engine.setProperty("rate", 175) # words per minute
engine.setProperty("volume", 1.0) # 0.0 – 1.0List all available pyttsx3 voices (to change the fallback voice):
import pyttsx3
engine = pyttsx3.init()
for i, v in enumerate(engine.getProperty("voices")):
print(i, v.id)debrief/
├── install.sh # environment setup
├── tts_demo.py # core: summarize → speak
├── .claude/
│ └── settings.json # project-scoped Claude Code hook (ready to use)
├── hooks/
│ ├── tts_notify.sh # shared hook script (Claude Code + Codex)
│ ├── claude/
│ │ └── settings.json # global Claude Code template
│ ├── codex/
│ │ ├── hooks.json # Codex hook config
│ │ └── config.toml # Codex feature flag
│ └── opencode/
│ └── tts-notify.js # OpenCode plugin
├── models/ # gitignored — populated by install.sh
└── .venv/ # gitignored — created by install.sh