# CHO CLAUDE ĐỌC: Bước 15. Lam Khuê: trợ lý giọng nói trên Lark điều khiển Claude

> Tài liệu này viết cho Claude Code của học viên. Người học chỉ cần dán câu lệnh bên dưới vào Claude, Claude đọc file này rồi làm.
> Thuộc hệ thống triển khai AI 20 bước của Trương Minh Kiên. Trang bước này: https://trienkhailamkhue.truongminhkien.vn

## Việc cần làm

Nhắn hoặc nói trong Lark, Claude trên máy bạn làm việc rồi trả lời. Kèm bộ canh tự khởi động lại.

Câu lệnh học viên dán vào Claude:

```
Tải gói https://trienkhailamkhue.truongminhkien.vn/lam-khue-lark.zip, giải nén, đọc CHO-CLAUDE-DOC.md rồi cài Lam Khuê trên Lark cho tôi
```

## Luật khi làm

1. Đọc hết file này, kể cả phần bẫy, trước khi chạy lệnh nào.
2. Việc cần mật khẩu, mã OTP, token hay thanh toán thì dừng lại để học viên tự làm, không nhập hộ.
3. Không xoá dữ liệu, bản ghi DNS hay file cũ của học viên. Chỉ thêm.
4. Khoá bí mật chỉ nằm trong `.env` (đã có trong `.gitignore`), không ghi vào mã, wiki hay kết quả.
5. Xong mỗi bước thì kiểm tra thật (chạy thử, đọc lại) rồi mới báo xong.
6. Gói này chạy trên máy của học viên, không phải máy người soạn. Mọi đường dẫn tính từ thư mục giải nén hoặc thư mục vault của học viên; hỏi học viên nếu cần. Skill nào nhắc tới file `output/...` hay trang `wiki/...` mà vault học viên chưa có thì đó chỉ là nguồn tham khảo của người soạn: bỏ qua, dùng nội dung ngay trong skill. Riêng `wiki/concepts/bo-mau-thuong-hieu.md`: nếu chưa có, chép từ `mau/bo-mau-thuong-hieu.md` trong gói rồi hỏi học viên để điền.

## Skill trong gói

- (gói này không kèm skill riêng)

Cách cài skill: chép từng thư mục trong `.claude/skills/` của gói vào `.claude/skills/` của vault Obsidian (bước 1). Tên thư mục phải trùng tên skill, file chính tên `SKILL.md`.

## Cách cài đặt từng bước (làm theo thứ tự)

### CHO CLAUDE ĐỌC — cài Lam Khuê (nói/gõ trong Lark → Claude làm việc), có kinh nghiệm chạy thật

> Bạn là Claude Code trên máy một người mới. Họ vừa dán: *"Tải gói trên rồi cài Lam Khuê cho tôi…"*.
> Lam Khuê là gói của **Trương Minh Kiên** (mã nằm ngay trong gói zip này)
> — gói zip có đủ mã (`scripts/`, `docs/`), kèm **bẫy đã trả giá sau 6 tuần
> chạy thật** và các luật an toàn. Đọc tệp này trước, rồi mới đọc `docs/PROMPT-TRIEN-KHAI.md` trong gói.

## 0. Nói thẳng với người dùng trước khi cài

1. Lam Khuê là **một tiến trình chạy nền có toàn quyền trên máy** (`bypassPermissions`): ai ra lệnh được
   cho Lam Khuê là điều khiển được máy. Vì thế Lam Khuê **chỉ nghe chủ** (`OWNER_OPEN_ID`) trong **một nhóm
   điều khiển** riêng. Không bao giờ mở cho nhóm có người lạ.
2. Cần: tài khoản Lark + quyền tạo app (gói `tro-ly-lark` đã làm), Node ≥ 18, Python/uv, ffmpeg, Claude
   Code; card NVIDIA thì nghe tốt, không có vẫn chạy (model `small`, nghe tiếng Việt kém hơn).
3. Ba việc **người dùng phải tự bấm**: tạo/publish app Lark + bật event `im.message.receive_v1`;
   đăng nhập `lark-cli --as bot`; tạo nhóm điều khiển và thêm bot vào.

## 1. Lấy gói

