Install
openclaw skills install kami-conflict-detectionDetect physical conflicts (fighting, shoving, scuffling) between 2+ people from RTSP camera streams or local video files. Event-driven mode: the script exits immediately upon detecting a conflict (exit code 10), outputting alert JSON to stdout. OpenClaw reads the alert, reports to the user in chat, then automatically restarts the script for continuous monitoring.
openclaw skills install kami-conflict-detectionDetect physical conflicts (fighting, shoving, scuffling) between 2+ people from RTSP camera streams or local video files. Uses an event-driven architecture where OpenClaw schedules the script in a loop for continuous real-time monitoring.
┌──────────────────────────────────────────────────────────┐
│ OpenClaw Scheduling Loop │
│ │
│ 1. OpenClaw starts the script │
│ └─ .venv/bin/python conflict_detector_last.py │
│ │
│ 2. Script continuously monitors video stream │
│ ├─ YOLO: count persons in frame │
│ ├─ >= min_persons? Collect multiple frames │
│ ├─ Send frames to LLM API for conflict analysis │
│ └─ Conflict detected? │
│ ├─ No → continue monitoring │
│ └─ Yes → save video clip, output JSON, exit(10) │
│ │
│ 3. OpenClaw reads stdout alert JSON │
│ └─ Reports detection result to user in chat window │
│ │
│ 4. OpenClaw automatically restarts script → back to 1 │
└──────────────────────────────────────────────────────────┘
Use this skill when the user wants to:
bash setup.sh
This will:
.venv/ virtual environmentonnxruntime, opencv-python-headless, numpy, requestsalerts/ output directoryIdempotent — safe to run repeatedly.
python3 and python3-venv installed on the systemyolov8s-worldv2.onnx model file in the skill directory--kami_api_key or environment variable KAMI_API_KEY). If you don't have one yet, register and obtain a key at: https://kamiclaw-skill.kamihome.com, You can enjoy a free credit limit of 200 credits.setup.sh has been run at least onceBefore running this skill, confirm the following parameters with the user:
| Parameter | Default | Description |
|---|---|---|
--rtsp_url | (required) | RTSP camera URL or local video file path |
--kami_api_key | (required) | Kami API key (also via env KAMI_API_KEY). Register at https://kamiclaw-skill.kamihome.com if you don't have one,You can enjoy a free credit limit of 200 credits. |
--yolo_model | yolov8s-worldv2.onnx | YOLO model file path |
--conf_threshold | 0.25 | YOLO confidence threshold (0.0-1.0) |
--min_persons | 2 | Minimum person count to trigger LLM analysis |
--sample_interval | 1.0 | How often (seconds) to run YOLO pre-filter |
--multi_frame_count | 3 | Number of frames to collect for LLM analysis |
--multi_frame_gap | 0.5 | Time gap (seconds) between collected frames |
--buffer_seconds | 30 | Ring buffer duration (seconds) for video clip export |
--clip_before | 5 | Seconds of video to include before the conflict |
--clip_after | 5 | Seconds of video to include after the conflict |
--output_dir | alerts/ | Directory for saved video clips |
--run_time | 0 | Max single-round run time in seconds; 0 = unlimited |
--fps | 15 | Video stream frame rate |
--inbox_file | alerts/pending.jsonl | Alarm inbox file consumed by the heartbeat task to push into the chat window |
--feishu_webhook | (env FEISHU_WEBHOOK_URL) | Feishu custom bot webhook URL — alarms are pushed directly to the user's phone |
--feishu_secret | (env FEISHU_WEBHOOK_SECRET) | Feishu webhook signing secret (only if the bot has signing enabled) |
Ask the user: do any parameters need to be changed?
Create a Feishu custom bot (自定义机器人) in the target group chat, copy its webhook URL, then either:
export FEISHU_WEBHOOK_URL="https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx"
# Optional, only if the bot has "签名校验" enabled:
export FEISHU_WEBHOOK_SECRET="your_secret_here"
Or pass --feishu_webhook / --feishu_secret on the CLI. When set, every conflict alarm is POSTed to Feishu as an interactive card (title / description / timestamp / clip duration / clip path). If the env var is empty, the Feishu channel is silently skipped — detection still works.
Alarms are delivered through three independent, redundant channels so the user is notified even if one path fails:
| # | Channel | Trigger | Consumer | Guarantee |
|---|---|---|---|---|
| 1 | stdout JSON + exit(10) | On every conflict | OpenClaw reads stdout and reports in chat window, then restarts the script | Primary chat push (OpenClaw loop) |
| 2 | Inbox file alerts/pending.jsonl | On every conflict (appended) | Heartbeat task in space/HEARTBEAT.md polls the file and proactively pushes unreported alarms into chat | Fallback chat push (survives OpenClaw glitches) |
| 3 | Feishu webhook (interactive card) | On every conflict (if FEISHU_WEBHOOK_URL set) | User's phone via Feishu bot | Instant phone push, regardless of LLM / chat state |
Channels 2 and 3 mirror the design already proven in kami-suspicious-person.
Channel 1 remains the canonical driver of the OpenClaw detect-report-restart loop.
OpenClaw should execute this skill using the following loop logic:
.venv/bin/python conflict_detector_last.py \
--rtsp_url <USER_RTSP_URL> \
--kami_api_key <API_KEY> \
[other params]
| Exit Code | Meaning | OpenClaw Action |
|---|---|---|
0 | Normal exit (video ended, timeout, no event) | Report "monitoring session ended normally" to user. Optionally restart. |
10 | Event detected — conflict alert JSON on stdout | Parse stdout JSON, report alert details to user in chat, then immediately restart the script. |
1 | Runtime error | Report error to user, check logs at conflict_detector.log. |
When exit code is 10, parse the stdout JSON and report to the user like:
🥊 Physical Conflict Alert A physical conflict has been detected: Two people are engaged in a physical altercation. Video clip saved to alerts/conflict_20250115_143022.mp4 (10s). Please review and take appropriate action.
Restarting monitoring...
After reporting, immediately restart the script with the same parameters to continue monitoring.
OpenClaw:
1. Run: .venv/bin/python conflict_detector_last.py --rtsp_url rtsp://... --kami_api_key ...
2. Wait for process to exit
3. If exit_code == 10:
- Read stdout JSON
- Display alert message to user in chat
- Go to step 1 (restart)
If exit_code == 0:
- Inform user: "Monitoring session ended normally, no conflicts detected"
- Ask user if they want to restart
If exit_code == 1:
- Report error, show log content
# Initialize environment (first time only)
bash setup.sh
# Run with RTSP stream
.venv/bin/python conflict_detector_last.py \
--rtsp_url rtsp://127.0.0.1/live/YOUR-STREAM-ID \
--kami_api_key YOUR-API-KEY
# Run with local video file (for testing)
.venv/bin/python conflict_detector_last.py \
--rtsp_url /path/to/test_video.mp4 \
--kami_api_key YOUR-API-KEY
# Custom parameters
.venv/bin/python conflict_detector_last.py \
--rtsp_url rtsp://127.0.0.1/live/YOUR-STREAM-ID \
--kami_api_key YOUR-API-KEY \
--min_persons 2 \
--clip_before 10 \
--clip_after 10 \
--run_time 3600
When a conflict is detected (exit code 10), stdout contains:
{
"alert": "conflict_detected",
"timestamp": "2025-01-15T14:30:22.123456",
"description": "Two people are engaged in a physical altercation",
"video_clip": "alerts/conflict_20250115_143022.mp4",
"clip_duration": "10s",
"message": "Warning: Physical conflict detected. Two people are engaged in a physical altercation. Video clip saved to alerts/conflict_20250115_143022.mp4. Please review and take appropriate action."
}
| Field | Type | Description |
|---|---|---|
alert | string | Always "conflict_detected" |
timestamp | string | ISO format timestamp of the alert |
description | string | LLM-generated description of the conflict |
video_clip | string | Path to the saved video clip |
clip_duration | string | Total duration of the saved clip |
message | string | Pre-formatted alert message for direct display |
| Code | Meaning |
|---|---|
0 | Normal exit (run time exceeded, video ended, user interrupt, no event detected) |
10 | Event detected — conflict alert, JSON output on stdout |
1 | Runtime error (model not found, stream failure, missing API key) |
RTSP/File → FrameGrabber thread (ring buffer + latest frame)
├─ All frames → ring buffer (last 30s)
└─ Latest frame → main thread (every 1s)
├─ YOLO: person count >= 2?
│ ├─ No → skip, clear frame buffer
│ └─ Yes → collect N frames (gap=0.5s)
│ → LLM conflict analysis
│ ├─ No conflict → continue
│ └─ Conflict detected:
│ → wait clip_after seconds
│ → export video clip from ring buffer
│ → output JSON to stdout
│ → exit(10)
└─ Timeout → exit(0)
OpenClaw drives the loop:
run script → wait for exit → parse stdout → report to user → re-run script
This skill pushes every alarm through three redundant channels (see Alarm Delivery Channels above): stdout+exit(10), inbox file, and Feishu webhook. Before launching the detector, the agent MUST verify:
FEISHU_WEBHOOK_URL env var is set (or --feishu_webhook is passed). If not, warn the user that phone push is disabled — chat-window push still works via stdout+exit(10) and the inbox file.alerts/ directory is writable so pending.jsonl can be appended.space/HEARTBEAT.md still contains the conflict-detection inbox task; on every heartbeat, read kami-conflict-detection/alerts/pending.jsonl, if non-empty send a proactive summary to the user then MOVE (not delete) the file to alerts/consumed/<timestamp>.jsonl. If empty, reply HEARTBEAT_OK.alerts/pending.jsonl has been consumed (or archived) to avoid re-reporting stale alarms.Never rely on tailing stdout to report alarms — the agent is only invoked on user messages / heartbeats, so real-time stdout watching is impossible.
alerts/pending.jsonl; non-empty → proactive chat summary; empty → HEARTBEAT_OK.alerts/consumed/, not deleted.FEISHU_WEBHOOK_URL before launch; warn the user if missing (phone push disabled, chat push still active).10, OpenClaw MUST restart the script immediately to continue monitoring.Virtual environment not found
→ Run bash setup.sh
Model file missing
→ Place yolov8s-worldv2.onnx in the skill directory
RTSP connection failure
→ Verify camera is online, check --rtsp_url, confirm network connectivity
LLM API failure
→ Check --kami_api_key is correct, or set via export KAMI_API_KEY=your-key. If you don't have a key, register at https://kamiclaw-skill.kamihome.com, You can enjoy a free credit limit of 200 credits. Verify network access to the detection API endpoint.
No alerts generated
→ Check conflict_detector.log for details. Common causes: fewer than 2 people in frame, confidence threshold too high (try lowering --conf_threshold).
Script exits immediately with code 1 → Check log for error details. Common causes: model file missing, RTSP URL unreachable, API key not set.
OpenClaw restart loop too fast
→ If the script keeps detecting events immediately on restart, consider increasing --sample_interval or adding a brief delay between restarts.