Hooks

Hooks cung cấp một hệ thống mở rộng theo sự kiện để tự động hóa các hành động khi có lệnh hoặc sự kiện từ agent. Hooks được tự động phát hiện từ các thư mục và có thể quản lý qua lệnh CLI, tương tự như cách Skills hoạt động trong OpenClaw.

Làm quen

Hooks là các script nhỏ chạy khi có sự kiện xảy ra. Có hai loại:

  • Hooks (trang này): chạy bên trong Gateway khi có sự kiện từ agent, như /new, /reset, /stop, hoặc các lifecycle events.
  • Webhooks: các HTTP webhook bên ngoài cho phép hệ thống khác kích hoạt công việc trong OpenClaw. Xem Webhook Hooks hoặc dùng openclaw webhooks để xem các lệnh hỗ trợ Gmail.

Hooks cũng có thể được đóng gói bên trong plugins; xem Plugins.

Các trường hợp sử dụng phổ biến:

  • Lưu snapshot bộ nhớ khi các bạn reset một session
  • Giữ audit trail của các lệnh để troubleshooting hoặc tuân thủ quy định
  • Kích hoạt tự động hóa tiếp theo khi session bắt đầu hoặc kết thúc
  • Ghi file vào agent workspace hoặc gọi API bên ngoài khi có sự kiện

Nếu các bạn có thể viết một hàm TypeScript nhỏ, các bạn có thể viết hook. Hooks được phát hiện tự động, và các bạn bật hoặc tắt chúng qua CLI.

Tổng quan

Hệ thống hooks cho phép các bạn:

  • Lưu context của session vào bộ nhớ khi gọi /new
  • Log tất cả lệnh để audit
  • Kích hoạt tự động hóa tùy chỉnh trên các sự kiện lifecycle của agent
  • Mở rộng hành vi của OpenClaw mà không cần sửa code lõi

Bắt đầu

Bundled Hooks

OpenClaw đi kèm với bốn bundled hooks được tự động phát hiện:

  • 💾 session-memory: Lưu context của session vào agent workspace (mặc định ~/.openclaw/workspace/memory/) khi các bạn gọi /new
  • 📝 command-logger: Log tất cả sự kiện lệnh vào ~/.openclaw/logs/commands.log
  • 🚀 boot-md: Chạy BOOT.md khi gateway khởi động (yêu cầu bật internal hooks)
  • 😈 soul-evil: Hoán đổi nội dung SOUL.md được inject với SOUL_EVIL.md trong cửa sổ purge hoặc ngẫu nhiên

Liệt kê các hooks có sẵn:

openclaw hooks list

Bật một hook:

openclaw hooks enable session-memory

Kiểm tra trạng thái hook:

openclaw hooks check

Xem thông tin chi tiết:

openclaw hooks info session-memory

Onboarding

Trong quá trình onboarding (openclaw onboard), các bạn sẽ được nhắc bật các hooks được khuyên dùng. Wizard tự động phát hiện các hooks đủ điều kiện và hiển thị để chọn.

Hook Discovery

Hooks được tự động phát hiện từ ba thư mục (theo thứ tự ưu tiên):

  1. Workspace hooks: <workspace>/hooks/ (theo từng agent, ưu tiên cao nhất)
  2. Managed hooks: ~/.openclaw/hooks/ (do người dùng cài đặt, dùng chung giữa các workspaces)
  3. Bundled hooks: <openclaw>/dist/hooks/bundled/ (đi kèm với OpenClaw)

Các thư mục managed hook có thể là single hook hoặc hook pack (thư mục package).

Mỗi hook là một thư mục chứa:

my-hook/
├── HOOK.md          # Metadata + tài liệu
└── handler.ts       # Triển khai handler

Hook Packs (npm/archives)

Hook packs là các npm package chuẩn export một hoặc nhiều hooks qua openclaw.hooks trong package.json. Cài đặt chúng bằng:

openclaw hooks install <path-or-spec>

Ví dụ package.json:

{
  "name": "@acme/my-hooks",
  "version": "0.1.0",
  "openclaw": {
    "hooks": ["./hooks/my-hook", "./hooks/other-hook"]
  }
}

Mỗi entry trỏ đến một thư mục hook chứa HOOK.mdhandler.ts (hoặc index.ts). Hook packs có thể đi kèm dependencies; chúng sẽ được cài đặt dưới ~/.openclaw/hooks/<id>.

