Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

vokomarov/claude-code-approvals

Open more actions menu

Repository files navigation

claude-code-approvals

A macOS daemon that intercepts Claude Code permission prompts and escalates them to your phone when you're away from your laptop.

When Claude Code asks for permission to run a command, this tool can:

  1. Show a macOS notification with Approve / Deny buttons (at t=15s by default)
  2. Send a Telegram message with inline buttons if the notification goes unanswered (at t=30s)
  3. Auto-apply a policy (deny or approve) after a hard timeout — or wait indefinitely if no timeout is set

Toggle the whole system on or off with a single command — no Claude Code restart required.


How it works

Claude Code (per permission request)
    │
    │  spawns: claude-code-approvals hook
    ▼
hook process  (reads stdin JSON, POSTs to daemon)
    │
    │  POST /api/permission  (blocking)
    ▼
claude-code-approvals daemon  (localhost:9753)
    │
    ├── t=15s ──► macOS notification  (alerter)
    │               [Approve] [Deny]
    │
    └── t=30s ──► Telegram message
                    [✅ Approve] [❌ Deny]

The daemon runs as a launchd service. Claude Code invokes the hook subcommand as a subprocess for each permission request; the hook blocks until the daemon returns a decision. When the daemon is disabled (cc off), it returns immediately and Claude Code falls back to its built-in interactive prompt.


Requirements

  • macOS (Apple Silicon or Intel)
  • Go 1.21+
  • alerter: brew install vjeantet/tap/alerter
  • A Telegram bot token and chat ID (see setup)

Installation

1. Clone and build

git clone https://github.com/vokomarov/claude-code-approvals.git ~/go/src/github.com/vokomarov/claude-code-approvals
cd ~/go/src/github.com/vokomarov/claude-code-approvals
make install

Make sure ~/go/bin is in your PATH:

echo 'export PATH="$HOME/go/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc

2. Configure

cp config.example.yaml config.yml

Edit config.yml and set your Telegram credentials at minimum:

telegram:
  bot_token: "YOUR_BOT_TOKEN"
  chat_id: 123456789

paths:
  claude_settings: "~/.claude/settings.json"  # adjust to your actual path

config.yml is gitignored — it stays local.

3. Configure the launchd service file

Open launchd/com.vokomarov.cc-approvals.plist and update the paths to match your environment:

<!-- Path to the installed binary -->
<string>/Users/YOUR_USERNAME/go/bin/claude-code-approvals</string>

<!-- Working directory (where config.yml lives) -->
<string>/Users/YOUR_USERNAME/go/src/github.com/vokomarov/claude-code-approvals</string>

<!-- Log output paths -->
<string>/Users/YOUR_USERNAME/go/src/github.com/vokomarov/claude-code-approvals/logs/cc-approvals.log</string>
<string>/Users/YOUR_USERNAME/go/src/github.com/vokomarov/claude-code-approvals/logs/cc-approvals-error.log</string>

Replace YOUR_USERNAME with your macOS username (whoami).

4. Install the launchd service

make service-install

Verify the daemon is running:

make health
# → {"status":"ok"}

5. Register the hook in Claude Code settings (one-time)

claude-code-approvals install

This writes the PermissionRequest hook entry to your Claude Code settings.json. You only need to do this once — it persists across daemon restarts and session restarts.


Telegram bot setup

  1. Open Telegram and message @BotFather/newbot
  2. Copy the bot token into config.yml under telegram.bot_token
  3. Send any message to your new bot, then open:
    https://api.telegram.org/bot<TOKEN>/getUpdates
    
    Read result[0].message.chat.id and set it as telegram.chat_id

Daily usage

claude-code-approvals on    # enable interception (no session restart needed)
claude-code-approvals off   # disable — Claude Code uses its built-in prompt
Situation Command
Check daemon is alive make health
View logs make logs
View error logs make logs-err
Restart daemon make service-reload
Stop daemon make service-stop

After making code changes:

make reinstall   # rebuild, update plist, restart daemon, health check

Configuration reference

Key Default Description
timeouts.macos_notification_seconds 15 Delay before macOS notification. 0 = skip
timeouts.telegram_notification_seconds 30 Delay before Telegram message. 0 = skip
timeouts.total_timeout_seconds 300 Hard ceiling in seconds; 0 = wait indefinitely (no timeout)
timeouts.timeout_policy deny Decision on hard timeout: deny or approve. Only used when total_timeout_seconds > 0
telegram.message_template (built-in) Go text/template; vars: .SessionID .ToolName .ToolInput .CreatedAt
paths.claude_settings Path to Claude Code settings.json modified by install/uninstall
daemon.port 9753 Port for HTTP API and health endpoint

Validation rules:

  • If both notification timeouts are non-zero, telegram_notification_seconds must exceed macos_notification_seconds by at least 5
  • total_timeout_seconds: 0 means wait indefinitely; any positive value must exceed the largest non-zero notification timeout
  • timeout_policy is required only when total_timeout_seconds > 0
  • On daemon shutdown, all pending requests are always denied regardless of timeout_policy
  • telegram.bot_token and chat_id are always required

Timeout-only mode (no notifications, auto-deny after 60s):

timeouts:
  macos_notification_seconds: 0
  telegram_notification_seconds: 0
  total_timeout_seconds: 60
  timeout_policy: deny

Claude Code settings

After claude-code-approvals install, your settings.json contains:

{
  "hooks": {
    "PermissionRequest": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "/Users/you/go/bin/claude-code-approvals hook"
          }
        ]
      }
    ]
  }
}

claude-code-approvals uninstall removes this entry. The on/off commands do not modify settings.json — they toggle the daemon's state via HTTP.


Development

make test        # run tests
make test-race   # run tests with race detector
make vet         # go vet
make lint        # golangci-lint (requires golangci-lint installed)

License

MIT

About

A tool to notify remotely about Claude Code approval request when you away

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages

Morty Proxy This is a proxified and sanitized view of the page, visit original site.