---
title: "Thông báo Claude Code trên điện thoại qua Hooks"
description: "Nhận cảnh báo trên điện thoại khi Claude Code cần cấp quyền hoặc xong việc. Cấu hình hook sao chép là dùng được với hook Notification, Stop và webhook."
date: 2026-10-02
author: Nooc
authorAvatarLink: /images/avatars/nooc.webp
authorLink: https://nooc.me
tags:
  - Claude Code
  - agent lập trình AI
  - hooks
  - thông báo điện thoại
  - webhook
  - năng suất lập trình viên
---

# Thông báo Claude Code trên điện thoại: biết khi nào nó cần bạn hoặc đã xong

Claude Code dừng lại trong hai tình huống đáng chú ý: nó bị chặn để chờ bạn (một yêu cầu cấp quyền, một câu hỏi), hoặc nó đã làm xong. Nếu bạn không nhìn vào terminal, hai trường hợp này trông y hệt nhau — không có gì xảy ra, và phiên làm việc nằm im cho đến khi bạn quay lại. Cách khắc phục là một hook: vài dòng trong `settings.json` gửi webhook tới điện thoại của bạn ngay khi một trong hai tình huống xảy ra.

Hướng dẫn này cho bạn cấu hình để sao chép, giải thích nên dùng hook event nào cho tình huống nào, và đi qua các chi tiết giúp nó chạy ổn định: đọc input của hook, cách đặt dấu nháy trong shell, và tránh bị ngập trong thông báo.

## Hook nào cho tình huống nào

