Endpoint base
Authentication
Mọi route ngoại trừ /, /dashboard, /health yêu cầu header:
X-Webhook-Token: <token đọc từ ~/wp-site/.webhook-token>
Có thể bật thêm HMAC body signing qua env WEBHOOK_HMAC_SECRET (header X-Signature: sha256=…).
Routes
| Method | Path | Auth | Mô tả |
| GET | / | — | Dashboard HTML này |
| GET | /health | — | {"ok":true,"queued":N} |
| GET | /sites | token | Danh sách site đã index + pulled + session_id |
| GET | /sessions | token | Map {site: session_uuid} hiện tại |
| DELETE | /sessions/<site> | token | Reset session 1 site (task tiếp theo sẽ tạo mới) |
| GET | /tasks | token | running_list (TẤT CẢ task đang chạy song song) + queued + 20 task gần đây. (running = task đầu, giữ tương thích) |
| GET | /tasks/<id> | token | Metadata + status + exit_code + session_id + 8 KB cuối log. Thêm ?full=1 → trả trọn log (cap 5 MB) cho chế độ View |
| GET | /models | token | Model mặc định (default/default_label) + danh sách model chọn được (models) |
| POST | /run | token | Gửi prompt vào queue |
| POST | /tasks/<id>/cancel | token | Huỷ task đang chạy hoặc xếp hàng (SIGTERM → SIGKILL sau 3s) |
| POST | /tasks/cancel-all | token | Huỷ MỌI task đang chạy + xếp hàng → {"ok":true,"canceled":N} (nút "Hủy tất cả" trên dashboard) |
| GET | /.well-known/agent-card.json | — | A2A Agent Card — discovery cho agent khác |
| POST | /a2a | token | A2A JSON-RPC 2.0: message/send, tasks/get, tasks/cancel |
Session policy
1 site = 1 session duy nhất. Listener tự lưu map {site: session_uuid} ở ~/wp-site/.sessions.json. Mỗi task site=X tự đính kèm --resume <uuid của X> để claude khôi phục toàn bộ context. Không cần truyền resume_session trong body — cứ gửi prompt + site là claude tiếp tục đúng hội thoại cũ.
Task đầu tiên cho 1 site → claude tự tạo session mới → listener extract session_id từ log và lưu lại. Các task sau auto-resume.
Muốn bắt đầu hội thoại mới cho site? DELETE /sessions/<site> (hoặc bấm 🔄 Reset trên dashboard).
POST /run — body schema
| Field | Bắt buộc | Tác dụng |
prompt | ✅ | Prompt cho claude -p |
site | — | Tên domain WP. Listener tra folder-index-server.csv, auto-pull vào ~/wp-site/projects/<site> nếu chưa có rồi cd vào đó. Bỏ trống → cwd = ~/wp-site |
model | — | Model AI: alias opus/sonnet/haiku hoặc full id (claude-opus-4-8). Trống → model mặc định cấu hình (CLAUDE_MODEL); cả hai trống → model HIỆN TẠI của Claude CLI (không ép --model) |
id | — | Task ID. Tự gen <unix>-<rand6> nếu trống |
mcp_config | — | Path file JSON cho --mcp-config (string hoặc array) |
strict_mcp | — | true → --strict-mcp-config (chỉ dùng config trên, bỏ user-scope) |
resume_session | — | UUID override thủ công — bỏ trống = dùng session lưu sẵn của site (auto-resume). Chỉ điền khi muốn dùng session khác |
continue_recent | — | true → --continue (tiếp session gần nhất cùng cwd, khác cơ chế auto theo site) |
fork_session | — | Khi resume/continue, tạo session ID mới (giữ history). Khi BẬT, map site→session KHÔNG được cập nhật — site vẫn dùng session gốc cho task tiếp theo |
Response của /run
HTTP 202
{"accepted": true, "id": "1780...-a3f9", "site": "avico.monademo.com", "queued": 0}
Response của /tasks (rút gọn)
{
"running": { ... } | null, // task đầu (giữ tương thích)
"running_list": [ // TẤT CẢ task chạy song song
{
"id": "...", "site": "...",
"started_at": "2026-06-01 15:00:00",
"prompt_preview": "...",
"log_tail": "...2 KB cuối log..."
}
],
"queued": [
{"id": "...", "site": "...", "prompt_preview": "..."}
],
"recent": [
{
"id": "...", "site": "...",
"status": "done | failed | running | unknown",
"exit_code": 0 | 130 | null,
"session_id": "<uuid hoặc null>",
"size": 1234,
"mtime": "2026-06-01 14:45:40"
}
]
}
Status & exit code
| status | exit_code | nghĩa |
done | 0 | Claude trả về thành công |
failed | ≠ 0 | Claude trả error code, hoặc lỗi sớm (ko có index, traversal, pull fail) |
failed | 130 | Bị huỷ bởi user qua /cancel (xếp hàng hoặc đang chạy) |
running | null | Task đang chạy (file log chưa có # exit code) |
unknown | null | File log trống hoặc đọc lỗi |
🔗 A2A (Agent2Agent)
Agent này là A2A Server: agent/orchestrator khác discovery qua GET /.well-known/agent-card.json (không cần token) rồi gửi task qua POST /a2a theo JSON-RPC 2.0 (cần token). Endpoint REST cũ (/run, /tasks) vẫn chạy song song.
site + prompt + model + lite truyền trong A2A Message dạng DataPart {site, prompt, model, lite} (hoặc TextPart làm prompt + metadata.{wp_site, model}). model tuỳ chọn — trống dùng model mặc định.
lite: true → chạy claude TỐI GIẢN (không nạp MCP/skill/tool/extra-args) → khởi động nhanh (~10s thay vì 60-75s). Dùng cho call văn bản thuần (classify/dispatch/soạn câu trả lời khi core fallback AI sang executor). Việc cần tool (sửa site, web-research) thì để lite trống/false.
| method | params | kết quả |
| message/send | {message:{parts:[{kind:"data",data:{site,prompt,model?}}]}} | Task state=submitted |
| tasks/get | {id} | Task + artifact log_tail |
| tasks/cancel | {id} | Task state=canceled |
Map status → A2A TaskState: queued→submitted, running→working, done→completed, failed→failed, cancel→canceled.
Curl examples
Gửi 1 task mới (auto-pull nếu chưa có; model tuỳ chọn — trống = model hiện tại của Claude):
Tiếp tục hội thoại của task trước:
Huỷ 1 task:
Xem snapshot tasks + watch:
🤖 Playbook — 8-step pipeline tự động
Template prompt dùng cho automation: gửi cho claude qua /run kèm site, claude sẽ tự đọc task Jira, sửa code, push lên server, chạy test, rồi comment + chuyển status Jira. Bạn chỉ cần gắn mã task Jira (vd AVICO-12) vào prompt.
Concurrency — pool 2 làn + chống flood
Worker chạy pool song song (mặc định WP_MAX_CONCURRENT_TASKS=4). Ràng buộc:
- Cùng site KHÔNG chạy đồng thời (chung session claude/git/DB của site đó) → 2 task cùng site tự tuần tự; khác site (hoặc site rỗng) chạy song song.
- 2 làn: task có site (việc WP thật) luôn được chừa slot; task site rỗng = call completion (classify/dispatch/web-research do core fallback A2A) bị giới hạn đồng thời (
WP_COMPLETION_MAX_CONCURRENT=2) → flood completion KHÔNG giành hết slot của việc thật.
- Load-shedding: hàng đợi completion vượt
WP_COMPLETION_QUEUE_CAP=6 → /run & /a2a trả 429 (A2A: JSON-RPC error) để caller fail-fast thay vì xếp hàng vô tận.
Storage layout
~/wp-site/ # WP_LOCAL_ROOT (config + script + logs)
├── wp-sync.sh
├── claude-webhook.py
├── dashboard.html
├── folder-index-server.csv
├── .webhook-token # chmod 600
├── webhook-logs/ # log từng task: <id>.log + webhook.log chính
└── projects/ # WP_SITES_DIR (1 folder / site)
└── <site>/wp-content/...
Env vars chính
WEBHOOK_PORT | port nội bộ (9000) |
WEBHOOK_TOKEN | token; nếu trống đọc ~/wp-site/.webhook-token |
WEBHOOK_HMAC_SECRET | bật HMAC body signing |
CLAUDE_BIN | đường dẫn claude CLI |
CLAUDE_CWD | workspace root (default ~/wp-site) |
WP_SITES_DIR | folder chứa site đã pull (default $CWD/projects) |
CLAUDE_PERMISSION | permission mode (default bypassPermissions) |
CLAUDE_ALLOWED_TOOLS | danh sách tool; trống = all |
CLAUDE_MCP_CONFIG | file MCP config mặc định |
CLAUDE_EXTRA_ARGS | flags thêm |
CLAUDE_MODEL | model mặc định khi task không truyền; trống = model hiện tại của CLI |
CLAUDE_MODELS | danh sách model cho GET /models (CSV); mặc định opus,sonnet,haiku |
WP_MAX_CONCURRENT_TASKS | số task chạy song song tối đa (1–16, default 4) |
WP_COMPLETION_MAX_CONCURRENT | trần đồng thời cho task completion (site rỗng); < max để chừa slot việc-có-site (default 2) |
WP_COMPLETION_QUEUE_CAP | hàng đợi completion tối đa, vượt → trả 429 (default 6) |