Cấu trúc Hook

Định dạng HOOK.md

File HOOK.md chứa metadata trong YAML frontmatter cộng với tài liệu Markdown:

---
name: my-hook
description: "Mô tả ngắn về hook này làm gì"
homepage: https://docs.openclaw.ai/hooks#my-hook
metadata:
  { "openclaw": { "emoji": "🔗", "events": ["command:new"], "requires": { "bins": ["node"] } } }
---

# My Hook

Tài liệu chi tiết ở đây...

## Nó làm gì

- Lắng nghe lệnh `/new`
- Thực hiện một hành động nào đó
- Log kết quả

## Yêu cầu

- Phải cài đặt Node.js

## Cấu hình

Không cần cấu hình.

Các trường Metadata

Object metadata.openclaw hỗ trợ:

  • emoji: Emoji hiển thị cho CLI (ví dụ: "💾")
  • events: Mảng các sự kiện để lắng nghe (ví dụ: ["command:new", "command:reset"])
  • export: Named export để sử dụng (mặc định là "default")
  • homepage: URL tài liệu
  • requires: Yêu cầu tùy chọn
    • bins: Các binary bắt buộc trên PATH (ví dụ: ["git", "node"])
    • anyBins: Ít nhất một trong các binary này phải có
    • env: Các biến môi trường bắt buộc
    • config: Các đường dẫn config bắt buộc (ví dụ: ["workspace.dir"])
    • os: Các nền tảng bắt buộc (ví dụ: ["darwin", "linux"])
  • always: Bỏ qua kiểm tra điều kiện (boolean)
  • install: Phương thức cài đặt (cho bundled hooks: [{"id":"bundled","kind":"bundled"}])

Triển khai Handler

File handler.ts export một hàm HookHandler:

import type { HookHandler } from "../../src/hooks/hooks.js";

const myHandler: HookHandler = async (event) => {
  // Chỉ kích hoạt với lệnh 'new'
  if (event.type !== "command" || event.action !== "new") {
    return;
  }

  console.log(`[my-hook] Lệnh New được kích hoạt`);
  console.log(`  Session: ${event.sessionKey}`);
  console.log(`  Timestamp: ${event.timestamp.toISOString()}`);

  // Logic tùy chỉnh của các bạn ở đây

  // Tùy chọn gửi tin nhắn cho người dùng
  event.messages.push("✨ Hook của mình đã chạy!");
};

export default myHandler;

Event Context

Mỗi event bao gồm:

{
  type: 'command' | 'session' | 'agent' | 'gateway',
  action: string,              // ví dụ: 'new', 'reset', 'stop'
  sessionKey: string,          // Định danh session
  timestamp: Date,             // Khi sự kiện xảy ra
  messages: string[],          // Push tin nhắn vào đây để gửi cho người dùng
  context: {
    sessionEntry?: SessionEntry,
    sessionId?: string,
    sessionFile?: string,
    commandSource?: string,    // ví dụ: 'whatsapp', 'telegram'
    senderId?: string,
    workspaceDir?: string,
    bootstrapFiles?: WorkspaceBootstrapFile[],
    cfg?: OpenClawConfig
  }
}

Các loại Event

Command Events

Được kích hoạt khi có lệnh agent:

  • command: Tất cả sự kiện lệnh (listener chung)
  • command:new: Khi gọi lệnh /new
  • command:reset: Khi gọi lệnh /reset
  • command:stop: Khi gọi lệnh /stop

Agent Events

  • agent:bootstrap: Trước khi các file bootstrap của workspace được inject (hooks có thể thay đổi context.bootstrapFiles)

Gateway Events

Được kích hoạt khi gateway khởi động:

  • gateway:startup: Sau khi channels khởi động và hooks được load

Tool Result Hooks (Plugin API)

Các hooks này không phải là event-stream listeners; chúng cho phép plugins điều chỉnh tool results một cách đồng bộ trước khi OpenClaw lưu chúng.

  • tool_result_persist: biến đổi tool results trước khi chúng được ghi vào session transcript. Phải đồng bộ; trả về payload tool result đã cập nhật hoặc undefined để giữ nguyên. Xem Agent Loop.

Future Events

Các loại event dự kiến:

  • session:start: Khi một session mới bắt đầu
  • session:end: Khi một session kết thúc
  • agent:error: Khi agent gặp lỗi
  • message:sent: Khi một tin nhắn được gửi
  • message:received: Khi một tin nhắn được nhận