Giải nén gói `https://trienkhailamkhue.truongminhkien.vn/lam-khue-lark.zip` vào một thư mục tên `LAMKHUE` (gói đã có đủ mã, không cần GitHub, không cần git), rồi `cd LAMKHUE`.
Thư mục đặt ở đường dẫn **không dấu, không khoảng trắng** (ví dụ `D:\LAMKHUE`).

## 2. Làm theo `docs/PROMPT-TRIEN-KHAI.md` trong gói — 7 bước, thứ tự không đổi

Đọc `itto.yaml` + `docs/00-PHIEU-INPUT.md` → kiểm công cụ nền → `scripts/install.ps1` →
`node scripts/whoami.mjs` lấy `OWNER_OPEN_ID` + `CONTROL_CHAT_ID` → điền `.env` (`BRAIN_ROOT` = thư mục
Bộ Não Thứ 2 của họ) → **cổng chốt** `node check-itto.mjs` và `node scripts/check-setup.mjs` phải XANH →
bàn giao: **người dùng tự bấm** `scripts/start.ps1` (Claude không tự bật tiến trình thường trú).

Sự cố thường gặp của chính tác giả: `docs/05-su-co.md`. Thử không tốn token: `DRY_RUN=true`.

## 3. Bẫy đã trả giá thêm (06/08 → 20/09/2026) — tác giả không có

| # | Bẫy | Cách xử |
|---|---|---|
| 1 | **Bot nói được nhưng không nghe được trong nhóm**: bộ nghe chạy `--filter user` (chỉ tin riêng) và khoá cứng một `CONTROL_CHAT_ID` | Đó là thiết kế an toàn, không phải lỗi. Muốn Lam Khuê nghe trong nhóm → **giữ nguyên lớp lọc `uidFrom === ownerUid`**; nếu không, ai được thêm vào nhóm cũng ra lệnh được máy |
| 2 | Tin dạng **thẻ chia sẻ link** (post/card) bị bộ nghe vứt bỏ → gửi link cho Lam Khuê thì im | Gửi link dạng chữ thường, hoặc gõ kèm chữ |
| 3 | Một cú gọi **chết lặng lẽ**: log ghi nhận lệnh rồi im, không thấy tiến trình Claude nào sinh ra | Đọc `scripts/logs/`; kiểm `claude --version` chạy được từ đúng user; kiểm `BRAIN_ROOT` tồn tại |
| 4 | Lam Khuê chạy trên **bộ não khác** với bộ não người dùng đang nghĩ (`BRAIN_ROOT` trỏ nhầm) | Mỗi bộ não một `BRAIN_ROOT`; ghi rõ trong `tom-luat.txt` Lam Khuê làm việc ở đâu |
| 5 | Chạy ẩn cửa sổ bằng `.vbs` (`chay-an.vbs`) → người dùng không biết máy đang chạy gì, không tắt được | Chạy **cửa sổ có tiêu đề** để tự thu nhỏ/tắt; watchdog theo `docs/04` |
| 6 | Trả lời **chậm 20–60 giây** vì mọi câu đều đi qua Claude Code | Thiết kế ba làn: làn 0 câu chờ 1–2 giây · làn 1 gọi thẳng API cho câu thường · làn 2 Claude Code cho việc thật. Chưa có khoá API thì chấp nhận chậm, nói trước với người dùng |
| 7 | Token/hồ sơ lark-cli của bot bị xoá bởi `config init` khi cài thứ khác | Không bao giờ chạy `config init` khi đã có hồ sơ (xem gói `tro-ly-lark`); bot câm = kiểm `lark-cli profile list` |
| 8 | Lam Khuê xưng hô, ngôn ngữ lung tung | Viết `scripts/tom-luat.txt`: tiếng Việt tuyệt đối, xưng "em", làm việc đúng `CLAUDE.md` của bộ não, không bịa |

## 4. Nghiệm thu

1. `DRY_RUN=true`: gõ "ping" trong nhóm điều khiển → Lam Khuê vọng lại trong < 5 giây.
2. `DRY_RUN=false`: nói một câu 10 giây "liệt kê 3 tệp mới nhất trong nguon/" → Lam Khuê trả lời bằng giọng, nội dung đúng.
3. Người khác (không phải chủ) nhắn trong nhóm → Lam Khuê **im**. Đây là phép thử quan trọng nhất.