Claude Code chạy hook theo các sự kiện trong vòng đời của nó. Hai sự kiện giải quyết vấn đề này ([tài liệu tham chiếu hooks](https://code.claude.com/docs/en/hooks)):

| Bạn muốn biết khi… | Hook event | Matcher / bộ lọc |
| --- | --- | --- |
| Claude đang chờ quyết định cấp quyền | `Notification` | `permission_prompt` |
| Claude đã rảnh và đang chờ input của bạn | `Notification` | `idle_prompt` |
| Claude phản hồi xong | `Stop` | không cần |

`matcher` của hook `Notification` lọc theo loại thông báo, nên bạn chọn được chính xác thông báo nào đến điện thoại. Input đến dưới dạng JSON qua stdin và gồm `notification_type`, `message`, `cwd` và `session_id`. Hook `Notification` không thể chặn hay thay đổi bất cứ thứ gì — chúng chỉ quan sát, đúng thứ bạn cần ở đây.

Input của `Stop` có `last_assistant_message`, đoạn văn bản cuối cùng Claude tạo ra. Đó là một dòng tóm tắt miễn phí cho thông báo.

## Bạn cần gì

- Echobell trên điện thoại ([App Store](https://apps.apple.com/app/apple-store/id6743597198?pt=128151925&ct=blog-claude-code-phone-notifications-vi&mt=8) / [Google Play](https://play.google.com/store/apps/details?id=one.echobell.echobellandroid))
- `curl` và `jq` trên máy chạy Claude Code
- Hai phút

## Bước 1 — Tạo hai kênh

Đừng gửi mọi thứ vào một kênh. Trong Echobell, hãy tạo:

- **Claude Blocked**, loại **Nhạy thời gian (Time Sensitive)** hoặc **Cuộc gọi** — cho các yêu cầu cấp quyền, khi agent đang đứng yên và mỗi phút đều là lãng phí, cả tài nguyên tính toán lẫn thời gian của bạn
- **Claude Done**, loại **Bình thường** — một thông báo đẩy thông thường, đọc lúc nào cũng được

Sao chép URL webhook của từng kênh. Nó có dạng `https://hook.echobell.one/t/<channel-token>`. Hãy coi nó như mật khẩu: ai có nó cũng có thể làm điện thoại của bạn đổ chuông.

Lưu cả hai dưới dạng biến môi trường để chúng không bao giờ nằm trong file cấu hình được commit:

```bash
export ECHOBELL_CLAUDE_BLOCKED_URL="https://hook.echobell.one/t/<blocked-token>"
export ECHOBELL_CLAUDE_DONE_URL="https://hook.echobell.one/t/<done-token>"
```

Đặt chúng trong shell profile để Claude Code kế thừa.

## Bước 2 — Thêm hooks

Thêm đoạn sau vào `~/.claude/settings.json` để áp dụng cho mọi dự án, hoặc vào `.claude/settings.local.json` cho một repository:

```json
{
  "hooks": {
    "Notification": [
      {
        "matcher": "permission_prompt",
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{title: \"Claude cần cấp quyền\", body: .message, project: (.cwd | split(\"/\") | last)}' | curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- \"$ECHOBELL_CLAUDE_BLOCKED_URL\""
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "jq -c '{title: \"Claude đã xong\", body: (.last_assistant_message // \"Xong\" | .[0:200]), project: (.cwd | split(\"/\") | last)}' | curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- \"$ECHOBELL_CLAUDE_DONE_URL\""
          }
        ]
      }
    ]
  }
}
```

Từng phần làm gì:

- `jq -c '{...}'` đọc JSON của hook từ stdin và dựng một payload nhỏ, để Echobell nhận đúng các trường bạn muốn thay vì toàn bộ tài liệu của hook.
- `.cwd | split("/") | last` biến `/home/me/code/api` thành `api`, nên thông báo cho biết dự án nào đang yêu cầu.
- `.[0:200]` cắt ngắn tin nhắn cuối. Nội dung thông báo bị worker của Echobell giới hạn ở 1500 byte, và màn hình khóa hiển thị còn ít hơn nhiều.
- `-m 10` đặt cho `curl` thời gian chờ 10 giây để sự cố mạng không bao giờ khiến Claude Code phải đợi hook của bạn.

Echobell hiển thị các key bạn gửi thông qua template của kênh, và kênh mới chưa có template nào đọc chúng — hãy đặt trong phần cài đặt kênh: template tiêu đề `{{title}}`, template nội dung `{{body}}`. Thêm `{{project}}` vào một trong hai nếu muốn hiện tên dự án, ví dụ `{{title}} ({{project}})`.

## Bước 3 — Kiểm thử mà không cần chờ yêu cầu thật

Chạy thủ công cùng pipeline với một payload hook giả:

```bash
echo '{"message":"Claude needs your permission to use Bash","cwd":"/home/me/code/api","notification_type":"permission_prompt"}' \
  | jq -c '{title: "Claude cần cấp quyền", body: .message, project: (.cwd | split("/") | last)}' \
  | curl -sS -m 10 -X POST -H 'Content-Type: application/json' -d @- "$ECHOBELL_CLAUDE_BLOCKED_URL"
```

Nếu điện thoại sáng lên, phía Echobell đã ổn và vấn đề còn lại nằm ở cách Claude Code đọc cấu hình. Trong Claude Code, chạy `/hooks` để xác nhận hook đã được nạp; thay đổi cấu hình khi phiên đang chạy có thể cần mở menu hooks hoặc khởi động lại mới có hiệu lực.

## Bước 4 — Cho kênh blocked đổ chuông

Thông báo đẩy thua chế độ Không làm phiền. Kênh **Cuộc gọi** hành xử như một cuộc gọi đến và xuyên qua chế độ Tập trung của iOS, điều đặc biệt quan trọng khi bạn giao một tác vụ dài rồi đi mất cả buổi tối. Nếu bạn chỉ muốn bị làm phiền với một số yêu cầu, hãy lọc bằng điều kiện kênh của Echobell trên các biến bạn gửi, ví dụ `project == "api"`, thay vì sửa hook. Danh sách biến đầy đủ có trong [tài liệu tham chiếu điều kiện](/vi/docs/conditions).

## Tránh ngập thông báo

Một phiên bận rộn có thể kích hoạt nhiều sự kiện `Stop` — mỗi phản hồi đều kết thúc bằng một sự kiện. Ba cách để giữ tín hiệu có ý nghĩa:

- **Đừng gửi `Stop` tới kênh đổ chuông.** Hoàn thành không khẩn cấp; hãy để ở loại Bình thường.
- **Dùng `idle_prompt` thay cho `Stop`** nếu bạn chỉ muốn biết khi Claude đã dừng và đang chờ bạn, thay vì sau mỗi phản hồi.
- **Thu hẹp theo dự án** bằng một điều kiện, để repository thử nghiệm không báo cho bạn chút nào.

## Chạy Claude Code từ xa hoặc trong CI

Cách tiếp cận này cũng hoạt động trong môi trường cloud hoặc từ xa, vì hook chỉ là một yêu cầu HTTPS đi ra. Không có gì cần truy cập được từ internet. Hãy đặt hai biến môi trường trong secrets của môi trường thay vì shell profile, và thông báo sẽ đến điện thoại bạn dù phiên chạy ở đâu.

## Khắc phục sự cố

**Không có gì đến, và bài kiểm thử thủ công cũng thất bại.** Kiểm tra biến URL đã được đặt trong shell khởi chạy Claude Code chưa: `echo "$ECHOBELL_CLAUDE_BLOCKED_URL"`. Biến rỗng khiến `curl` thất bại âm thầm.

**Kiểm thử thủ công chạy được nhưng hook không kích hoạt.** Xác nhận lại matcher: `permission_prompt` và `idle_prompt` là hai giá trị khác nhau, và matcher không khớp thì đơn giản là không bao giờ chạy. Chạy `/hooks` và kiểm tra JSON hợp lệ — một dấu phẩy thừa ở cuối sẽ vô hiệu hóa toàn bộ hook trong file cấu hình đó.

**Nội dung thông báo trống.** Bộ lọc `jq` tham chiếu một trường không tồn tại với sự kiện đó. `message` có trong input của `Notification`; `last_assistant_message` có trong input của `Stop`. Dùng `//` để cung cấp giá trị mặc định, như trong cấu hình ở trên.

**Kích hoạt quá thường xuyên.** Xem mục ở trên — chuyển từ `Stop` sang `idle_prompt`, hoặc thêm điều kiện.

## Câu hỏi thường gặp

### Làm sao nhận thông báo khi Claude Code cần cấp quyền?

Thêm một hook `Notification` với matcher `permission_prompt` gửi webhook tới một kênh. Echobell biến yêu cầu đó thành thông báo đẩy hoặc cảnh báo kiểu cuộc gọi trên điện thoại của bạn.

### Làm sao biết Claude Code đã xong một tác vụ?

Thêm một hook `Stop`. Nó chạy khi Claude phản hồi xong, và input của nó có `last_assistant_message`, bạn có thể dùng làm nội dung thông báo.

### Thông báo có thể xuyên qua chế độ Không làm phiền không?

Có, nếu kênh nhận là kênh Cuộc gọi. Nó hành xử như một cuộc gọi đến, loại mà chế độ Tập trung của iOS cho đi qua. Thông báo đẩy thường từ bất kỳ ứng dụng nào thì không.

### Cách này có dùng được với Claude Code trên web hoặc phiên từ xa không?

Có. Hook chỉ tạo một yêu cầu HTTPS đi ra, nên hoạt động ở bất cứ đâu phiên có thể kết nối internet. Hãy cung cấp URL kênh qua secrets của môi trường.

### Đặt URL webhook trong settings.json có an toàn không?

Nên dùng biến môi trường như ở trên để token không bị commit vào repository. Nếu bị lộ, hãy tạo kênh mới và bỏ kênh cũ.

## Tổng kết

Hai kênh, hai hook và một pipeline `jq | curl`: kênh **Cuộc gọi** hoặc Nhạy thời gian cho `permission_prompt`, kênh Bình thường cho `Stop`. Sau đó bạn có thể giao một tác vụ agent dài, rời khỏi phòng, và chỉ bị gọi lại khi agent thực sự cần bạn.

[Tải Echobell cho iPhone](https://apps.apple.com/app/apple-store/id6743597198?pt=128151925&ct=blog-claude-code-phone-notifications-vi&mt=8) hoặc [tải trên Google Play](https://play.google.com/store/apps/details?id=one.echobell.echobellandroid), rồi chạy bài kiểm thử thủ công ở trên trước khi giao cho nó một tác vụ dài.

## Bài viết liên quan

- [Biến các cổng phê duyệt của agent thành cuộc gọi điện thoại](/vi/blog/ai-agent-human-in-the-loop-alerts)
- [Nhận thông báo khi một lệnh terminal chạy lâu hoàn tất](/vi/blog/notify-when-terminal-command-finishes)
- [Hướng dẫn tích hợp webhook](/vi/docs/webhook)
- [Tài liệu tham chiếu điều kiện kênh](/vi/docs/conditions)
- [Xuyên qua chế độ Tập trung của iOS cho cảnh báo quan trọng](/vi/blog/how-to-bypass-ios-focus-mode-for-critical-alerts)
