English | 中文
Real-time monitoring and observability dashboard for OpenClaw instances.
ClawPulse collects key metrics from one or more OpenClaw gateways — request latency, throughput, error rate, token usage, and channel health — stores them in a local SQLite database, surfaces them through a dark-theme web dashboard, and fires webhook alerts when thresholds are breached.
Screenshot placeholder – replace with an actual screenshot after first run
- Real-time metrics – polling every 30 s (configurable); latency, RPM, TPM, error rate, channel status
- Multi-instance – monitor any number of OpenClaw deployments from one dashboard
- Historical trends – 15 m / 1 h / 6 h / 24 h / 7 d time-range charts with bucketed averages
- Alert engine – rule-based alerts with configurable thresholds,
duration(sustained breach), and severity (warning/critical) - Webhook notifications – POST JSON to Slack, Discord, PagerDuty, Feishu, DingTalk, or any custom endpoint; fires on alert and on resolution
- Zero external dependencies – SQLite only; no Redis, no Postgres
- Docker-first – single
docker compose upto get started
# 1. Clone and enter the repo
git clone https://github.com/hidearmoon/clawpulse.git
cd clawpulse
# 2. Start ClawPulse
docker compose up -d
# 3. Open the dashboard
open http://localhost:8765Add your first OpenClaw instance via the "Add Instance" panel in the dashboard, or set it in config.yaml before starting.
# Requires Python 3.10+
pip install -e .
# Optional: copy and edit the config
cp config.example.yaml config.yaml
clawpulse --port 8765All settings can be overridden via environment variables prefixed with CLAWPULSE_.
| Variable | Default | Description |
|---|---|---|
CLAWPULSE_HOST |
0.0.0.0 |
Bind host |
CLAWPULSE_PORT |
8765 |
Bind port |
CLAWPULSE_DEBUG |
false |
Enable debug logging |
CLAWPULSE_DB_PATH |
clawpulse.db |
SQLite file path |
CLAWPULSE_DATA_RETENTION_DAYS |
7 |
Days to keep metric history |
CLAWPULSE_COLLECT_INTERVAL_SECONDS |
30 |
Collection interval (min 5) |
CLAWPULSE_COLLECT_TIMEOUT_SECONDS |
10 |
Per-request HTTP timeout |
CLAWPULSE_WEBHOOK_URL |
(empty) | Global default webhook URL |
CLAWPULSE_WEBHOOK_HEADERS |
{} |
Global webhook headers (JSON) |
CLAWPULSE_KEY_<INSTANCE_ID_UPPER> |
(empty) | API key for a persisted instance |
API key env var example: for an instance with id prod, set CLAWPULSE_KEY_PROD=sk-xxx.
server:
port: 8765
database:
retention_days: 30
collector:
interval_seconds: 15
alerting:
webhook_url: "https://hooks.slack.com/services/xxx/yyy/zzz"
instances:
- id: "prod"
name: "Production"
base_url: "http://openclaw.example.com:3000"
api_key: "" # prefer CLAWPULSE_KEY_PROD env varSee config.example.yaml for the full annotated reference.
All responses use the envelope: {"success": bool, "data": ..., "message": str|null}
| Method | Path | Description |
|---|---|---|
GET |
/api/instances |
List monitored instances |
POST |
/api/instances |
Add an instance |
DELETE |
/api/instances/{id} |
Remove an instance |
Add instance body:
{
"name": "Production",
"base_url": "http://openclaw.example.com:3000",
"api_key": "sk-xxxxxxxxxxxxxxxxx"
}| Method | Path | Description |
|---|---|---|
GET |
/api/metrics/realtime |
Latest value for every metric |
GET |
/api/metrics/history |
Time-bucketed history (?metric=response_latency_ms&range=1h) |
GET |
/api/metrics/summary |
Aggregate stats (?range=24h) |
| Method | Path | Description |
|---|---|---|
GET |
/api/alerts/rules |
List all alert rules |
POST |
/api/alerts/rules |
Create an alert rule |
DELETE |
/api/alerts/rules/{id} |
Delete an alert rule |
GET |
/api/alerts/states |
Current state per rule/instance |
GET |
/api/alerts/history |
Alert firing/resolved history |
Create alert rule body:
{
"name": "High latency",
"metric_name": "response_latency_ms",
"operator": ">",
"threshold": 2000,
"duration_seconds": 60,
"severity": "warning",
"instance_id": null,
"webhook_url": "https://hooks.slack.com/services/xxx/yyy/zzz",
"webhook_headers": {}
}| Method | Path | Description |
|---|---|---|
GET |
/api/health |
Liveness probe |
GET |
/docs |
Interactive Swagger UI |
curl -X POST http://localhost:8765/api/alerts/rules \
-H "Content-Type: application/json" \
-d '{
"name": "High latency",
"metric_name": "response_latency_ms",
"operator": ">",
"threshold": 2000,
"duration_seconds": 60,
"severity": "warning",
"webhook_url": "https://hooks.slack.com/services/xxx/yyy/zzz"
}'curl -X POST http://localhost:8765/api/alerts/rules \
-H "Content-Type: application/json" \
-d '{
"name": "Error rate spike",
"metric_name": "error_rate",
"operator": ">",
"threshold": 0.1,
"duration_seconds": 0,
"severity": "critical"
}'{
"event": "alert.firing",
"alert": {
"id": 1,
"name": "High latency",
"severity": "warning",
"state": "firing",
"metric_name": "response_latency_ms",
"operator": ">",
"threshold": 2000.0,
"current_value": 3241.5
},
"instance": { "id": "prod" },
"fired_at": "2025-01-15T10:23:45Z",
"timestamp": "2025-01-15T10:23:45Z"
}The same structure is sent for alert.resolved, with resolved_at instead of fired_at.
normal ──(condition met, duration=0)──► firing
normal ──(condition met, duration>0)──► pending ──(duration elapsed)──► firing
firing ──(condition cleared)──────────► resolved
resolved ──(condition met again)──────► firing
# Install in editable mode with dev dependencies
pip install -e ".[dev]"
# Run tests (excluding integration)
pytest tests/ --ignore=tests/integration -v
# Run with auto-reload
clawpulse --debug
# Lint
pip install ruff
ruff check clawpulse/clawpulse/
__init__.py # Package version
main.py # FastAPI app factory + CLI entry point
api.py # REST API routes
collector.py # Metrics collection scheduler
storage.py # SQLite layer (metrics + alert tables)
alerting.py # Alert engine + state machine
notifier.py # Webhook notification delivery
config.py # Configuration (env vars + YAML)
static/ # Frontend (dark-theme Chart.js dashboard)
tests/ # pytest suite (42+ tests)
Dockerfile
docker-compose.yml
config.example.yaml
| Metric | Source | Description |
|---|---|---|
request_total |
/api/status |
Cumulative request count |
rpm |
/api/status |
Requests per minute |
tpm |
/api/status |
Tokens per minute |
uptime_seconds |
/api/status |
Instance uptime |
today_request_count |
/api/dashboard/ |
Today's request count |
token_total |
/api/dashboard/ |
Today's total tokens |
response_latency_ms |
/api/channel/ + /api/log/ |
Average response latency (ms) |
error_rate |
/api/log/ |
Error ratio (0–1) |
channels_enabled |
/api/channel/ |
Number of enabled channels |
channels_disabled |
/api/channel/ |
Number of disabled channels |
channel_status |
/api/channel/ |
Per-channel status (labelled) |
channel_response_time_ms |
/api/channel/ |
Per-channel response time |
channel_balance |
/api/channel/ |
Per-channel balance |
MIT © OpenClaw Labs – see LICENSE
English | 中文
ClawPulse 是 OpenClaw 的实时监控与可观测性仪表盘。
它从一个或多个 OpenClaw 网关采集关键指标(请求延迟、吞吐量、错误率、Token 用量、渠道健康状态),存入本地 SQLite 数据库,通过深色主题的 Web 仪表盘展示,并在指标超出阈值时触发 Webhook 告警。
- 实时指标 – 默认每 30 秒轮询一次(可配置),覆盖延迟、RPM、TPM、错误率、渠道状态
- 多实例 – 在一个仪表盘中监控任意数量的 OpenClaw 部署
- 历史趋势 – 支持 15 分钟 / 1 小时 / 6 小时 / 24 小时 / 7 天时间范围的分桶平均折线图
- 告警引擎 – 基于规则的告警,支持阈值配置、
duration(持续触发时长)和告警级别(warning/critical) - Webhook 通知 – 向 Slack、Discord、PagerDuty、飞书、钉钉或任意自定义端点 POST JSON;告警触发和恢复时均发送通知
- 零外部依赖 – 仅使用 SQLite,无需 Redis、PostgreSQL
- Docker 优先 – 一条
docker compose up即可启动
# 1. 克隆项目
git clone https://github.com/hidearmoon/clawpulse.git
cd clawpulse
# 2. 启动 ClawPulse
docker compose up -d
# 3. 打开仪表盘
open http://localhost:8765在仪表盘的"添加实例"面板中添加你的 OpenClaw 实例,或在启动前编辑 config.yaml。
# 需要 Python 3.10+
pip install -e .
# 可选:复制并编辑配置
cp config.example.yaml config.yaml
clawpulse --port 8765所有设置均可通过 CLAWPULSE_ 前缀的环境变量覆盖。
| 变量 | 默认值 | 说明 |
|---|---|---|
CLAWPULSE_HOST |
0.0.0.0 |
监听地址 |
CLAWPULSE_PORT |
8765 |
监听端口 |
CLAWPULSE_DEBUG |
false |
开启调试日志 |
CLAWPULSE_DB_PATH |
clawpulse.db |
SQLite 文件路径 |
CLAWPULSE_DATA_RETENTION_DAYS |
7 |
指标历史保留天数 |
CLAWPULSE_COLLECT_INTERVAL_SECONDS |
30 |
采集间隔(最小 5 秒) |
CLAWPULSE_COLLECT_TIMEOUT_SECONDS |
10 |
单次 HTTP 请求超时 |
CLAWPULSE_WEBHOOK_URL |
(空) | 全局默认 Webhook 地址 |
CLAWPULSE_WEBHOOK_HEADERS |
{} |
全局 Webhook 请求头(JSON) |
CLAWPULSE_KEY_<实例ID大写> |
(空) | 已持久化实例的 API Key |
API Key 环境变量示例: 对于 id 为 prod 的实例,设置 CLAWPULSE_KEY_PROD=sk-xxx。
所有响应格式:{"success": bool, "data": ..., "message": str|null}
| 方法 | 路径 | 说明 |
|---|---|---|
GET |
/api/instances |
列出所有实例 |
POST |
/api/instances |
添加实例 |
DELETE |
/api/instances/{id} |
删除实例 |
GET |
/api/metrics/realtime |
所有指标最新值 |
GET |
/api/metrics/history |
分桶历史数据 |
GET |
/api/metrics/summary |
聚合统计 |
GET |
/api/alerts/rules |
告警规则列表 |
POST |
/api/alerts/rules |
创建告警规则 |
DELETE |
/api/alerts/rules/{id} |
删除告警规则 |
GET |
/api/alerts/states |
当前告警状态 |
GET |
/api/alerts/history |
告警历史记录 |
GET |
/api/health |
健康检查 |
GET |
/docs |
Swagger 交互文档 |
curl -X POST http://localhost:8765/api/alerts/rules \
-H "Content-Type: application/json" \
-d '{
"name": "高延迟告警",
"metric_name": "response_latency_ms",
"operator": ">",
"threshold": 2000,
"duration_seconds": 60,
"severity": "warning",
"webhook_url": "https://hooks.slack.com/services/xxx/yyy/zzz"
}'normal ──(条件满足, duration=0)──► firing
normal ──(条件满足, duration>0)──► pending ──(持续达到 duration)──► firing
firing ──(条件消失)──────────────► resolved
resolved ──(条件再次满足)──────────► firing
# 安装开发依赖
pip install -e ".[dev]"
# 运行单元测试(跳过集成测试)
pytest tests/ --ignore=tests/integration -v
# 开发模式(热重载)
clawpulse --debug
# 代码检查
pip install ruff
ruff check clawpulse/MIT © OpenClaw Labs – 见 LICENSE