Tạo Custom Hooks

1. Chọn vị trí

  • Workspace hooks (<workspace>/hooks/): Theo từng agent, ưu tiên cao nhất
  • Managed hooks (~/.openclaw/hooks/): Dùng chung giữa các workspaces

2. Tạo cấu trúc thư mục

mkdir -p ~/.openclaw/hooks/my-hook
cd ~/.openclaw/hooks/my-hook

3. Tạo HOOK.md

---
name: my-hook
description: "Làm điều gì đó hữu ích"
metadata: { "openclaw": { "emoji": "🎯", "events": ["command:new"] } }
---

# My Custom Hook

Hook này làm điều gì đó hữu ích khi các bạn gọi `/new`.

4. Tạo handler.ts

import type { HookHandler } from "../../src/hooks/hooks.js";

const handler: HookHandler = async (event) => {
  if (event.type !== "command" || event.action !== "new") {
    return;
  }

  console.log("[my-hook] Đang chạy!");
  // Logic của các bạn ở đây
};

export default handler;

5. Bật và test

# Xác minh hook được phát hiện
openclaw hooks list

# Bật nó
openclaw hooks enable my-hook

# Restart gateway process (restart menu bar app trên macOS, hoặc restart dev process)

# Kích hoạt sự kiện
# Gửi /new qua messaging channel

Cấu hình

Định dạng Config mới (Khuyên dùng)

{
  "hooks": {
    "internal": {
      "enabled": true,
      "entries": {
        "session-memory": { "enabled": true },
        "command-logger": { "enabled": false }
      }
    }
  }
}

Cấu hình theo từng Hook

Hooks có thể có cấu hình tùy chỉnh:

{
  "hooks": {
    "internal": {
      "enabled": true,
      "entries": {
        "my-hook": {
          "enabled": true,
          "env": {
            "MY_CUSTOM_VAR": "value"
          }
        }
      }
    }
  }
}

Extra Directories

Load hooks từ các thư mục bổ sung:

{
  "hooks": {
    "internal": {
      "enabled": true,
      "load": {
        "extraDirs": ["/path/to/more/hooks"]
      }
    }
  }
}

Định dạng Config cũ (Vẫn được hỗ trợ)

Định dạng config cũ vẫn hoạt động để tương thích ngược:

{
  "hooks": {
    "internal": {
      "enabled": true,
      "handlers": [
        {
          "event": "command:new",
          "module": "./hooks/handlers/my-handler.ts",
          "export": "default"
        }
      ]
    }
  }
}

Migration: Dùng hệ thống discovery mới cho các hooks mới. Legacy handlers được load sau các directory-based hooks.

Lệnh CLI

Liệt kê Hooks

# Liệt kê tất cả hooks
openclaw hooks list

# Chỉ hiển thị hooks đủ điều kiện
openclaw hooks list --eligible

# Output chi tiết (hiển thị yêu cầu còn thiếu)
openclaw hooks list --verbose

# Output JSON
openclaw hooks list --json

Thông tin Hook

# Hiển thị thông tin chi tiết về một hook
openclaw hooks info session-memory

# Output JSON
openclaw hooks info session-memory --json

Kiểm tra điều kiện

# Hiển thị tóm tắt điều kiện
openclaw hooks check

# Output JSON
openclaw hooks check --json

Bật/Tắt

# Bật một hook
openclaw hooks enable session-memory

# Tắt một hook
openclaw hooks disable command-logger

Bundled Hooks

session-memory

Lưu context của session vào bộ nhớ khi các bạn gọi /new.

Events: command:new

Yêu cầu: workspace.dir phải được cấu hình

Output: <workspace>/memory/YYYY-MM-DD-slug.md (mặc định ~/.openclaw/workspace)

Nó làm gì:

  1. Dùng session entry trước khi reset để tìm transcript đúng
  2. Trích xuất 15 dòng cuối của cuộc hội thoại
  3. Dùng LLM để tạo filename slug mô tả
  4. Lưu metadata của session vào file memory có ngày tháng

Ví dụ output:

# Session: 2026-01-16 14:30:00 UTC

- **Session Key**: agent:main:main
- **Session ID**: abc123def456
- **Source**: telegram

Ví dụ filename:

  • 2026-01-16-vendor-pitch.md
  • 2026-01-16-api-design.md
  • 2026-01-16-1430.md (fallback timestamp nếu tạo slug thất bại)