## 5. Báo cáo cuối (khuôn)

```
✅ Lam Khuê chạy tại <đường dẫn> · nhóm điều khiển: <tên> · chủ: <tên người dùng>
🧪 ping < 5s ✔ · lệnh giọng ✔ · người lạ nhắn → im ✔
⚠️ Nhắc: người dùng tự bấm start.ps1; không mở cho nhóm lạ; không dùng .vbs ẩn cửa sổ
```


## Hướng dẫn chi tiết và các bẫy đã gặp

(Bản đầy đủ có hình và nút bấm: https://trienkhailamkhue.truongminhkien.vn)

Yêu cầu trước khi bắt đầu

- Đã xong [Bước 4: Cài Lark](https://trienkhailark.truongminhkien.vn/)
- Máy tính chạy được liên tục (server riêng, hoặc máy cá nhân bật xuyên suốt giờ làm việc)

## Cách hoạt động (nói với Claude AI để nó tự dựng)

1

### Tạo 1 App Lark riêng làm "Bot"

Yêu cầu Claude AI: *"Tạo cho tôi 1 Lark Custom App tên \[tên trợ lý của bạn\], có quyền gửi/nhận tin nhắn (im:message, im:message:send_as_bot), bật nhận sự kiện tin nhắn qua Long Connection."* Claude tự vào Lark Developer Console qua lark-cli để tạo.

2

### Tạo thêm 1 Custom Bot Webhook (bắt buộc, hay bị bỏ sót)

Ngoài App Bot ở bước 1, cần thêm 1 "Custom Bot" riêng để gửi tin nhắn CHỮ trả lời về đúng nhóm/hội thoại: mở nhóm chat trên Lark → "..." → Group Bots (Bot nhóm) → thêm Custom Bot mới → khi tạo, **tắt hẳn mục "Đặt xác nhận chữ ký"** (nếu không tắt, code gửi tin sẽ bị từ chối vì không ký đúng) → copy lấy webhook URL, giữ riêng không đưa vào chat/ghi vào file công khai (URL này ai có cũng gửi tin được vào nhóm).

3

### Lấy code thật (đã chạy sẵn cho Trương Minh Kiên, không phải để AI viết lại)

Đây là code Node.js thật đang chạy 24/7 trên máy tôi — đưa thẳng link này cho Claude AI:

https://trienkhailamkhue.truongminhkien.vn/lam-khue-lark.zip

Nói: *"Đọc repo ở link trên rồi cài cho tôi, làm theo README.md và docs/00-PHIEU-INPUT.md."* Bộ não của trợ lý là `scripts/lark-voice-bridge.mjs`: lắng nghe tin gửi tới App Bot vừa tạo → mỗi tin mới tự chạy Claude Code trả lời → gửi kết quả ngược lại qua webhook đã tạo ở Bước 2. Copy `scripts/.env.example` thành `.env`, điền `OWNER_OPEN_ID` + `CONTROL_CHAT_ID` (chạy `node whoami.mjs`, nhắn 1 tin vào nhóm để lấy) và `LARK_WEBHOOK` (webhook Bước 2).

4

### Đặt lịch tự chạy 24/7

Yêu cầu Claude AI đăng ký `scripts/start.ps1` (đã có sẵn trong repo) thành 1 tác vụ nền chạy khi khởi động máy (Windows: Task Scheduler; Mac/Linux: launchd/systemd). Không cần mở cửa sổ Terminal, script tự chạy ẩn.

5

### Gắn "người canh gác" (watchdog) — đã có sẵn trong repo

`scripts/watchdog.mjs` đã viết sẵn: tự chạy lặp lại, kiểm tra bridge ở Bước 3 còn "nhịp tim" thật không (quá 35 phút không cập nhật coi như treo) — chết hoặc treo thì tự khởi động lại, báo qua chính kênh Lark. Chỉ cần đăng ký nó thành tác vụ nền lặp lại mỗi vài phút.

## Điền 1 lần, dán khối lệnh cho Claude AI

Điền 3 ô lấy ở Bước 1-2 phía trên, khối lệnh bên dưới tự ghép lại — copy rồi dán thẳng vào Claude AI, không cần tự viết prompt.

OWNER_OPEN_ID bắt buộc Chạy `node whoami.mjs`, nhắn 1 tin vào nhóm điều khiển — nó tự in ra giá trị này.

CONTROL_CHAT_ID bắt buộc In ra cùng lúc với OWNER_OPEN_ID ở bước trên.

LARK_WEBHOOK bắt buộc bí mật Webhook Custom Bot đã tạo ở Bước 2 — giữ riêng, ai có link này cũng gửi tin vào nhóm được.

BRAIN_ROOT tuỳ chọn Thư mục bạn cho Claude toàn quyền thao tác khi nhận lệnh qua Lark.

CLAUDE_MODEL sonnet — mặc định, cân bằng opus — thông minh hơn, đắt hơn haiku — rẻ và nhanh Đổi sau trong `.env` không cần cài lại gì.

Mọi giá trị bạn gõ chỉ nằm trong trình duyệt — trang không gửi đi đâu, không lưu lại. Đóng tab là mất.

Ẩn bí mật khi chia sẻ màn hình

Xoá hết

Khối lệnh — dán vào Claude AI

Sao chép khối lệnh

Chưa điền ô nào — khối lệnh đang ở dạng mẫu.

## ⚠ Bẫy đã gặp thật + cách gỡ

1\. Một câu hỏi ra 3-4 câu trả lời giống hệt nhau

Bật script chạy nền nhiều lần (khởi động tay + watchdog tự khởi động lại đè lên nhau) mà không kiểm tra bản cũ đã tắt chưa → 2-3 tiến trình cùng lắng nghe, mỗi tin nhắn bị trả lời nhiều lần.

**Cách gỡ:** mỗi lần script khởi động, phải tự kiểm tra "có bản nào đang chạy sẵn không" (đọc file ghi mã tiến trình cũ, kiểm tra tiến trình đó còn sống thật không) — nếu còn sống thì tự thoát ngay, không chạy chồng lên.

2\. "Người canh gác" tự dưng im lặng suốt nhiều giờ, không phát hiện được sự cố

Lịch chạy lặp lại mỗi vài phút (trên Windows Task Scheduler) bị thiếu 1 cấu hình bắt buộc là "thời hạn lặp" — không set thì lịch chỉ chạy đều trong khoảng 1-2 tiếng đầu rồi tự dừng hẳn, không báo lỗi gì, chỉ lặng lẽ ngừng canh gác.

**Cách gỡ:** khi tạo lịch lặp lại, luôn đặt rõ "thời hạn lặp" là 1 con số rất lớn (ví dụ 10 năm) thay vì để trống — để trống không có nghĩa là "chạy mãi mãi" như trực giác thường nghĩ. Đặt đúng rồi thì lịch tự sống lại cả sau khi khởi động lại máy, không cần thêm trigger "chạy khi khởi động" riêng.

3\. Trợ lý vẫn "sống" (canh gác báo ổn) nhưng thực ra đã ngừng trả lời tin nhắn

Nếu "còn sống" chỉ được đo bằng việc tiến trình chưa bị tắt, thì phần lắng nghe tin nhắn bên trong có thể đã treo âm thầm (mất kết nối mạng, kẹt hàng chờ) mà tiến trình cha vẫn chạy — canh gác không phát hiện ra.

**Cách gỡ:** để trợ lý tự ghi lại "nhịp tim" (1 dòng thời gian) mỗi khi THỰC SỰ nhận được sự kiện gì đó, không phải chỉ 1 bộ đếm giờ độc lập chạy song song — canh gác kiểm tra nhịp tim đó, quá **35 phút** không cập nhật thì coi như treo, tự kill và khởi động lại.

Bước tiếp theo

Đã có trợ lý AI qua Lark, sang bước kế tiếp: làm y hệt vậy nhưng qua Zalo — vì không phải khách hàng nào cũng dùng Lark.

[Sang bước 16: Cài Lam Khuê (Zalo) →](https://trienkhaizalo.truongminhkien.vn/)

