Route AI coding-assistant approval and input prompts to a phone call through Vapi. Works with Claude Code and OpenAI Codex.
- Say
activate hands freeto start,deactivate hands freeto stop. - The assistant's permission requests and end-of-turn questions ring your phone via Vapi.
- Approve with spoken
approve/denyor keypad1/2. Free-form questions accept any spoken answer.
- Claude Code, or Codex with hooks enabled
- Node.js 18+ and Python 3.9+
- A Vapi private API key, phone number id, and a destination number in E.164 format (e.g.
+15555550123)
npx @parcha/hands-free install # auto-detects Claude Code vs Codex
# or pick one explicitly:
npx @parcha/hands-free install --harness=claude-code
npx @parcha/hands-free install --harness=codexAuto-detection prefers ~/.claude when present, otherwise ~/.codex. Then fill in the env file the installer dropped:
# Claude Code:
$EDITOR ~/.claude/hands-free/.env
# Codex:
$EDITOR ~/.codex/hands-free/.envRestart your assistant. Verify with:
npx @parcha/hands-free doctorThe installer drops a single Python hook script (hands_free_hook.py) under the harness's home directory and wires it into three hook events:
| Event | Claude Code | Codex | What it does |
|---|---|---|---|
UserPromptSubmit |
✓ | ✓ | Detects activate/deactivate hands free and toggles state. |
| Permission gate | PreToolUse |
PermissionRequest |
When active, places an outbound Vapi call asking for approve/deny. |
Stop |
✓ | ✓ | When the final assistant message looks like a question, calls you for a spoken answer and feeds the transcript back as the user's reply. |
The same hook script runs under both harnesses; it shapes its stdout decision payload based on HANDS_FREE_HARNESS (set by the installer in the hook command).
<harness home>/ # ~/.claude or ~/.codex
├── hands-free/
│ ├── .env # your Vapi credentials (chmod 600)
│ ├── state.json # active/inactive flag
│ └── scripts/hands_free_hook.py
├── skills/hands-free/
│ ├── SKILL.md
│ ├── agents/openai.yaml
│ └── scripts/hands_free_hook.py
├── settings.json # Claude Code only — hooks block
├── hooks.json # Codex only
└── config.toml # Codex only — adds [features] codex_hooks = true
- API credentials live only in
<harness home>/hands-free/.env(mode 600). - The default voice is Vapi
Elliot; overrideVAPI_VOICE_IDin the env file. - Prompt text and spoken replies are sent to Vapi. Review your Vapi retention settings before using with sensitive code.
- The hook never reads or modifies anything outside its own subtree; existing entries in
settings.json/hooks.jsonare preserved.
If you'd rather wire it up yourself, copy scripts/hands_free_hook.py to a location your assistant can run, and use one of the templates in examples/:
examples/claude-settings.json— Claude Code hooks blockexamples/hooks.json— Codex hooks blockexamples/config.toml— Codexcodex_hooks = truefeature flag
npm test
npm publish --access public