Bật:

openclaw hooks enable session-memory

command-logger

Log tất cả sự kiện lệnh vào file audit tập trung.

Events: command

Yêu cầu: Không có

Output: ~/.openclaw/logs/commands.log

Nó làm gì:

  1. Capture chi tiết sự kiện (command action, timestamp, session key, sender ID, source)
  2. Append vào file log ở định dạng JSONL
  3. Chạy im lặng ở background

Ví dụ log entries:

{"timestamp":"2026-01-16T14:30:00.000Z","action":"new","sessionKey":"agent:main:main","senderId":"+1234567890","source":"telegram"}
{"timestamp":"2026-01-16T15:45:22.000Z","action":"stop","sessionKey":"agent:main:main","senderId":"[email protected]","source":"whatsapp"}

Xem logs:

# Xem các lệnh gần đây
tail -n 20 ~/.openclaw/logs/commands.log

# Pretty-print với jq
cat ~/.openclaw/logs/commands.log | jq .

# Lọc theo action
grep '"action":"new"' ~/.openclaw/logs/commands.log | jq .

Bật:

openclaw hooks enable command-logger

soul-evil

Hoán đổi nội dung SOUL.md được inject với SOUL_EVIL.md trong cửa sổ purge hoặc ngẫu nhiên.

Events: agent:bootstrap

Docs: SOUL Evil Hook

Output: Không ghi file; hoán đổi chỉ xảy ra trong bộ nhớ.

Bật:

openclaw hooks enable soul-evil

Config:

{
  "hooks": {
    "internal": {
      "enabled": true,
      "entries": {
        "soul-evil": {
          "enabled": true,
          "file": "SOUL_EVIL.md",
          "chance": 0.1,
          "purge": { "at": "21:00", "duration": "15m" }
        }
      }
    }
  }
}

boot-md

Chạy BOOT.md khi gateway khởi động (sau khi channels khởi động). Internal hooks phải được bật để hook này chạy.

Events: gateway:startup

Yêu cầu: workspace.dir phải được cấu hình

Nó làm gì:

  1. Đọc BOOT.md từ workspace của các bạn
  2. Chạy các hướng dẫn qua agent runner
  3. Gửi bất kỳ tin nhắn outbound nào được yêu cầu qua message tool

Bật:

openclaw hooks enable boot-md

Best Practices

Giữ Handlers nhanh

Hooks chạy trong quá trình xử lý lệnh. Giữ chúng nhẹ:

// ✓ Tốt - async work, trả về ngay lập tức
const handler: HookHandler = async (event) => {
  void processInBackground(event); // Fire and forget
};

// ✗ Không tốt - chặn xử lý lệnh
const handler: HookHandler = async (event) => {
  await slowDatabaseQuery(event);
  await evenSlowerAPICall(event);
};

Xử lý lỗi một cách khéo léo

Luôn wrap các thao tác rủi ro:

const handler: HookHandler = async (event) => {
  try {
    await riskyOperation(event);
  } catch (err) {
    console.error("[my-handler] Thất bại:", err instanceof Error ? err.message : String(err));
    // Không throw - để các handlers khác chạy
  }
};

Lọc Events sớm

Return sớm nếu event không liên quan:

const handler: HookHandler = async (event) => {
  // Chỉ xử lý lệnh 'new'
  if (event.type !== "command" || event.action !== "new") {
    return;
  }

  // Logic của các bạn ở đây
};

Dùng Event Keys cụ thể

Chỉ định các events chính xác trong metadata khi có thể:

metadata: { "openclaw": { "events": ["command:new"] } } # Cụ thể

Thay vì:

metadata: { "openclaw": { "events": ["command"] } } # Chung - overhead nhiều hơn

Debugging

Bật Hook Logging

Gateway log việc load hook khi khởi động:

Registered hook: session-memory -> command:new
Registered hook: command-logger -> command
Registered hook: boot-md -> gateway:startup

Kiểm tra Discovery

Liệt kê tất cả hooks được phát hiện:

openclaw hooks list --verbose

Kiểm tra Registration

Trong handler của các bạn, log khi nó được gọi:

const handler: HookHandler = async (event) => {
  console.log("[my-handler] Được kích hoạt:", event.type, event.action);
  // Logic của các bạn
};

Xác minh điều kiện

Kiểm tra tại sao một hook không đủ điều kiện:

openclaw hooks info my-hook

Tìm các yêu cầu còn thiếu trong output.

Testing

Gateway Logs

Theo dõi gateway logs để xem hook execution:

# macOS
./scripts/clawlog.sh -f

# Các nền tảng khác
tail -f ~/.openclaw/gateway.log

Test Hooks trực tiếp

Test các handlers của các bạn một cách độc lập:

import { test } from "vitest";
import { createHookEvent } from "./src/hooks/hooks.js";
import myHandler from "./hooks/my-hook/handler.js";

test("my handler hoạt động", async () => {
  const event = createHookEvent("command", "new", "test-session", {
    foo: "bar",
  });

  await myHandler(event);

  // Assert side effects
});

Kiến trúc

Các thành phần lõi

  • src/hooks/types.ts: Định nghĩa type
  • src/hooks/workspace.ts: Quét và load thư mục
  • src/hooks/frontmatter.ts: Parse metadata HOOK.md
  • src/hooks/config.ts: Kiểm tra điều kiện
  • src/hooks/hooks-status.ts: Báo cáo trạng thái
  • src/hooks/loader.ts: Dynamic module loader
  • src/cli/hooks-cli.ts: Lệnh CLI
  • src/gateway/server-startup.ts: Load hooks khi gateway khởi động
  • src/auto-reply/reply/commands-core.ts: Kích hoạt command events

Discovery Flow

Gateway startup

Quét thư mục (workspace → managed → bundled)

Parse các file HOOK.md

Kiểm tra điều kiện (bins, env, config, os)

Load handlers từ các hooks đủ điều kiện

Đăng ký handlers cho events

Event Flow

User gửi /new

Validation lệnh

Tạo hook event

Kích hoạt hook (tất cả handlers đã đăng ký)

Xử lý lệnh tiếp tục

Session reset

Troubleshooting

Hook không được phát hiện

  1. Kiểm tra cấu trúc thư mục:

    ls -la ~/.openclaw/hooks/my-hook/
    # Phải hiển thị: HOOK.md, handler.ts
  2. Xác minh định dạng HOOK.md:

    cat ~/.openclaw/hooks/my-hook/HOOK.md
    # Phải có YAML frontmatter với name và metadata
  3. Liệt kê tất cả hooks được phát hiện:

    openclaw hooks list

Hook không đủ điều kiện

Kiểm tra yêu cầu:

openclaw hooks info my-hook

Tìm những thứ còn thiếu:

  • Binaries (kiểm tra PATH)
  • Biến môi trường
  • Giá trị config
  • Tương thích OS

Hook không chạy

  1. Xác minh hook đã được bật:

    openclaw hooks list
    # Phải hiển thị ✓ bên cạnh các hooks đã bật
  2. Restart gateway process để hooks reload.

  3. Kiểm tra gateway logs để tìm lỗi:

    ./scripts/clawlog.sh | grep hook

Lỗi Handler

Kiểm tra lỗi TypeScript/import:

# Test import trực tiếp
node -e "import('./path/to/handler.ts').then(console.log)"

Migration Guide

Từ Legacy Config sang Discovery

Trước:

{
  "hooks": {
    "internal": {
      "enabled": true,
      "handlers": [
        {
          "event": "command:new",
          "module": "./hooks/handlers/my-handler.ts"
        }
      ]
    }
  }
}

Sau:

  1. Tạo thư mục hook:

    mkdir -p ~/.openclaw/hooks/my-hook
    mv ./hooks/handlers/my-handler.ts ~/.openclaw/hooks/my-hook/handler.ts
  2. Tạo HOOK.md:

    ---
    name: my-hook
    description: "Hook tùy chỉnh của mình"
    metadata: { "openclaw": { "emoji": "🎯", "events": ["command:new"] } }
    ---
    
    # My Hook
    
    Làm điều gì đó hữu ích.
  3. Cập nhật config:

    {
      "hooks": {
        "internal": {
          "enabled": true,
          "entries": {
            "my-hook": { "enabled": true }
          }
        }
      }
    }
  4. Xác minh và restart gateway process:

    openclaw hooks list
    # Phải hiển thị: 🎯 my-hook ✓

Lợi ích của migration:

  • Tự động discovery
  • Quản lý CLI
  • Kiểm tra điều kiện
  • Tài liệu tốt hơn
  • Cấu trúc nhất quán

Xem thêm