{"id":"440438fe-9c67-4094-9aa2-76d40e92a0b3","entityType":"agent","slug":"clawhub-13681882136-kami-conflict-detection","name":"kami-conflict-detection","canonicalUrl":"https://www.xpersona.co/agent/clawhub-13681882136-kami-conflict-detection","canonicalPath":"/agent/clawhub-13681882136-kami-conflict-detection","generatedAt":"2026-10-11T17:44:17.019Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"editorial-content","verified":true,"confidence":"high","updatedAt":"2026-10-11T14:09:10.669Z","emptyReason":null},"description":"Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many RTSP camera streams concurrently. Continuous mode: a single Pytho... Skill: kami-conflict-detection Owner: 13681882136 Summary: Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many RTSP camera streams concurrently. Continuous mode: a single Pytho... Tags: latest:2.0.4 Version history: v2.0.4 | 2026-06-09T05:56:07.493Z | user add alert img v2.0.3 | 2026-05-29T03:10:32.629Z | user add muitl cma v2.0.2 | 2026-05-28T02:23:01.145Z | user remove env v2","descriptionLabel":"Technical summary","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 1.1K downloads reported by the source. Last updated 10/11/2026.","installCommand":"clawhub skill install s170wja1qf8kmkzj5brvhsj1r185a522:kami-conflict-detection","sourceUrl":"https://clawhub.ai/13681882136/kami-conflict-detection","homepage":"https://clawhub.ai/13681882136/skills/kami-conflict-detection","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/13681882136/kami-conflict-detection","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/13681882136/skills/kami-conflict-detection","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":60,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many RTSP camera streams concurrently. Continuous mode: a single Pytho..."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-11T14:09:10.669Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T14:09:10.669Z","emptyReason":null},"stars":null,"forks":null,"downloads":1052,"packageName":null,"latestVersion":"2.0.4","tractionLabel":"1.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-11T14:09:10.591Z","emptyReason":null},"lastUpdatedAt":"2026-10-11T14:09:10.669Z","lastCrawledAt":"2026-10-11T14:09:10.591Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-12T14:09:10.591Z","lastVerifiedAt":null,"highlights":[{"version":"2.0.4","createdAt":"2026-06-09T05:56:07.493Z","changelog":"add alert img","fileCount":8,"zipByteSize":36230},{"version":"2.0.3","createdAt":"2026-05-29T03:10:32.629Z","changelog":"add muitl cma","fileCount":8,"zipByteSize":30438},{"version":"2.0.2","createdAt":"2026-05-28T02:23:01.145Z","changelog":"remove env","fileCount":8,"zipByteSize":26060},{"version":"2.0.1","createdAt":"2026-05-27T09:51:51.357Z","changelog":"add config.json","fileCount":8,"zipByteSize":26097},{"version":"2.0.0","createdAt":"2026-05-27T06:56:22.011Z","changelog":"add hardware and alert channel:telegram discord","fileCount":7,"zipByteSize":24826},{"version":"1.0.1","createdAt":"2026-05-13T06:46:41.310Z","changelog":"update free credit intro","fileCount":6,"zipByteSize":20422},{"version":"1.0.0","createdAt":"2026-05-11T05:30:49.601Z","changelog":"Initial public release of physical conflict detection for cameras and video files. - Detects fights, shoving, and physical altercations between 2+ people using YOLO and LLM-based analysis. - Event-driven design: exits immediately on conflict detection with alert JSON; integrates with OpenClaw for continuous monitoring. - Supports tri-channel alarm delivery: primary chat via OpenClaw stdout, inbox file for redundancy, and Feishu bot push to user’s phone. - Configurable via command-line parameters (camera/video source, model file, thresholds, etc.). - Includes setup script for environment and dependency installation. - Requires Python 3, ONNX YOLO model, RTSP camera or local video file, and Kami API key.","fileCount":6,"zipByteSize":20343}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s170wja1qf8kmkzj5brvhsj1r185a522:kami-conflict-detection","setupComplexity":"low","setupSteps":["Setup complexity is classified as HIGH. You must provision dedicated cloud infrastructure or an isolated VM. Do not run this directly on your local workstation.","Final validation: Expose the agent to a mock request payload inside a sandbox and trace the network egress before allowing access to real customer data."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-13681882136-kami-conflict-detection/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-13681882136-kami-conflict-detection/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-13681882136-kami-conflict-detection/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-13681882136-kami-conflict-detection/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-13681882136-kami-conflict-detection/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-13681882136-kami-conflict-detection/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-11T17:44:17.014Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-13681882136-kami-conflict-detection/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-13681882136-kami-conflict-detection/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-13681882136-kami-conflict-detection/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-13681882136-kami-conflict-detection/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"high","updatedAt":"2026-10-11T14:09:10.669Z","emptyReason":null},"readme":"Skill: kami-conflict-detection\n\nOwner: 13681882136\n\nSummary: Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many RTSP camera streams concurrently. Continuous mode: a single Pytho...\n\nTags: latest:2.0.4\n\nVersion history:\n\nv2.0.4 | 2026-06-09T05:56:07.493Z | user\n\nadd alert img\n\nv2.0.3 | 2026-05-29T03:10:32.629Z | user\n\nadd muitl cma\n\nv2.0.2 | 2026-05-28T02:23:01.145Z | user\n\nremove env\n\nv2.0.1 | 2026-05-27T09:51:51.357Z | user\n\nadd config.json\n\nv2.0.0 | 2026-05-27T06:56:22.011Z | user\n\nadd hardware and alert channel:telegram discord\n\nv1.0.1 | 2026-05-13T06:46:41.310Z | user\n\nupdate free credit intro\n\nv1.0.0 | 2026-05-11T05:30:49.601Z | auto\n\nInitial public release of physical conflict detection for cameras and video files.\n\n- Detects fights, shoving, and physical altercations between 2+ people using YOLO and LLM-based analysis.\n- Event-driven design: exits immediately on conflict detection with alert JSON; integrates with OpenClaw for continuous monitoring.\n- Supports tri-channel alarm delivery: primary chat via OpenClaw stdout, inbox file for redundancy, and Feishu bot push to user’s phone.\n- Configurable via command-line parameters (camera/video source, model file, thresholds, etc.).\n- Includes setup script for environment and dependency installation.\n- Requires Python 3, ONNX YOLO model, RTSP camera or local video file, and Kami API key.\n\nArchive index:\n\nArchive v2.0.4: 8 files, 36230 bytes\n\nFiles: config.json (288b), conflict_detector_last.py (54380b), README.md (24502b), requirements.txt (67b), setup.sh (3939b), skill-card.md (2674b), SKILL.md (18646b), _meta.json (142b)\n\nFile v2.0.4:SKILL.md\n\n---\r\nname: kami-conflict-detection\r\ndescription: |\r\n  Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many\r\n  RTSP camera streams concurrently. Continuous mode: a single Python process monitors every\r\n  configured camera in parallel, pushes a per-camera alert (stdout / inbox file / Feishu /\r\n  Discord / Telegram) on each detected event, and keeps running — it does NOT exit on\r\n  detection.\r\nversion: 2.0.4\r\nauthor: kami-smarthome\r\ntags:\r\n  - smart-home\r\n  - conflict-detection\r\n  - fight-detection\r\n  - violence-detection\r\n  - yolo\r\n  - rtsp\r\n  - surveillance\r\n  - security\r\n  - edge-ai\r\n  - multi-camera\r\n  - openclaw\r\ntriggers:\r\n  - detect fighting\r\n  - detect conflict\r\n  - detect physical conflict\r\n  - check for fighting\r\n  - is anyone fighting\r\n  - detect scuffle\r\n  - detect shoving\r\n  - monitor for fights\r\n  - start conflict monitoring\r\n  - begin violence detection\r\nmetadata:\r\n  openclaw:\r\n    requires:\r\n      bins:\r\n        - python3.10\r\n      hardware:\r\n        cpu: \"4+ cores (x86_64 / ARM64)\"\r\n        memory: \"8 GB+\"\r\n        storage: \"10 GB+\"\r\n        gpu: \"optional (speeds up ONNX inference)\"\r\n      network:\r\n        - \"RTSP camera access (LAN)\"\r\n        - \"Internet (KamiClaw API)\"\r\n      devices:\r\n        - \"RTSP IP camera\"\r\n    emoji: \"🥊\"\r\n---\r\n\r\n# Kami Conflict Detection\r\n\r\nDetect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many RTSP camera streams concurrently. Continuous mode — the process never exits on detection; every confirmed event is pushed as an alert tagged with the originating camera, then monitoring resumes.\r\n\r\n## Privacy Policy\r\n\r\nFor privacy policy details, see: <https://kamiclaw-skill.kamihome.com/privacy>\r\n\r\n## How It Works\r\n\r\n1. **YOLO pre-filter** — lightweight person detection counts people in each frame (must be ≥ `min_persons`, default 2).\r\n2. **Multi-frame collection** — collects N frames with a configurable time gap.\r\n3. **LLM conflict analysis** — frames are sent to the Kami detection API for violence/conflict judgment.\r\n4. **Continuous alerting** — on a confirmed conflict, the worker saves a per-camera video clip, pushes an alert with `camera = <camera_name>` to every configured channel, and **immediately resumes monitoring**. The process keeps running until the user stops it (Ctrl+C / OpenClaw shutdown).\r\n\r\n> Multi-camera: every entry in `config.json -> cameras[]` runs in its own worker thread inside the same process. The YOLO ONNX session, the conflict analyzer and all push channels are shared once across cameras. Push channels are **shared** — no per-camera webhook split. Stranger / clip / log lines are namespaced by camera name.\r\n\r\n## When to Use\r\n\r\n- Monitor one or many camera feeds for physical fights or scuffles\r\n- Detect shoving, pushing, or violent behavior between people\r\n- Run conflict detection on a local video file for testing\r\n- Set up automated surveillance alerts for physical altercations\r\n\r\n## Installation\r\n\r\n```bash\r\nbash setup.sh\r\n```\r\n\r\nNo `sudo` required. The script auto-bootstraps **python3.10** in user space (via [uv](https://github.com/astral-sh/uv) when needed), creates `.venv/`, installs dependencies, and prepares `alerts/`. Idempotent — safe to re-run.\r\n\r\n## Prerequisites\r\n\r\n- Linux/macOS shell with `curl` (or `wget`) and `unzip` available\r\n- `yolov8s-worldv2.onnx` model file in the skill directory (auto-downloaded as a pre-exported ONNX bundle from `https://publicfiles.xiaoyi.com/kami-conflict-detection-model.zip` on first run if missing — no `.pt` conversion required)\r\n- One or more RTSP cameras online, OR a local video file for testing\r\n- Kami API key (`--kami_api_key` or write to `config.json`). Register at <https://kamiclaw-skill.kamihome.com> for a free 200-credit quota.\r\n- `setup.sh` has been run at least once\r\n\r\n> Python 3.10 is **not** a manual prerequisite — `setup.sh` will install it locally without sudo if missing.\r\n\r\n## Parameters\r\n\r\nConfirm the following before running. The fields marked **(persisted in `config.json`)** can be saved to `config.json` next to the script so the user does not need to provide them every run — see [Configuration Persistence](#configuration-persistence) below.\r\n\r\n| Parameter | Default | Description |\r\n|-----------|---------|-------------|\r\n| `--rtsp_url` | *(empty; see `cameras[]` in `config.json`)* | Single-camera CLI override. When set, takes priority over `cameras[]`. |\r\n| `--camera_name` | *(empty)* | Optional camera name used together with `--rtsp_url`. Defaults to `camera_0`. |\r\n| `--kami_api_key` | *(persisted in `config.json`)* | Kami API key |\r\n| `--yolo_model` | `yolov8s-worldv2.onnx` | YOLO model file path |\r\n| `--conf_threshold` | `0.25` | YOLO confidence threshold |\r\n| `--min_persons` | `2` | Minimum person count to trigger LLM analysis |\r\n| `--sample_interval` | `1.0` | YOLO pre-filter interval (seconds) |\r\n| `--multi_frame_count` | `3` | Frames per LLM analysis |\r\n| `--multi_frame_gap` | `0.5` | Gap between collected frames (seconds) |\r\n| `--buffer_seconds` | `30` | Ring buffer duration for clip export |\r\n| `--clip_before` | `5` | Seconds of video before the conflict |\r\n| `--clip_after` | `5` | Seconds of video after the conflict |\r\n| `--output_dir` | `alerts/` | Root directory for saved video clips. Per-camera subfolders (`alerts/<camera_name>/`) are created automatically. |\r\n| `--fps` | `15` | Video stream frame rate |\r\n| `--inbox_file` | `alerts/pending.jsonl` | Alarm inbox consumed by the heartbeat task |\r\n| `--feishu_webhook` | *(persisted in `config.json`)* | Feishu custom bot webhook URL |\r\n| `--feishu_secret` | *(persisted in `config.json`)* | Feishu signing secret (only if signing enabled) |\r\n| `--feishu_app_id` | *(persisted in `config.json`)* | Feishu **self-built app** App ID. Required only if you want the conflict snapshot to render **inline** inside the Feishu card (uploads the image to Feishu and embeds it via `image_key`). |\r\n| `--feishu_app_secret` | *(persisted in `config.json`)* | Feishu self-built app App Secret, paired with `--feishu_app_id`. |\r\n| `--discord_webhook` | *(persisted in `config.json`)* | Discord channel webhook URL |\r\n| `--telegram_bot_token` | *(persisted in `config.json`)* | Telegram Bot token |\r\n| `--telegram_chat_id` | *(persisted in `config.json`)* | Telegram target chat/group/channel ID |\r\n| `--proxy` | *(persisted in `config.json`)* | HTTPS proxy for Discord/Telegram (not used for Feishu). Mainland-China users MUST set this for Discord/Telegram. |\r\n\r\n**Only ask the user about a parameter if (a) it's still empty in `config.json` AND has no command-line value, OR (b) the user explicitly asks to adjust it. Do NOT pause the conversation for blanket parameter confirmation.**\r\n\r\n## Configuration Persistence (`config.json`)\r\n\r\nA `config.json` file lives next to the script with the following empty-by-default fields:\r\n\r\n```json\r\n{\r\n  \"cameras\": [\r\n    {\r\n      \"name\": \"\",\r\n      \"rtsp_url\": \"\"\r\n    }\r\n  ],\r\n  \"kami_api_key\": \"\",\r\n  \"feishu_webhook\": \"\",\r\n  \"feishu_secret\": \"\",\r\n  \"feishu_app_id\": \"\",\r\n  \"feishu_app_secret\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\r\n```\r\n\r\n**`cameras` array — one entry per RTSP source.** All cameras run concurrently inside a single process, sharing the loaded YOLO ONNX model, the conflict analyzer and the same set of push channels. Add a new entry to the array for each additional camera (e.g. `living_room`, `office_door`, …).\r\n\r\n| Camera field | Required | Behaviour when empty |\r\n|--------------|----------|----------------------|\r\n| `name` | recommended | Free-form short label written into every alert as `alert.camera`, prefixed to `alert.message` as `[name]`, and used as the snapshot subdirectory under `alerts/<name>/`. If the user does not supply one, the script auto-assigns `camera_0`, `camera_1`, … and logs the assignment. |\r\n| `rtsp_url` | **yes** | Entry is skipped if empty. Accepts `rtsp://...`, `http(s)://...`, or a local file path. |\r\n\r\nResolution order at runtime: **`--rtsp_url` (single-camera CLI override)** → **`cameras[]` in `config.json`** → empty (fatal: `EXIT_ERROR`).\r\n\r\n**Workflow OpenClaw MUST follow (single-turn, no extra confirmation):**\r\n\r\n1. On first launch, read `config.json` and identify which fields are still empty.\r\n2. **Ask the user only for the empty fields**:\r\n   - **Cameras** — for each camera the user wants to monitor, ask for the `rtsp_url` AND a camera `name` **in the same question**:\r\n     - The `name` is a free-form short label, ideally a natural-language tag like `living_room` / `front_door` / `office`. It will appear in every alarm to identify which camera fired the event.\r\n     - When the user is unsure about their RTSP URL format, provide these common brand templates as a reference:\r\n       ```\r\n       TP-Link:  rtsp://<user>:<password>@<ip>:554/stream1\r\n       Hikvision(海康): rtsp://<user>:<password>@<ip>:554/Streaming/Channels/101\r\n       Dahua(大华):    rtsp://<user>:<password>@<ip>:554/cam/realmonitor?channel=1&subtype=0\r\n       ```\r\n       > Note: `<user>` and `<password>` are the camera's login credentials (often `admin`); `<ip>` is the camera's LAN IP. The port is almost always `554`. Substream variants (lower resolution / bandwidth) may use path `102` (Hikvision) or `subtype=1` (Dahua).\r\n     - **If the user only provides the `rtsp_url` and omits the name, IMMEDIATELY tell them: \"No camera name provided. The script will auto-assign an incremental id like `camera_0` / `camera_1`. Do you want to proceed with the auto id?\"** Only proceed with the auto id once the user accepts (or stays silent / says ok). Do NOT silently assign the auto id without notifying.\r\n     - Persist each camera as an object in the `cameras` array.\r\n   - **Kami API key** — required for the LLM conflict analysis.\r\n   - **Push channels** — which to enable (Feishu / Discord / Telegram) and their credentials. Push channels are **shared** across all cameras (no per-camera split); every camera uses the same webhooks.\r\n     - **Feishu** — ask for `feishu_webhook` (required). If the user wants the conflict snapshot to render **inline inside the Feishu card**, ALSO ask for `feishu_app_id` + `feishu_app_secret` (self-built app credentials, used only to upload the snapshot via OpenAPI to obtain an `image_key`). Without app credentials the snapshot falls back to a clickable image-host URL.\r\n     - **Discord** — ask for `discord_webhook`. The conflict snapshot is attached as multipart so it renders inline automatically. Mainland-China users MUST also provide `proxy`.\r\n     - **Telegram** — ask for `telegram_bot_token` + `telegram_chat_id`. The conflict snapshot is delivered via `sendPhoto` and renders inline. Mainland-China users MUST also provide `proxy`.\r\n3. **Write the user's answers back into `config.json`** (preserve existing non-empty fields). Subsequent launches skip these prompts.\r\n4. **Immediately in the SAME turn**, run `bash setup.sh` (idempotent) and launch the detector. Do NOT end the turn after step 3 — do NOT wait for the user to say \"start\" or \"begin\".\r\n5. If all required fields are already non-empty on entry, skip steps 2–3 and go straight to step 4.\r\n\r\n## Alarm Push Channels\r\n\r\nAlarms can be pushed through the following channels — all optional, configure any combination:\r\n\r\n| Channel | Required Parameters |\r\n|---------|--------------------|\r\n| **Feishu** (custom bot) | `--feishu_webhook` (required); `--feishu_secret` (optional, signing); `--feishu_app_id` + `--feishu_app_secret` (optional, **enables inline snapshot image** via Feishu OpenAPI `image_key`) |\r\n| **Discord** (channel webhook) | `--discord_webhook` (snapshot attached as multipart, renders inline) |\r\n| **Telegram** (Bot API) | `--telegram_bot_token` + `--telegram_chat_id` (snapshot delivered via `sendPhoto`, renders inline) |\r\n\r\nBeyond app push, every alarm is **always** delivered through two redundant local channels:\r\n\r\n1. **stdout JSON line** — OpenClaw reads stdout line-by-line and reports each alert in chat (no exit; the process keeps running).\r\n2. **Inbox file `alerts/pending.jsonl`** — appended on every alarm; consumed by the heartbeat task as a fallback.\r\n\r\n> Refer to the official docs of each platform for how to obtain webhook URLs / bot tokens / chat IDs.\r\n> In mainland China, Discord and Telegram require a proxy (`--proxy` or `HTTPS_PROXY`).\r\n> Push card labels are language-fixed: **Feishu → Chinese**, **Discord/Telegram → English**.\r\n\r\n## Usage\r\n\r\n```bash\r\n# First time only\r\nbash setup.sh\r\n\r\n# Multi-camera mode (recommended): write cameras[] into config.json once,\r\n# then just run the script with no extra args.\r\n.venv/bin/python conflict_detector_last.py\r\n\r\n# Single-camera CLI override (one-off, e.g., for testing a video file)\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url /path/to/test_video.mp4 \\\r\n  --camera_name test_video \\\r\n  --kami_api_key YOUR-API-KEY\r\n```\r\n\r\n## Output Format (stdout JSON)\r\n\r\nWhen a conflict is detected, the worker prints one JSON line and continues monitoring:\r\n\r\n```json\r\n{\r\n  \"alert\": \"conflict_detected\",\r\n  \"camera\": \"living_room\",\r\n  \"timestamp\": \"2026-05-21 14:30:22\",\r\n  \"description\": \"Two people are engaged in a physical altercation\",\r\n  \"video_clip\": \"alerts/living_room/conflict_living_room_20260521_143022.mp4\",\r\n  \"snapshot_image\": \"alerts/living_room/snapshot_living_room_20260521_143022.jpg\",\r\n  \"clip_duration\": \"10s\",\r\n  \"message\": \"[living_room] Warning: Physical conflict detected. ...\"\r\n}\r\n```\r\n\r\n> The `snapshot_image` field is a single representative frame captured **between `clip_before` and `clip_after`** windows (i.e. at the conflict moment), resized to a 640px long side and saved as JPEG. It is embedded inline in the Feishu / Discord / Telegram cards.\r\n\r\n## Exit Codes\r\n\r\n| Code | Meaning | OpenClaw Action |\r\n|------|---------|-----------------|\r\n| `0` | Normal exit (Ctrl+C, all streams ended, no fatal error) | Inform user; optionally restart |\r\n| `1` | Runtime error (model not found, missing API key, no camera configured) | Report error; check `conflict_detector.log` |\r\n\r\n> Continuous mode: detected conflicts do NOT terminate the process — they only push alerts. The process stays alive until interrupted.\r\n\r\n## Strict Rules (MUST Follow)\r\n\r\n- **RULE**: Alarms flow via (a) stdout JSON line, (b) inbox file, (c) Feishu (optional), (d) Discord (optional), (e) Telegram (optional). Never rely on a single channel.\r\n- **RULE (continuous mode)**: A detected conflict NEVER terminates the process. The worker pushes the alert and resumes monitoring on the same stream. There is no `exit 10`; there is no detect-report-restart loop.\r\n- **RULE (multi-camera)**: All cameras in `config.json -> cameras[]` are monitored concurrently inside a single Python process (shared YOLO ONNX session, shared analyzer, one inference lock, per-camera FrameGrabber + worker thread). Never spawn one process per camera.\r\n- **RULE (camera id)**: Every alarm written to `pending.jsonl`, Feishu, Discord and Telegram MUST include the camera name in the `camera` field. The `message` field MUST be prefixed with `[<camera_name>] `. Snapshots MUST be written under `alerts/<camera_name>/`.\r\n- **RULE (camera name prompt)**: When asking the user for an RTSP URL, the agent MUST in the SAME question also ask for a human-readable camera `name` (e.g. `living_room`, `front_door`). If the user provides the URL but skips the name, the agent MUST EXPLICITLY notify them that an auto id (`camera_0`, `camera_1`, …) will be used; never assign the auto id silently.\r\n- **RULE (shared push)**: Feishu / Discord / Telegram credentials in `config.json` apply to every camera. There is no per-camera webhook split.\r\n- **RULE (feishu inline image)**: To render the conflict snapshot inline inside the Feishu card, the agent MUST ask the user for `feishu_app_id` AND `feishu_app_secret` (self-built app credentials) when configuring Feishu. Without them, the snapshot falls back to a clickable sm.ms URL (or plain text path). The webhook alone is NOT sufficient for inline image rendering.\r\n- **RULE (snapshot)**: Every conflict alarm MUST carry a `snapshot_image` field pointing to a JPEG saved under `alerts/<camera_name>/snapshot_<camera_name>_YYYYMMDD_HHMMSS.jpg`. The frame is captured between `clip_before` and `clip_after` (i.e. at the conflict moment) and resized to a 640px long side for consistent display across push channels.\r\n- **RULE**: Every heartbeat consumes `alerts/pending.jsonl`; non-empty → proactive chat summary; empty → `HEARTBEAT_OK`.\r\n- **RULE**: Consumed alarms are MOVED to `alerts/consumed/`, not deleted.\r\n- **RULE**: Before launch, read `config.json`; only ask the user for fields that are empty, and **write the answers back into `config.json`** so subsequent launches are non-interactive.\r\n- **RULE (auto-launch)**: Once at least one camera (with `rtsp_url`) and `kami_api_key` are present in `config.json` (either pre-existing or just written), the agent MUST run `bash setup.sh` and launch the detector **in the same conversation turn**. Never end the turn at \"config saved\" — the user does NOT need to send a second message like \"start it\" or \"begin detection\".\r\n- **RULE**: Warn the user if no push channel is configured (chat-window push still active).\r\n\r\n## Troubleshooting\r\n\r\n| Problem | Fix |\r\n|---------|-----|\r\n| Virtual environment not found | Run `bash setup.sh` |\r\n| Model file missing | `setup.sh` (or first script run) auto-downloads the ONNX bundle from `https://publicfiles.xiaoyi.com/kami-conflict-detection-model.zip`, extracts it, moves the `.onnx` next to the script and deletes the temp folder. If automatic download fails, manually fetch the zip, unzip it, and move `yolov8s-worldv2.onnx` into the skill directory. |\r\n| `unzip` not found | Install `unzip` (e.g. `apt install unzip` / `brew install unzip`) and rerun `setup.sh`. |\r\n| RTSP connection failure | Verify camera is online; check `cameras[].rtsp_url` |\r\n| LLM API failure | Check `kami_api_key`; verify network to the Kami API endpoint |\r\n| No alerts generated | See `conflict_detector.log`; try lowering `--conf_threshold` |\r\n| Script exits with code 1 | Check log; common causes: missing model, no camera configured, missing API key |\r\n| Feishu card shows snapshot path instead of an inline image | Provide `feishu_app_id` + `feishu_app_secret` (self-built app); without them the script falls back to sm.ms URL / local path. |\r\n| Discord / Telegram push silently fails | Mainland-China users must set `proxy` in `config.json` (or `--proxy`). Feishu does NOT need a proxy. |\n\nFile v2.0.4:README.md\n\n# Kami Conflict Detection\r\n\r\nReal-time multi-camera physical conflict (fighting, shoving, scuffling) detection for RTSP camera streams or local video files. Uses YOLO for person pre-filtering and a remote multimodal LLM API for conflict analysis.\r\n\r\n**Multi-camera capable.** A single process can monitor an arbitrary number of RTSP cameras concurrently (e.g. `living_room` + `office_door` + …). The YOLO ONNX session and conflict analyzer are loaded **once and shared** across all cameras; each camera owns an independent frame grabber, worker thread and snapshot directory. Push channels (Feishu / Discord / Telegram) are shared — every camera uses the same webhooks. The process keeps running across detections — it does NOT exit on event.\r\n\r\n## How It Works\r\n\r\nFor each configured camera, a dedicated worker thread polls the stream, uses YOLO to count persons in each frame, and when 2+ people are detected, collects multiple frames and sends them to the Kami detection API for conflict analysis. When a conflict is confirmed, the worker saves a per-camera video clip covering the moments before and after the incident, prints an alert JSON line tagged with the camera name to stdout, pushes the alert to every configured channel, and **immediately resumes monitoring**. The process keeps running until the user stops it (Ctrl+C / OpenClaw shutdown).\r\n\r\n```\r\nFor each camera (parallel worker thread):\r\n  Read stream → YOLO counts persons → 2+ people? → Collect frames → LLM analysis\r\n                                                                        ↓\r\n                                            Conflict? → save per-camera clip\r\n                                                     → push alert (stdout / inbox / Feishu / Discord / Telegram)\r\n                                                     → resume monitoring (no exit)\r\n```\r\n\r\n## Quick Start\r\n\r\n```bash\r\n# 1. Install dependencies\r\nbash setup.sh\r\n\r\n# 2. Configure cameras and API key in config.json (recommended), then run:\r\n.venv/bin/python conflict_detector_last.py\r\n\r\n# Or for a one-off single-camera run via CLI override:\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --camera_name living_room \\\r\n  --kami_api_key YOUR-API-KEY\r\n```\r\n\r\n## Installation\r\n\r\n```bash\r\nbash setup.sh\r\n```\r\n\r\nNo `sudo` required. The script will:\r\n- Auto-bootstrap **Python 3.10** in user space (via [uv](https://github.com/astral-sh/uv)) — no system-level package manager needed\r\n- Create a `.venv/` virtual environment\r\n- Install all pip dependencies (`onnxruntime`, `opencv-python-headless`, `numpy`, `requests`)\r\n- Auto-download a pre-exported YOLO ONNX bundle from `https://publicfiles.xiaoyi.com/kami-conflict-detection-model.zip` (extracted to a temp folder, then `.onnx` is moved next to the script and the temp folder is deleted) — **no `.pt` conversion / no `ultralytics` install**.\r\n- Create `alerts/` output directory\r\n\r\n## API Key\r\n\r\nThis skill requires a Kami API key for the conflict analysis LLM service.\r\n\r\n**If you don't have a key yet, register and obtain one at:**\r\n> https://kamiclaw-skill.kamihome.com\r\nYou can enjoy a free credit limit of 200 credits.\r\n\r\nProvide the key via:\r\n- `config.json` (recommended) — the value persists across runs\r\n- Command line: `--kami_api_key YOUR-KEY` (overrides `config.json` for this run only)\r\n\r\n## Configuration File (config.json)\r\n\r\nA `config.json` file in the skill directory persists user-provided values so you don't have to pass them on every run. Empty fields are ignored. Command-line arguments take priority over `config.json`.\r\n\r\n```json\r\n{\r\n  \"cameras\": [\r\n    {\r\n      \"name\": \"living_room\",\r\n      \"rtsp_url\": \"rtsp://192.168.1.100/live/stream1\"\r\n    },\r\n    {\r\n      \"name\": \"office_door\",\r\n      \"rtsp_url\": \"rtsp://192.168.1.101/live/stream1\"\r\n    }\r\n  ],\r\n  \"kami_api_key\": \"YOUR-KAMI-KEY\",\r\n  \"feishu_webhook\": \"\",\r\n  \"feishu_secret\": \"\",\r\n  \"feishu_app_id\": \"\",\r\n  \"feishu_app_secret\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\r\n```\r\n\r\nResolution order at runtime: **`--rtsp_url` (single-camera CLI override)** → **`cameras[]` in `config.json`** → empty (fatal). When OpenClaw asks the user for these values, write the answers into `config.json`.\r\n\r\n### Multi-Camera Mode\r\n\r\nThe `cameras` array can contain one or many entries. All entries are monitored concurrently inside a **single Python process** (single-process / multi-thread / shared-model architecture):\r\n\r\n| Field | Required | Behaviour when empty |\r\n|-------|----------|----------------------|\r\n| `name` | recommended | Free-form human-readable label (e.g. `living_room`, `front_door`, `office`). The agent should ask for it together with the `rtsp_url`. If the user does not provide one, the script auto-assigns `camera_0`, `camera_1`, … by array index and logs the assignment. The name is written into every alarm as `alert.camera`, prefixed to `alert.message` as `[name]`, and used as the snapshot subdirectory under `alerts/`. |\r\n| `rtsp_url` | **yes** | Entry is skipped if empty. Accepts `rtsp://...`, `http(s)://...`, or a local file path. |\r\n\r\n**Push channels are shared by all cameras.** The `feishu_webhook` / `discord_webhook` / `telegram_*` fields apply to every detected event; there is no per-camera webhook split. Every alert payload carries `\"camera\": \"<name>\"` and an `[<name>]` prefix in `message`, so the receiving operator can tell which camera fired the alarm.\r\n\r\n**Continuous mode.** A detected conflict NEVER terminates the process. The worker pushes the alert and resumes monitoring on the same stream. The process only exits on Ctrl+C, all streams ending, or a fatal startup error.\r\n\r\n## Prerequisites\r\n\r\n- Linux/macOS shell with `curl` (or `wget`) and `unzip` available\r\n- `yolov8s-worldv2.onnx` model file in the skill directory (auto-downloaded as a pre-exported ONNX bundle on first run if missing — see [Model File](#model-file) below)\r\n- One or more RTSP cameras online and network-reachable, OR a local video file for testing\r\n- Kami API key (see above)\r\n- `setup.sh` has been run at least once\r\n\r\n> Python 3.10 is **not** a manual prerequisite — `setup.sh` will install it locally without sudo if missing.\r\n\r\n### Model File\r\n\r\nThe YOLO ONNX model is auto-fetched on first run from:\r\n\r\n```\r\nhttps://publicfiles.xiaoyi.com/kami-conflict-detection-model.zip\r\n```\r\n\r\nThe zip extracts into a folder called `kami-conflict-detection-model/` containing one or more `.onnx` files (currently `yolov8s-worldv2.onnx`). The script:\r\n\r\n1. downloads the zip,\r\n2. extracts it,\r\n3. moves the `.onnx` files next to `conflict_detector_last.py`,\r\n4. deletes the extracted folder and the zip.\r\n\r\nNo `.pt` download, no `ultralytics` package install, no on-device ONNX export step. If the automatic download fails, manually fetch the zip, unzip it, and place `yolov8s-worldv2.onnx` in the skill directory.\r\n\r\n## Parameters\r\n\r\n### Required (via `config.json` or CLI)\r\n\r\n| Parameter | Description |\r\n|-----------|-------------|\r\n| `cameras[]` (config.json) **or** `--rtsp_url` + `--camera_name` (CLI) | Video sources. Provide cameras as an array in `config.json`, or override with a single source on the CLI. Each entry accepts an RTSP URL or a local file path. |\r\n| `--kami_api_key` | Kami API key for conflict analysis. Register at https://kamiclaw-skill.kamihome.com — you can enjoy a free credit limit of 200 credits. |\r\n\r\n### Optional\r\n\r\n| Parameter | Default | Type | Description |\r\n|-----------|---------|------|-------------|\r\n| `--rtsp_url` | *(empty)* | str | Single-camera CLI override. When set, takes priority over `cameras[]` in `config.json`. |\r\n| `--camera_name` | *(empty)* | str | Camera name used together with `--rtsp_url`. Defaults to `camera_0` if omitted. |\r\n| `--yolo_model` | `yolov8s-worldv2.onnx` | path | Path to the YOLO ONNX model file. |\r\n| `--conf_threshold` | `0.25` | float (0-1) | YOLO detection confidence threshold. Lower detects more persons but may include false positives. |\r\n| `--min_persons` | `2` | int | Minimum number of persons in frame to trigger LLM analysis. A conflict requires at least 2 people. |\r\n| `--sample_interval` | `1.0` | float (seconds) | How often to run YOLO person detection on the stream. Lower values increase CPU usage but improve responsiveness. |\r\n| `--multi_frame_count` | `3` | int | Number of frames to collect before sending to LLM. More frames give the LLM better context but increase latency. |\r\n| `--multi_frame_gap` | `0.5` | float (seconds) | Time gap between collected frames. Spreads frames over time to capture motion progression. |\r\n| `--buffer_seconds` | `30` | int (seconds) | Ring buffer duration. Stores recent frames in memory for video clip export when a conflict is detected. |\r\n| `--clip_before` | `5` | int (seconds) | Seconds of video to include before the conflict moment in the exported clip. |\r\n| `--clip_after` | `5` | int (seconds) | Seconds of video to include after the conflict moment. The script waits this long after detection before exporting. |\r\n| `--output_dir` | `./alerts` | path | Root directory for saved video clips. Per-camera subfolders (`alerts/<camera_name>/`) are created automatically. |\r\n| `--fps` | `15` | int | Frame rate for the video stream reader. Should match or approximate the camera's actual frame rate. |\r\n\r\n### Parameter Tuning Guide\r\n\r\n| Scenario | Adjustment |\r\n|----------|------------|\r\n| Missing persons in frame | Lower `--conf_threshold` (e.g., 0.25→0.15) |\r\n| Too many false person detections | Raise `--conf_threshold` (e.g., 0.25→0.4) |\r\n| Want to detect solo aggression | Set `--min_persons 1` (not recommended, high false positive rate) |\r\n| High CPU usage | Increase `--sample_interval` (e.g., 1.0→3.0) |\r\n| LLM analysis too slow | Reduce `--multi_frame_count` (e.g., 3→2) |\r\n| Want longer video clips | Increase `--clip_before` and `--clip_after` |\r\n| Memory constrained | Reduce `--buffer_seconds` (e.g., 30→15) |\r\n\r\n## Output Format\r\n\r\nWhen a conflict is detected, the worker prints one JSON line and continues monitoring:\r\n\r\n```json\r\n{\r\n  \"alert\": \"conflict_detected\",\r\n  \"camera\": \"living_room\",\r\n  \"timestamp\": \"2026-05-21 14:30:22\",\r\n  \"description\": \"Two people are engaged in a physical altercation\",\r\n  \"video_clip\": \"alerts/living_room/conflict_living_room_20260521_143022.mp4\",\r\n  \"snapshot_image\": \"alerts/living_room/snapshot_living_room_20260521_143022.jpg\",\r\n  \"clip_duration\": \"10s\",\r\n  \"message\": \"[living_room] Warning: Physical conflict detected. Two people are engaged in a physical altercation. Video clip saved to alerts/living_room/conflict_living_room_20260521_143022.mp4. Please review and take appropriate action.\"\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `alert` | Event type, always `\"conflict_detected\"` |\r\n| `camera` | The camera name that fired this alert (matches a `cameras[].name` entry, or `camera_0`/`camera_1`/… if auto-assigned) |\r\n| `timestamp` | Alert time formatted as `YYYY-MM-DD HH:MM:SS` |\r\n| `description` | LLM-generated description of the conflict |\r\n| `video_clip` | File path to the saved MP4 video clip (under `alerts/<camera_name>/`) |\r\n| `snapshot_image` | File path to a single representative JPEG frame (between `clip_before` and `clip_after`, resized to a 640px long side). Embedded inline in Feishu / Discord / Telegram pushes. |\r\n| `clip_duration` | Total duration of the saved clip |\r\n| `message` | Pre-formatted alert message ready for display, prefixed with `[<camera_name>] ` |\r\n\r\n## Exit Codes\r\n\r\n| Code | Meaning | Typical Action |\r\n|------|---------|----------------|\r\n| `0` | Normal exit — Ctrl+C, all streams ended, no fatal error. | End session. |\r\n| `1` | Runtime error — model missing, no camera configured, API key not set. | Check `conflict_detector.log` for details. |\r\n\r\n> Continuous mode: detected conflicts do NOT terminate the process — they only push alerts. The process stays alive until interrupted.\r\n\r\n## Log File\r\n\r\nAll operational logs are written to `conflict_detector.log` in the script directory. Logs go to stderr (not stdout) to keep stdout clean for JSON output only.\r\n\r\n## Examples\r\n\r\n```bash\r\n# Recommended: write cameras[] + kami_api_key into config.json once,\r\n# then just run the script with no extra args. All cameras run in parallel.\r\n.venv/bin/python conflict_detector_last.py\r\n\r\n# Single-camera CLI override (one-off, e.g., for testing a video file)\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url /home/user/test_fight_video.mp4 \\\r\n  --camera_name test_video \\\r\n  --kami_api_key YOUR-API-KEY\r\n\r\n# Longer video clips, faster sampling\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --clip_before 10 \\\r\n  --clip_after 10 \\\r\n  --sample_interval 0.5\r\n```\r\n\r\n---\r\n\r\n## Alarm Push Channels (Detailed)\r\n\r\nBeyond the default JSON stdout output, alarms can be simultaneously pushed to external messaging platforms. These are **pure push notifications** — they only send alerts OUT, they do NOT let you interact with the detector via those apps. (For interactive control via app, see [OpenClaw Channel Integration](#openclaw-channel-integration) below.)\r\n\r\nAll channels are optional. Configure any combination via command-line arguments or `config.json`. Push channels are **shared by all cameras** — every detected event is pushed to the same set of webhooks, but the `camera` field in the payload (and the `[<name>]` prefix in `message`) tells the receiver which camera fired the alarm.\r\n\r\n### 1. Feishu (Lark) — Custom Bot Webhook\r\n\r\n| Parameter | config.json field | Description |\r\n|-----------|-------------------|-------------|\r\n| `--feishu_webhook` | `feishu_webhook` | Webhook URL (required) |\r\n| `--feishu_secret` | `feishu_secret` | Signing secret (optional) |\r\n| `--feishu_app_id` | `feishu_app_id` | Self-built app App ID. **Required only for inline image rendering** — used to upload the conflict snapshot via Feishu OpenAPI and embed it as an `img` element inside the card. |\r\n| `--feishu_app_secret` | `feishu_app_secret` | Self-built app App Secret, paired with `feishu_app_id`. |\r\n\r\n**How to obtain the webhook:**\r\n\r\n1. Open Feishu PC/web → Go to the target group chat\r\n2. Click \"...\" (group settings) → **Bots** → **Add Bot** → **Custom Bot**\r\n3. Give it a name (e.g., \"Conflict Alert\") → **Done**\r\n4. Copy the **Webhook URL** (format: `https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx`)\r\n5. (Optional) Enable **Signing Verification** → copy the secret key\r\n\r\n**How to obtain `feishu_app_id` / `feishu_app_secret` (only needed for inline image):**\r\n\r\n1. Open <https://open.feishu.cn/app> → **Create Custom App** (“创建企业自建应用”)\r\n2. In **Credentials & Basic Info** copy `App ID` + `App Secret`\r\n3. Under **Permissions & Scopes**, add `im:resource` (image upload). Enabling additional `im:message` scopes is optional and only needed for two-way bots, not for image upload.\r\n4. Add the same app to the chat group used by the webhook so the uploaded image_key is renderable there.\r\n\r\n> Without `feishu_app_id` + `feishu_app_secret`, the snapshot falls back to a clickable URL via the sm.ms public image host. With them, the image renders inline directly in the card.\r\n\r\n> Push language: **Chinese**\r\n\r\n### 2. Discord — Channel Webhook\r\n\r\n| Parameter | config.json field | Description |\r\n|-----------|-------------------|-------------|\r\n| `--discord_webhook` | `discord_webhook` | Webhook URL |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Discord → Go to the target text channel\r\n2. Click the gear icon (Edit Channel) → **Integrations** → **Webhooks**\r\n3. Click **New Webhook** → Give it a name → Select the channel\r\n4. Click **Copy Webhook URL** (format: `https://discord.com/api/webhooks/123456/abcdef...`)\r\n\r\n> Push language: **English**\r\n> Mainland China note: Requires a proxy. Pass `--proxy http://host:port` on the command line.\r\n\r\n### 3. Telegram — Bot API\r\n\r\n| Parameter | config.json field | Description |\r\n|-----------|-------------------|-------------|\r\n| `--telegram_bot_token` | `telegram_bot_token` | Bot token |\r\n| `--telegram_chat_id` | `telegram_chat_id` | Target chat/group/channel ID |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Telegram, search for **@BotFather**\r\n2. Send `/newbot` → follow the prompts to name your bot\r\n3. Copy the **bot token** (format: `123456789:ABCdefGHI...`)\r\n4. Add the bot to your target group (or just DM the bot)\r\n5. Get the **chat ID**:\r\n   - DM `@userinfobot` → it replies with your User ID (for private messages)\r\n   - Or call `https://api.telegram.org/bot<TOKEN>/getUpdates` after sending a message in the group → find `\"chat\":{\"id\":-100xxxxx}` in the response\r\n   - Group/channel IDs are negative numbers (e.g., `-1001234567890`)\r\n\r\n> Push language: **English**\r\n> Mainland China note: Requires a proxy. Pass `--proxy http://host:port` on the command line.\r\n\r\n### Proxy Configuration\r\n\r\nFor Discord and Telegram in mainland China, pass the proxy on the command line:\r\n\r\n```bash\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --discord_webhook https://discord.com/api/webhooks/... \\\r\n  --proxy http://192.168.1.1:7890\r\n```\r\n\r\n> The proxy is only used for Discord/Telegram. Feishu does not go through the proxy.\r\n\r\n---\r\n\r\n## OpenClaw Channel Integration\r\n\r\nThe push channels above are one-way: they only send alarm notifications OUT.\r\n\r\nIf you want to **directly interact with OpenClaw via a messaging app** (e.g., send a message in Telegram to trigger detection, or receive OpenClaw's conversational responses), you need to configure **OpenClaw Channels** in `openclaw.json`. This bypasses the OpenClaw backend chat window, letting the app become the primary interface.\r\n\r\n### Feishu Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"feishu\": {\r\n      \"enabled\": true,\r\n      \"appId\": \"cli_xxxxxx\",\r\n      \"appSecret\": \"xxxxxxxxxxxxxxxx\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n**How to obtain:** Create an app in [Feishu Open Platform](https://open.feishu.cn/), get the App ID and App Secret, then enable the bot messaging capability.\r\n\r\n### Telegram Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"telegram\": {\r\n      \"enabled\": true,\r\n      \"botToken\": \"123456789:ABCdefGHIjklMNO...\",\r\n      \"dmPolicy\": \"open\",\r\n      \"proxy\": \"http://192.168.1.1:7890\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `botToken` | Same bot token from @BotFather (same one used for push, or a different bot) |\r\n| `dmPolicy` | `\"open\"` = accept messages from anyone; `\"pairing\"` = require `/pair` + approval; `\"allowlist\"` = only allow specific User IDs |\r\n| `proxy` | **Must** include protocol prefix (`http://` or `socks5://`). Required in mainland China. |\r\n\r\n**`dmPolicy` options:**\r\n\r\n| Policy | Behavior |\r\n|--------|----------|\r\n| `open` | Any Telegram user can DM the bot and interact with OpenClaw |\r\n| `pairing` | User sends `/pair` to the bot → terminal shows a CODE → run `openclaw pairing approve telegram <CODE>` to approve |\r\n| `allowlist` | Only User IDs listed in `allowFrom` are allowed. Example: `\"allowFrom\": [\"tg:123456789\"]` |\r\n\r\n> To find your Telegram User ID: DM `@userinfobot` on Telegram, or check the terminal logs during pairing.\r\n\r\n### Discord Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"discord\": {\r\n      \"enabled\": true,\r\n      \"token\": \"MTUwODM4Mzk4...\",\r\n      \"dmPolicy\": \"open\",\r\n      \"allowFrom\": [\"*\"],\r\n      \"requireMention\": true\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `token` | Bot token from [Discord Developer Portal](https://discord.com/developers/applications) → Application → Bot → Token |\r\n| `dmPolicy` | Same as Telegram: `\"open\"` / `\"pairing\"` / `\"allowlist\"` |\r\n| `allowFrom` | `[\"*\"]` = accept all; or specific User IDs like `[\"discord:123456\"]` |\r\n| `requireMention` | If `true`, the bot only responds when @mentioned; if `false`, responds to all messages in allowed channels |\r\n| `guilds` | (Optional) Restrict to specific server IDs: `[\"1234567890\"]` |\r\n\r\n**How to create a Discord bot:**\r\n\r\n1. Go to [Discord Developer Portal](https://discord.com/developers/applications)\r\n2. Click **New Application** → name it → **Bot** tab → click **Reset Token** → copy the token\r\n3. Under **Privileged Gateway Intents**, enable **MESSAGE CONTENT INTENT**\r\n4. **OAuth2** tab → **URL Generator** → select scopes: `bot` → permissions: `Send Messages`, `Read Message History` → copy the invite URL\r\n5. Open the invite URL in your browser to add the bot to your server\r\n\r\n> **Important:** Discord channel in `openclaw.json` does **NOT** support a `proxy` field. If you need a proxy for Discord, set it via environment variable:\r\n> ```bash\r\n> export HTTPS_PROXY=http://192.168.1.1:7890\r\n> ```\r\n\r\n### Push Channels vs. OpenClaw Channels — Summary\r\n\r\n| | Alarm Push Channels (this skill) | OpenClaw Channels (openclaw.json) |\r\n|---|---|---|\r\n| Direction | One-way: skill → app (notification) | Two-way: user ↔ OpenClaw (conversation) |\r\n| Purpose | Send alarm messages when events detected | Allow user to trigger/control skills via messaging apps |\r\n| Configuration | `--feishu_webhook` / `--discord_webhook` / `--telegram_bot_token` | `openclaw.json` → `channels` block |\r\n| Requires | Webhook URLs or bot token | Full bot setup + OpenClaw runtime |\r\n\r\n---\r\n\r\n## File Structure\r\n\r\n```\r\nkami-conflict-detection/\r\n├── conflict_detector_last.py   # Main detection script\r\n├── yolov8s-worldv2.onnx        # YOLO person detection model\r\n├── setup.sh                    # Environment setup script\r\n├── requirements.txt            # Python dependencies\r\n├── config.json                 # Persistent user configuration (cameras, API key, push)\r\n├── SKILL.md                    # OpenClaw skill definition\r\n├── README.md                   # This file\r\n├── .venv/                      # Virtual environment (created by setup.sh)\r\n├── alerts/                     # Alert video clips output (per-camera subfolders)\r\n│   ├── <camera_name>/\r\n│   │   └── conflict_<camera_name>_YYYYMMDD_HHMMSS.mp4\r\n│   └── pending.jsonl           # Alarm inbox consumed by the heartbeat task\r\n└── conflict_detector.log       # Runtime log file\r\n```\r\n\r\n## Troubleshooting\r\n\r\n**Virtual environment not found**\r\n→ Run `bash setup.sh`\r\n\r\n**Model file missing (`yolov8s-worldv2.onnx`)**\r\n→ The script will auto-download the pre-exported ONNX bundle on first run from `https://publicfiles.xiaoyi.com/kami-conflict-detection-model.zip`, extract it, move `yolov8s-worldv2.onnx` next to the script, and delete the temp folder. If this fails (e.g. no internet, `unzip` missing), manually fetch the zip, unzip it, and place the `.onnx` in the skill directory.\r\n\r\n**RTSP connection failure**\r\n→ Verify the camera is online, check the URL format in `cameras[].rtsp_url`, confirm network connectivity.\r\n\r\n**API key error**\r\n→ Ensure your Kami API key is valid. If you don't have one, register at https://kamiclaw-skill.kamihome.com. You can enjoy a free credit limit of 200 credits.\r\n\r\n**No alerts generated**\r\n→ Check `conflict_detector.log`. Common causes:\r\n  - Fewer than 2 people in frame (YOLO pre-filter not triggered)\r\n  - YOLO confidence too high — try `--conf_threshold 0.15`\r\n  - LLM API returning \"no conflict\" — review the video to confirm actual conflict exists\r\n\r\n**Script exits immediately with code 1**\r\n→ Check log for details. Usually: model file missing, no camera configured (empty `cameras[]` and no `--rtsp_url`), or API key not provided.\r\n\r\n**Feishu/Discord/Telegram push not working**\r\n→ Check:\r\n  - Webhook URL / bot token correct?\r\n  - Proxy configured? (Discord/Telegram in mainland China require proxy — set `proxy` in `config.json` or pass `--proxy`)\r\n  - Network reachable? (try `curl <webhook_url>` manually)\r\n  - Check `conflict_detector.log` for push error messages\r\n\r\n**Feishu card snapshot is just a URL/path, not an inline image**\r\n→ The skill renders the snapshot inline only when `feishu_app_id` + `feishu_app_secret` are provided. Without them, it falls back to a clickable sm.ms URL or the local file path. Add a self-built Feishu app (see [Alarm Push Channels → Feishu](#1-feishu-lark--custom-bot-webhook)) and write the App ID / Secret into `config.json`.\r\n\r\n**`unzip` not found during `setup.sh`**\r\n→ Install `unzip` (e.g. `apt install unzip` / `brew install unzip`) and rerun `bash setup.sh`. The model bundle is distributed as a zip and requires `unzip` to extract.\n\nFile v2.0.4:_meta.json\n\n{\n  \"ownerId\": \"kn7e9156e1awf00v1sas2wkdfd85a4zh\",\n  \"slug\": \"kami-conflict-detection\",\n  \"version\": \"2.0.4\",\n  \"publishedAt\": 1780984567493\n}\n\nFile v2.0.4:skill-card.md\n\n## Description:\n\nDetects physical conflicts such as fighting, shoving, and scuffling from one or more RTSP camera streams or local video files.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[13681882136](https://clawhub.ai/user/13681882136)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, facility operators, and security teams use this skill to monitor RTSP cameras or test video files for possible physical altercations and route alerts to local output or configured messaging channels.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Selected camera frames leave the local environment for Kami conflict analysis.\n\nMitigation: Use the skill only with approved cameras and environments, review the privacy policy, and confirm that surveillance footage may be sent to the Kami service.\n\nRisk: Snapshots and alert details may be sent to configured third-party channels or public image hosting.\n\nMitigation: Use private, approved messaging channels and avoid the Feishu sm.ms fallback unless public image hosting is acceptable.\n\nRisk: Configuration and logs can contain sensitive camera URLs, API keys, webhooks, or alert details.\n\nMitigation: Protect config.json and logs with local access controls, avoid committing them, and use dedicated low-privilege camera credentials.\n\nRisk: Setup downloads dependencies and a model artifact during installation or first run.\n\nMitigation: Review and pin setup dependencies and model artifacts before deployment in controlled or regulated environments.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/13681882136/skills/kami-conflict-detection)\n- [KamiClaw service](https://kamiclaw-skill.kamihome.com)\n- [Kami conflict detection model bundle](https://publicfiles.xiaoyi.com/kami-conflict-detection-model.zip)\n- [uv Python package manager](https://github.com/astral-sh/uv)\n\n## Skill Output:\n\n**Output Type(s):** [guidance, shell commands, configuration, JSON, files]\n\n**Output Format:** [Markdown guidance with shell commands and JSON alert records; the detector also saves MP4 clips and JPEG snapshots.]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires configured camera sources and a Kami API key; alerts can be emitted to stdout, an inbox file, Feishu, Discord, or Telegram.]\n\n## Skill Version(s):\n\n2.0.4 (source: frontmatter and release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v2.0.4:config.json\n\n{\r\n  \"cameras\": [\r\n    {\r\n      \"name\": \"\",\r\n      \"rtsp_url\": \"\"\r\n    }\r\n  ],\r\n  \"kami_api_key\": \"\",\r\n  \"feishu_webhook\": \"\",\r\n  \"feishu_secret\": \"\",\r\n  \"feishu_app_id\": \"\",\r\n  \"feishu_app_secret\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\n\nFile v2.0.4:requirements.txt\n\nonnxruntime\r\nopencv-python-headless\r\nnumpy\r\nrequests\r\nultralytics\n\nArchive v2.0.3: 8 files, 30438 bytes\n\nFiles: config.json (212b), conflict_detector_last.py (43362b), README.md (21155b), requirements.txt (67b), setup.sh (2246b), skill-card.md (3003b), SKILL.md (14628b), _meta.json (142b)\n\nFile v2.0.3:SKILL.md\n\n---\r\nname: kami-conflict-detection\r\ndescription: |\r\n  Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many\r\n  RTSP camera streams concurrently. Continuous mode: a single Python process monitors every\r\n  configured camera in parallel, pushes a per-camera alert (stdout / inbox file / Feishu /\r\n  Discord / Telegram) on each detected event, and keeps running — it does NOT exit on\r\n  detection.\r\nversion: 3.0.0\r\nauthor: kami-smarthome\r\ntags:\r\n  - smart-home\r\n  - conflict-detection\r\n  - fight-detection\r\n  - violence-detection\r\n  - yolo\r\n  - rtsp\r\n  - surveillance\r\n  - security\r\n  - edge-ai\r\n  - multi-camera\r\n  - openclaw\r\ntriggers:\r\n  - detect fighting\r\n  - detect conflict\r\n  - detect physical conflict\r\n  - check for fighting\r\n  - is anyone fighting\r\n  - detect scuffle\r\n  - detect shoving\r\n  - monitor for fights\r\n  - start conflict monitoring\r\n  - begin violence detection\r\nmetadata:\r\n  openclaw:\r\n    requires:\r\n      bins:\r\n        - python3.10\r\n      hardware:\r\n        cpu: \"4+ cores (x86_64 / ARM64)\"\r\n        memory: \"8 GB+\"\r\n        storage: \"10 GB+\"\r\n        gpu: \"optional (speeds up ONNX inference)\"\r\n      network:\r\n        - \"RTSP camera access (LAN)\"\r\n        - \"Internet (KamiClaw API)\"\r\n      devices:\r\n        - \"RTSP IP camera\"\r\n    emoji: \"🥊\"\r\n---\r\n\r\n# Kami Conflict Detection\r\n\r\nDetect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many RTSP camera streams concurrently. Continuous mode — the process never exits on detection; every confirmed event is pushed as an alert tagged with the originating camera, then monitoring resumes.\r\n\r\n## Privacy Policy\r\n\r\nFor privacy policy details, see: <https://kamiclaw-skill.kamihome.com/privacy>\r\n\r\n## How It Works\r\n\r\n1. **YOLO pre-filter** — lightweight person detection counts people in each frame (must be ≥ `min_persons`, default 2).\r\n2. **Multi-frame collection** — collects N frames with a configurable time gap.\r\n3. **LLM conflict analysis** — frames are sent to the Kami detection API for violence/conflict judgment.\r\n4. **Continuous alerting** — on a confirmed conflict, the worker saves a per-camera video clip, pushes an alert with `camera = <camera_name>` to every configured channel, and **immediately resumes monitoring**. The process keeps running until the user stops it (Ctrl+C / OpenClaw shutdown).\r\n\r\n> Multi-camera: every entry in `config.json -> cameras[]` runs in its own worker thread inside the same process. The YOLO ONNX session, the conflict analyzer and all push channels are shared once across cameras. Push channels are **shared** — no per-camera webhook split. Stranger / clip / log lines are namespaced by camera name.\r\n\r\n## When to Use\r\n\r\n- Monitor one or many camera feeds for physical fights or scuffles\r\n- Detect shoving, pushing, or violent behavior between people\r\n- Run conflict detection on a local video file for testing\r\n- Set up automated surveillance alerts for physical altercations\r\n\r\n## Installation\r\n\r\n```bash\r\nbash setup.sh\r\n```\r\n\r\nNo `sudo` required. The script auto-bootstraps **python3.10** in user space (via [uv](https://github.com/astral-sh/uv) when needed), creates `.venv/`, installs dependencies, and prepares `alerts/`. Idempotent — safe to re-run.\r\n\r\n## Prerequisites\r\n\r\n- Linux/macOS shell with `curl` (or `wget`) available\r\n- `yolov8s-worldv2.onnx` model file in the skill directory (auto-downloaded + exported from `.pt` on first run if missing)\r\n- One or more RTSP cameras online, OR a local video file for testing\r\n- Kami API key (`--kami_api_key` or write to `config.json`). Register at <https://kamiclaw-skill.kamihome.com> for a free 200-credit quota.\r\n- `setup.sh` has been run at least once\r\n\r\n> Python 3.10 is **not** a manual prerequisite — `setup.sh` will install it locally without sudo if missing.\r\n\r\n## Parameters\r\n\r\nConfirm the following before running. The fields marked **(persisted in `config.json`)** can be saved to `config.json` next to the script so the user does not need to provide them every run — see [Configuration Persistence](#configuration-persistence) below.\r\n\r\n| Parameter | Default | Description |\r\n|-----------|---------|-------------|\r\n| `--rtsp_url` | *(empty; see `cameras[]` in `config.json`)* | Single-camera CLI override. When set, takes priority over `cameras[]`. |\r\n| `--camera_name` | *(empty)* | Optional camera name used together with `--rtsp_url`. Defaults to `camera_0`. |\r\n| `--kami_api_key` | *(persisted in `config.json`)* | Kami API key |\r\n| `--yolo_model` | `yolov8s-worldv2.onnx` | YOLO model file path |\r\n| `--conf_threshold` | `0.25` | YOLO confidence threshold |\r\n| `--min_persons` | `2` | Minimum person count to trigger LLM analysis |\r\n| `--sample_interval` | `1.0` | YOLO pre-filter interval (seconds) |\r\n| `--multi_frame_count` | `3` | Frames per LLM analysis |\r\n| `--multi_frame_gap` | `0.5` | Gap between collected frames (seconds) |\r\n| `--buffer_seconds` | `30` | Ring buffer duration for clip export |\r\n| `--clip_before` | `5` | Seconds of video before the conflict |\r\n| `--clip_after` | `5` | Seconds of video after the conflict |\r\n| `--output_dir` | `alerts/` | Root directory for saved video clips. Per-camera subfolders (`alerts/<camera_name>/`) are created automatically. |\r\n| `--fps` | `15` | Video stream frame rate |\r\n| `--inbox_file` | `alerts/pending.jsonl` | Alarm inbox consumed by the heartbeat task |\r\n| `--feishu_webhook` | *(persisted in `config.json`)* | Feishu custom bot webhook URL |\r\n| `--feishu_secret` | *(optional, command-line only)* | Feishu signing secret (only if signing enabled) |\r\n| `--discord_webhook` | *(persisted in `config.json`)* | Discord channel webhook URL |\r\n| `--telegram_bot_token` | *(persisted in `config.json`)* | Telegram Bot token |\r\n| `--telegram_chat_id` | *(persisted in `config.json`)* | Telegram target chat/group/channel ID |\r\n| `--proxy` | *(optional, command-line only)* | HTTPS proxy for Discord/Telegram (not used for Feishu) |\r\n\r\n**Only ask the user about a parameter if (a) it's still empty in `config.json` AND has no command-line value, OR (b) the user explicitly asks to adjust it. Do NOT pause the conversation for blanket parameter confirmation.**\r\n\r\n## Configuration Persistence (`config.json`)\r\n\r\nA `config.json` file lives next to the script with the following empty-by-default fields:\r\n\r\n```json\r\n{\r\n  \"cameras\": [\r\n    {\r\n      \"name\": \"\",\r\n      \"rtsp_url\": \"\"\r\n    }\r\n  ],\r\n  \"kami_api_key\": \"\",\r\n  \"feishu_webhook\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\r\n```\r\n\r\n**`cameras` array — one entry per RTSP source.** All cameras run concurrently inside a single process, sharing the loaded YOLO ONNX model, the conflict analyzer and the same set of push channels. Add a new entry to the array for each additional camera (e.g. `living_room`, `office_door`, …).\r\n\r\n| Camera field | Required | Behaviour when empty |\r\n|--------------|----------|----------------------|\r\n| `name` | recommended | Free-form short label written into every alert as `alert.camera`, prefixed to `alert.message` as `[name]`, and used as the snapshot subdirectory under `alerts/<name>/`. If the user does not supply one, the script auto-assigns `camera_0`, `camera_1`, … and logs the assignment. |\r\n| `rtsp_url` | **yes** | Entry is skipped if empty. Accepts `rtsp://...`, `http(s)://...`, or a local file path. |\r\n\r\nResolution order at runtime: **`--rtsp_url` (single-camera CLI override)** → **`cameras[]` in `config.json`** → empty (fatal: `EXIT_ERROR`).\r\n\r\n**Workflow OpenClaw MUST follow (single-turn, no extra confirmation):**\r\n\r\n1. On first launch, read `config.json` and identify which fields are still empty.\r\n2. **Ask the user only for the empty fields**:\r\n   - **Cameras** — for each camera the user wants to monitor, ask for the `rtsp_url` AND a camera `name` **in the same question**:\r\n     - The `name` is a free-form short label, ideally a natural-language tag like `living_room` / `front_door` / `office`. It will appear in every alarm to identify which camera fired the event.\r\n     - **If the user only provides the `rtsp_url` and omits the name, IMMEDIATELY tell them: \"No camera name provided. The script will auto-assign an incremental id like `camera_0` / `camera_1`. Do you want to proceed with the auto id?\"** Only proceed with the auto id once the user accepts (or stays silent / says ok). Do NOT silently assign the auto id without notifying.\r\n     - Persist each camera as an object in the `cameras` array.\r\n   - **Kami API key** — required for the LLM conflict analysis.\r\n   - **Push channels** — which to enable (Feishu / Discord / Telegram) and their credentials. Push channels are **shared** across all cameras (no per-camera split); every camera uses the same webhooks.\r\n3. **Write the user's answers back into `config.json`** (preserve existing non-empty fields). Subsequent launches skip these prompts.\r\n4. **Immediately in the SAME turn**, run `bash setup.sh` (idempotent) and launch the detector. Do NOT end the turn after step 3 — do NOT wait for the user to say \"start\" or \"begin\".\r\n5. If all required fields are already non-empty on entry, skip steps 2–3 and go straight to step 4.\r\n\r\n## Alarm Push Channels\r\n\r\nAlarms can be pushed through the following channels — all optional, configure any combination:\r\n\r\n| Channel | Required Parameters |\r\n|---------|--------------------|\r\n| **Feishu** (custom bot) | `--feishu_webhook` (and optional `--feishu_secret`) |\r\n| **Discord** (channel webhook) | `--discord_webhook` |\r\n| **Telegram** (Bot API) | `--telegram_bot_token` + `--telegram_chat_id` |\r\n\r\nBeyond app push, every alarm is **always** delivered through two redundant local channels:\r\n\r\n1. **stdout JSON line** — OpenClaw reads stdout line-by-line and reports each alert in chat (no exit; the process keeps running).\r\n2. **Inbox file `alerts/pending.jsonl`** — appended on every alarm; consumed by the heartbeat task as a fallback.\r\n\r\n> Refer to the official docs of each platform for how to obtain webhook URLs / bot tokens / chat IDs.\r\n> In mainland China, Discord and Telegram require a proxy (`--proxy` or `HTTPS_PROXY`).\r\n> Push card labels are language-fixed: **Feishu → Chinese**, **Discord/Telegram → English**.\r\n\r\n## Usage\r\n\r\n```bash\r\n# First time only\r\nbash setup.sh\r\n\r\n# Multi-camera mode (recommended): write cameras[] into config.json once,\r\n# then just run the script with no extra args.\r\n.venv/bin/python conflict_detector_last.py\r\n\r\n# Single-camera CLI override (one-off, e.g., for testing a video file)\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url /path/to/test_video.mp4 \\\r\n  --camera_name test_video \\\r\n  --kami_api_key YOUR-API-KEY\r\n```\r\n\r\n## Output Format (stdout JSON)\r\n\r\nWhen a conflict is detected, the worker prints one JSON line and continues monitoring:\r\n\r\n```json\r\n{\r\n  \"alert\": \"conflict_detected\",\r\n  \"camera\": \"living_room\",\r\n  \"timestamp\": \"2025-01-15T14:30:22.123456\",\r\n  \"description\": \"Two people are engaged in a physical altercation\",\r\n  \"video_clip\": \"alerts/living_room/conflict_living_room_20250115_143022.mp4\",\r\n  \"clip_duration\": \"10s\",\r\n  \"message\": \"[living_room] Warning: Physical conflict detected. ...\"\r\n}\r\n```\r\n\r\n## Exit Codes\r\n\r\n| Code | Meaning | OpenClaw Action |\r\n|------|---------|-----------------|\r\n| `0` | Normal exit (Ctrl+C, all streams ended, no fatal error) | Inform user; optionally restart |\r\n| `1` | Runtime error (model not found, missing API key, no camera configured) | Report error; check `conflict_detector.log` |\r\n\r\n> Continuous mode: detected conflicts do NOT terminate the process — they only push alerts. The process stays alive until interrupted.\r\n\r\n## Strict Rules (MUST Follow)\r\n\r\n- **RULE**: Alarms flow via (a) stdout JSON line, (b) inbox file, (c) Feishu (optional), (d) Discord (optional), (e) Telegram (optional). Never rely on a single channel.\r\n- **RULE (continuous mode)**: A detected conflict NEVER terminates the process. The worker pushes the alert and resumes monitoring on the same stream. There is no `exit 10`; there is no detect-report-restart loop.\r\n- **RULE (multi-camera)**: All cameras in `config.json -> cameras[]` are monitored concurrently inside a single Python process (shared YOLO ONNX session, shared analyzer, one inference lock, per-camera FrameGrabber + worker thread). Never spawn one process per camera.\r\n- **RULE (camera id)**: Every alarm written to `pending.jsonl`, Feishu, Discord and Telegram MUST include the camera name in the `camera` field. The `message` field MUST be prefixed with `[<camera_name>] `. Snapshots MUST be written under `alerts/<camera_name>/`.\r\n- **RULE (camera name prompt)**: When asking the user for an RTSP URL, the agent MUST in the SAME question also ask for a human-readable camera `name` (e.g. `living_room`, `front_door`). If the user provides the URL but skips the name, the agent MUST EXPLICITLY notify them that an auto id (`camera_0`, `camera_1`, …) will be used; never assign the auto id silently.\r\n- **RULE (shared push)**: Feishu / Discord / Telegram credentials in `config.json` apply to every camera. There is no per-camera webhook split.\r\n- **RULE**: Every heartbeat consumes `alerts/pending.jsonl`; non-empty → proactive chat summary; empty → `HEARTBEAT_OK`.\r\n- **RULE**: Consumed alarms are MOVED to `alerts/consumed/`, not deleted.\r\n- **RULE**: Before launch, read `config.json`; only ask the user for fields that are empty, and **write the answers back into `config.json`** so subsequent launches are non-interactive.\r\n- **RULE (auto-launch)**: Once at least one camera (with `rtsp_url`) and `kami_api_key` are present in `config.json` (either pre-existing or just written), the agent MUST run `bash setup.sh` and launch the detector **in the same conversation turn**. Never end the turn at \"config saved\" — the user does NOT need to send a second message like \"start it\" or \"begin detection\".\r\n- **RULE**: Warn the user if no push channel is configured (chat-window push still active).\r\n\r\n## Troubleshooting\r\n\r\n| Problem | Fix |\r\n|---------|-----|\r\n| Virtual environment not found | Run `bash setup.sh` |\r\n| Model file missing | Place `yolov8s-worldv2.onnx` in the skill directory, or let the script auto-export it on first run |\r\n| RTSP connection failure | Verify camera is online; check `cameras[].rtsp_url` |\r\n| LLM API failure | Check `kami_api_key`; verify network to the Kami API endpoint |\r\n| No alerts generated | See `conflict_detector.log`; try lowering `--conf_threshold` |\r\n| Script exits with code 1 | Check log; common causes: missing model, no camera configured, missing API key |\n\nFile v2.0.3:README.md\n\n# Kami Conflict Detection\r\n\r\nReal-time multi-camera physical conflict (fighting, shoving, scuffling) detection for RTSP camera streams or local video files. Uses YOLO for person pre-filtering and a remote multimodal LLM API for conflict analysis.\r\n\r\n**Multi-camera capable.** A single process can monitor an arbitrary number of RTSP cameras concurrently (e.g. `living_room` + `office_door` + …). The YOLO ONNX session and conflict analyzer are loaded **once and shared** across all cameras; each camera owns an independent frame grabber, worker thread and snapshot directory. Push channels (Feishu / Discord / Telegram) are shared — every camera uses the same webhooks. The process keeps running across detections — it does NOT exit on event.\r\n\r\n## How It Works\r\n\r\nFor each configured camera, a dedicated worker thread polls the stream, uses YOLO to count persons in each frame, and when 2+ people are detected, collects multiple frames and sends them to the Kami detection API for conflict analysis. When a conflict is confirmed, the worker saves a per-camera video clip covering the moments before and after the incident, prints an alert JSON line tagged with the camera name to stdout, pushes the alert to every configured channel, and **immediately resumes monitoring**. The process keeps running until the user stops it (Ctrl+C / OpenClaw shutdown).\r\n\r\n```\r\nFor each camera (parallel worker thread):\r\n  Read stream → YOLO counts persons → 2+ people? → Collect frames → LLM analysis\r\n                                                                        ↓\r\n                                            Conflict? → save per-camera clip\r\n                                                     → push alert (stdout / inbox / Feishu / Discord / Telegram)\r\n                                                     → resume monitoring (no exit)\r\n```\r\n\r\n## Quick Start\r\n\r\n```bash\r\n# 1. Install dependencies\r\nbash setup.sh\r\n\r\n# 2. Configure cameras and API key in config.json (recommended), then run:\r\n.venv/bin/python conflict_detector_last.py\r\n\r\n# Or for a one-off single-camera run via CLI override:\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --camera_name living_room \\\r\n  --kami_api_key YOUR-API-KEY\r\n```\r\n\r\n## Installation\r\n\r\n```bash\r\nbash setup.sh\r\n```\r\n\r\nNo `sudo` required. The script will:\r\n- Auto-bootstrap **Python 3.10** in user space (via [uv](https://github.com/astral-sh/uv)) — no system-level package manager needed\r\n- Create a `.venv/` virtual environment\r\n- Install all pip dependencies (`onnxruntime`, `opencv-python-headless`, `numpy`, `requests`)\r\n- Create `alerts/` output directory\r\n\r\n## API Key\r\n\r\nThis skill requires a Kami API key for the conflict analysis LLM service.\r\n\r\n**If you don't have a key yet, register and obtain one at:**\r\n> https://kamiclaw-skill.kamihome.com\r\nYou can enjoy a free credit limit of 200 credits.\r\n\r\nProvide the key via:\r\n- `config.json` (recommended) — the value persists across runs\r\n- Command line: `--kami_api_key YOUR-KEY` (overrides `config.json` for this run only)\r\n\r\n## Configuration File (config.json)\r\n\r\nA `config.json` file in the skill directory persists user-provided values so you don't have to pass them on every run. Empty fields are ignored. Command-line arguments take priority over `config.json`.\r\n\r\n```json\r\n{\r\n  \"cameras\": [\r\n    {\r\n      \"name\": \"living_room\",\r\n      \"rtsp_url\": \"rtsp://192.168.1.100/live/stream1\"\r\n    },\r\n    {\r\n      \"name\": \"office_door\",\r\n      \"rtsp_url\": \"rtsp://192.168.1.101/live/stream1\"\r\n    }\r\n  ],\r\n  \"kami_api_key\": \"YOUR-KAMI-KEY\",\r\n  \"feishu_webhook\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\r\n```\r\n\r\nResolution order at runtime: **`--rtsp_url` (single-camera CLI override)** → **`cameras[]` in `config.json`** → empty (fatal). When OpenClaw asks the user for these values, write the answers into `config.json`.\r\n\r\n### Multi-Camera Mode\r\n\r\nThe `cameras` array can contain one or many entries. All entries are monitored concurrently inside a **single Python process** (single-process / multi-thread / shared-model architecture):\r\n\r\n| Field | Required | Behaviour when empty |\r\n|-------|----------|----------------------|\r\n| `name` | recommended | Free-form human-readable label (e.g. `living_room`, `front_door`, `office`). The agent should ask for it together with the `rtsp_url`. If the user does not provide one, the script auto-assigns `camera_0`, `camera_1`, … by array index and logs the assignment. The name is written into every alarm as `alert.camera`, prefixed to `alert.message` as `[name]`, and used as the snapshot subdirectory under `alerts/`. |\r\n| `rtsp_url` | **yes** | Entry is skipped if empty. Accepts `rtsp://...`, `http(s)://...`, or a local file path. |\r\n\r\n**Push channels are shared by all cameras.** The `feishu_webhook` / `discord_webhook` / `telegram_*` fields apply to every detected event; there is no per-camera webhook split. Every alert payload carries `\"camera\": \"<name>\"` and an `[<name>]` prefix in `message`, so the receiving operator can tell which camera fired the alarm.\r\n\r\n**Continuous mode.** A detected conflict NEVER terminates the process. The worker pushes the alert and resumes monitoring on the same stream. The process only exits on Ctrl+C, all streams ending, or a fatal startup error.\r\n\r\n## Prerequisites\r\n\r\n- Linux/macOS shell with `curl` (or `wget`) available\r\n- `yolov8s-worldv2.onnx` model file in the skill directory (auto-downloaded + exported from `.pt` on first run if missing)\r\n- One or more RTSP cameras online and network-reachable, OR a local video file for testing\r\n- Kami API key (see above)\r\n- `setup.sh` has been run at least once\r\n\r\n> Python 3.10 is **not** a manual prerequisite — `setup.sh` will install it locally without sudo if missing.\r\n\r\n## Parameters\r\n\r\n### Required (via `config.json` or CLI)\r\n\r\n| Parameter | Description |\r\n|-----------|-------------|\r\n| `cameras[]` (config.json) **or** `--rtsp_url` + `--camera_name` (CLI) | Video sources. Provide cameras as an array in `config.json`, or override with a single source on the CLI. Each entry accepts an RTSP URL or a local file path. |\r\n| `--kami_api_key` | Kami API key for conflict analysis. Register at https://kamiclaw-skill.kamihome.com — you can enjoy a free credit limit of 200 credits. |\r\n\r\n### Optional\r\n\r\n| Parameter | Default | Type | Description |\r\n|-----------|---------|------|-------------|\r\n| `--rtsp_url` | *(empty)* | str | Single-camera CLI override. When set, takes priority over `cameras[]` in `config.json`. |\r\n| `--camera_name` | *(empty)* | str | Camera name used together with `--rtsp_url`. Defaults to `camera_0` if omitted. |\r\n| `--yolo_model` | `yolov8s-worldv2.onnx` | path | Path to the YOLO ONNX model file. |\r\n| `--conf_threshold` | `0.25` | float (0-1) | YOLO detection confidence threshold. Lower detects more persons but may include false positives. |\r\n| `--min_persons` | `2` | int | Minimum number of persons in frame to trigger LLM analysis. A conflict requires at least 2 people. |\r\n| `--sample_interval` | `1.0` | float (seconds) | How often to run YOLO person detection on the stream. Lower values increase CPU usage but improve responsiveness. |\r\n| `--multi_frame_count` | `3` | int | Number of frames to collect before sending to LLM. More frames give the LLM better context but increase latency. |\r\n| `--multi_frame_gap` | `0.5` | float (seconds) | Time gap between collected frames. Spreads frames over time to capture motion progression. |\r\n| `--buffer_seconds` | `30` | int (seconds) | Ring buffer duration. Stores recent frames in memory for video clip export when a conflict is detected. |\r\n| `--clip_before` | `5` | int (seconds) | Seconds of video to include before the conflict moment in the exported clip. |\r\n| `--clip_after` | `5` | int (seconds) | Seconds of video to include after the conflict moment. The script waits this long after detection before exporting. |\r\n| `--output_dir` | `./alerts` | path | Root directory for saved video clips. Per-camera subfolders (`alerts/<camera_name>/`) are created automatically. |\r\n| `--fps` | `15` | int | Frame rate for the video stream reader. Should match or approximate the camera's actual frame rate. |\r\n\r\n### Parameter Tuning Guide\r\n\r\n| Scenario | Adjustment |\r\n|----------|------------|\r\n| Missing persons in frame | Lower `--conf_threshold` (e.g., 0.25→0.15) |\r\n| Too many false person detections | Raise `--conf_threshold` (e.g., 0.25→0.4) |\r\n| Want to detect solo aggression | Set `--min_persons 1` (not recommended, high false positive rate) |\r\n| High CPU usage | Increase `--sample_interval` (e.g., 1.0→3.0) |\r\n| LLM analysis too slow | Reduce `--multi_frame_count` (e.g., 3→2) |\r\n| Want longer video clips | Increase `--clip_before` and `--clip_after` |\r\n| Memory constrained | Reduce `--buffer_seconds` (e.g., 30→15) |\r\n\r\n## Output Format\r\n\r\nWhen a conflict is detected, the worker prints one JSON line and continues monitoring:\r\n\r\n```json\r\n{\r\n  \"alert\": \"conflict_detected\",\r\n  \"camera\": \"living_room\",\r\n  \"timestamp\": \"2025-01-15T14:30:22.123456\",\r\n  \"description\": \"Two people are engaged in a physical altercation\",\r\n  \"video_clip\": \"alerts/living_room/conflict_living_room_20250115_143022.mp4\",\r\n  \"clip_duration\": \"10s\",\r\n  \"message\": \"[living_room] Warning: Physical conflict detected. Two people are engaged in a physical altercation. Video clip saved to alerts/living_room/conflict_living_room_20250115_143022.mp4. Please review and take appropriate action.\"\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `alert` | Event type, always `\"conflict_detected\"` |\r\n| `camera` | The camera name that fired this alert (matches a `cameras[].name` entry, or `camera_0`/`camera_1`/… if auto-assigned) |\r\n| `timestamp` | ISO 8601 timestamp of the alert |\r\n| `description` | LLM-generated description of the conflict |\r\n| `video_clip` | File path to the saved video clip (under `alerts/<camera_name>/`) |\r\n| `clip_duration` | Total duration of the saved clip |\r\n| `message` | Pre-formatted alert message ready for display, prefixed with `[<camera_name>] ` |\r\n\r\n## Exit Codes\r\n\r\n| Code | Meaning | Typical Action |\r\n|------|---------|----------------|\r\n| `0` | Normal exit — Ctrl+C, all streams ended, no fatal error. | End session. |\r\n| `1` | Runtime error — model missing, no camera configured, API key not set. | Check `conflict_detector.log` for details. |\r\n\r\n> Continuous mode: detected conflicts do NOT terminate the process — they only push alerts. The process stays alive until interrupted.\r\n\r\n## Log File\r\n\r\nAll operational logs are written to `conflict_detector.log` in the script directory. Logs go to stderr (not stdout) to keep stdout clean for JSON output only.\r\n\r\n## Examples\r\n\r\n```bash\r\n# Recommended: write cameras[] + kami_api_key into config.json once,\r\n# then just run the script with no extra args. All cameras run in parallel.\r\n.venv/bin/python conflict_detector_last.py\r\n\r\n# Single-camera CLI override (one-off, e.g., for testing a video file)\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url /home/user/test_fight_video.mp4 \\\r\n  --camera_name test_video \\\r\n  --kami_api_key YOUR-API-KEY\r\n\r\n# Longer video clips, faster sampling\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --clip_before 10 \\\r\n  --clip_after 10 \\\r\n  --sample_interval 0.5\r\n```\r\n\r\n---\r\n\r\n## Alarm Push Channels (Detailed)\r\n\r\nBeyond the default JSON stdout output, alarms can be simultaneously pushed to external messaging platforms. These are **pure push notifications** — they only send alerts OUT, they do NOT let you interact with the detector via those apps. (For interactive control via app, see [OpenClaw Channel Integration](#openclaw-channel-integration) below.)\r\n\r\nAll channels are optional. Configure any combination via command-line arguments or `config.json`. Push channels are **shared by all cameras** — every detected event is pushed to the same set of webhooks, but the `camera` field in the payload (and the `[<name>]` prefix in `message`) tells the receiver which camera fired the alarm.\r\n\r\n### 1. Feishu (Lark) — Custom Bot Webhook\r\n\r\n| Parameter | config.json field | Description |\r\n|-----------|-------------------|-------------|\r\n| `--feishu_webhook` | `feishu_webhook` | Webhook URL |\r\n| `--feishu_secret` | *(command-line only)* | Signing secret (optional) |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Feishu PC/web → Go to the target group chat\r\n2. Click \"...\" (group settings) → **Bots** → **Add Bot** → **Custom Bot**\r\n3. Give it a name (e.g., \"Conflict Alert\") → **Done**\r\n4. Copy the **Webhook URL** (format: `https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx`)\r\n5. (Optional) Enable **Signing Verification** → copy the secret key\r\n\r\n> Push language: **Chinese**\r\n\r\n### 2. Discord — Channel Webhook\r\n\r\n| Parameter | config.json field | Description |\r\n|-----------|-------------------|-------------|\r\n| `--discord_webhook` | `discord_webhook` | Webhook URL |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Discord → Go to the target text channel\r\n2. Click the gear icon (Edit Channel) → **Integrations** → **Webhooks**\r\n3. Click **New Webhook** → Give it a name → Select the channel\r\n4. Click **Copy Webhook URL** (format: `https://discord.com/api/webhooks/123456/abcdef...`)\r\n\r\n> Push language: **English**\r\n> Mainland China note: Requires a proxy. Pass `--proxy http://host:port` on the command line.\r\n\r\n### 3. Telegram — Bot API\r\n\r\n| Parameter | config.json field | Description |\r\n|-----------|-------------------|-------------|\r\n| `--telegram_bot_token` | `telegram_bot_token` | Bot token |\r\n| `--telegram_chat_id` | `telegram_chat_id` | Target chat/group/channel ID |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Telegram, search for **@BotFather**\r\n2. Send `/newbot` → follow the prompts to name your bot\r\n3. Copy the **bot token** (format: `123456789:ABCdefGHI...`)\r\n4. Add the bot to your target group (or just DM the bot)\r\n5. Get the **chat ID**:\r\n   - DM `@userinfobot` → it replies with your User ID (for private messages)\r\n   - Or call `https://api.telegram.org/bot<TOKEN>/getUpdates` after sending a message in the group → find `\"chat\":{\"id\":-100xxxxx}` in the response\r\n   - Group/channel IDs are negative numbers (e.g., `-1001234567890`)\r\n\r\n> Push language: **English**\r\n> Mainland China note: Requires a proxy. Pass `--proxy http://host:port` on the command line.\r\n\r\n### Proxy Configuration\r\n\r\nFor Discord and Telegram in mainland China, pass the proxy on the command line:\r\n\r\n```bash\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --discord_webhook https://discord.com/api/webhooks/... \\\r\n  --proxy http://192.168.1.1:7890\r\n```\r\n\r\n> The proxy is only used for Discord/Telegram. Feishu does not go through the proxy.\r\n\r\n---\r\n\r\n## OpenClaw Channel Integration\r\n\r\nThe push channels above are one-way: they only send alarm notifications OUT.\r\n\r\nIf you want to **directly interact with OpenClaw via a messaging app** (e.g., send a message in Telegram to trigger detection, or receive OpenClaw's conversational responses), you need to configure **OpenClaw Channels** in `openclaw.json`. This bypasses the OpenClaw backend chat window, letting the app become the primary interface.\r\n\r\n### Feishu Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"feishu\": {\r\n      \"enabled\": true,\r\n      \"appId\": \"cli_xxxxxx\",\r\n      \"appSecret\": \"xxxxxxxxxxxxxxxx\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n**How to obtain:** Create an app in [Feishu Open Platform](https://open.feishu.cn/), get the App ID and App Secret, then enable the bot messaging capability.\r\n\r\n### Telegram Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"telegram\": {\r\n      \"enabled\": true,\r\n      \"botToken\": \"123456789:ABCdefGHIjklMNO...\",\r\n      \"dmPolicy\": \"open\",\r\n      \"proxy\": \"http://192.168.1.1:7890\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `botToken` | Same bot token from @BotFather (same one used for push, or a different bot) |\r\n| `dmPolicy` | `\"open\"` = accept messages from anyone; `\"pairing\"` = require `/pair` + approval; `\"allowlist\"` = only allow specific User IDs |\r\n| `proxy` | **Must** include protocol prefix (`http://` or `socks5://`). Required in mainland China. |\r\n\r\n**`dmPolicy` options:**\r\n\r\n| Policy | Behavior |\r\n|--------|----------|\r\n| `open` | Any Telegram user can DM the bot and interact with OpenClaw |\r\n| `pairing` | User sends `/pair` to the bot → terminal shows a CODE → run `openclaw pairing approve telegram <CODE>` to approve |\r\n| `allowlist` | Only User IDs listed in `allowFrom` are allowed. Example: `\"allowFrom\": [\"tg:123456789\"]` |\r\n\r\n> To find your Telegram User ID: DM `@userinfobot` on Telegram, or check the terminal logs during pairing.\r\n\r\n### Discord Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"discord\": {\r\n      \"enabled\": true,\r\n      \"token\": \"MTUwODM4Mzk4...\",\r\n      \"dmPolicy\": \"open\",\r\n      \"allowFrom\": [\"*\"],\r\n      \"requireMention\": true\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `token` | Bot token from [Discord Developer Portal](https://discord.com/developers/applications) → Application → Bot → Token |\r\n| `dmPolicy` | Same as Telegram: `\"open\"` / `\"pairing\"` / `\"allowlist\"` |\r\n| `allowFrom` | `[\"*\"]` = accept all; or specific User IDs like `[\"discord:123456\"]` |\r\n| `requireMention` | If `true`, the bot only responds when @mentioned; if `false`, responds to all messages in allowed channels |\r\n| `guilds` | (Optional) Restrict to specific server IDs: `[\"1234567890\"]` |\r\n\r\n**How to create a Discord bot:**\r\n\r\n1. Go to [Discord Developer Portal](https://discord.com/developers/applications)\r\n2. Click **New Application** → name it → **Bot** tab → click **Reset Token** → copy the token\r\n3. Under **Privileged Gateway Intents**, enable **MESSAGE CONTENT INTENT**\r\n4. **OAuth2** tab → **URL Generator** → select scopes: `bot` → permissions: `Send Messages`, `Read Message History` → copy the invite URL\r\n5. Open the invite URL in your browser to add the bot to your server\r\n\r\n> **Important:** Discord channel in `openclaw.json` does **NOT** support a `proxy` field. If you need a proxy for Discord, set it via environment variable:\r\n> ```bash\r\n> export HTTPS_PROXY=http://192.168.1.1:7890\r\n> ```\r\n\r\n### Push Channels vs. OpenClaw Channels — Summary\r\n\r\n| | Alarm Push Channels (this skill) | OpenClaw Channels (openclaw.json) |\r\n|---|---|---|\r\n| Direction | One-way: skill → app (notification) | Two-way: user ↔ OpenClaw (conversation) |\r\n| Purpose | Send alarm messages when events detected | Allow user to trigger/control skills via messaging apps |\r\n| Configuration | `--feishu_webhook` / `--discord_webhook` / `--telegram_bot_token` | `openclaw.json` → `channels` block |\r\n| Requires | Webhook URLs or bot token | Full bot setup + OpenClaw runtime |\r\n\r\n---\r\n\r\n## File Structure\r\n\r\n```\r\nkami-conflict-detection/\r\n├── conflict_detector_last.py   # Main detection script\r\n├── yolov8s-worldv2.onnx        # YOLO person detection model\r\n├── setup.sh                    # Environment setup script\r\n├── requirements.txt            # Python dependencies\r\n├── config.json                 # Persistent user configuration (cameras, API key, push)\r\n├── SKILL.md                    # OpenClaw skill definition\r\n├── README.md                   # This file\r\n├── .venv/                      # Virtual environment (created by setup.sh)\r\n├── alerts/                     # Alert video clips output (per-camera subfolders)\r\n│   ├── <camera_name>/\r\n│   │   └── conflict_<camera_name>_YYYYMMDD_HHMMSS.mp4\r\n│   └── pending.jsonl           # Alarm inbox consumed by the heartbeat task\r\n└── conflict_detector.log       # Runtime log file\r\n```\r\n\r\n## Troubleshooting\r\n\r\n**Virtual environment not found**\r\n→ Run `bash setup.sh`\r\n\r\n**Model file missing (`yolov8s-worldv2.onnx`)**\r\n→ The script will auto-download the `.pt` and export to ONNX on first run. If this fails, manually place the ONNX model in the skill directory.\r\n\r\n**RTSP connection failure**\r\n→ Verify the camera is online, check the URL format in `cameras[].rtsp_url`, confirm network connectivity.\r\n\r\n**API key error**\r\n→ Ensure your Kami API key is valid. If you don't have one, register at https://kamiclaw-skill.kamihome.com. You can enjoy a free credit limit of 200 credits.\r\n\r\n**No alerts generated**\r\n→ Check `conflict_detector.log`. Common causes:\r\n  - Fewer than 2 people in frame (YOLO pre-filter not triggered)\r\n  - YOLO confidence too high — try `--conf_threshold 0.15`\r\n  - LLM API returning \"no conflict\" — review the video to confirm actual conflict exists\r\n\r\n**Script exits immediately with code 1**\r\n→ Check log for details. Usually: model file missing, no camera configured (empty `cameras[]` and no `--rtsp_url`), or API key not provided.\r\n\r\n**Feishu/Discord/Telegram push not working**\r\n→ Check:\r\n  - Webhook URL / bot token correct?\r\n  - Proxy configured? (Discord/Telegram in mainland China require proxy)\r\n  - Network reachable? (try `curl <webhook_url>` manually)\r\n  - Check `conflict_detector.log` for push error messages\n\nFile v2.0.3:_meta.json\n\n{\n  \"ownerId\": \"kn7e9156e1awf00v1sas2wkdfd85a4zh\",\n  \"slug\": \"kami-conflict-detection\",\n  \"version\": \"2.0.3\",\n  \"publishedAt\": 1780024232629\n}\n\nFile v2.0.3:skill-card.md\n\n## Description: <br>\nDetects physical conflicts such as fighting, shoving, and scuffling across one or more RTSP camera streams, using YOLO person filtering and a remote Kami multimodal analysis API to produce per-camera alerts while continuing to monitor. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[13681882136](https://clawhub.ai/user/13681882136) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and operators use this skill to configure long-running camera monitoring for physical altercation alerts across RTSP cameras or local test videos. It is intended for environments where camera access, API credentials, clip storage, and alert routing have been reviewed and approved. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: Continuous monitoring of RTSP cameras and remote frame analysis can expose sensitive video content. <br>\nMitigation: Use only authorized cameras, review Kami API data handling before deployment, and limit operation to approved locations and purposes. <br>\nRisk: API keys and webhook credentials are stored in config.json. <br>\nMitigation: Restrict file permissions, keep config.json out of source control and shared archives, and rotate credentials if exposure is suspected. <br>\nRisk: Incident clips and alert records are saved locally under the alerts directory. <br>\nMitigation: Apply access controls, define retention limits, and periodically delete or archive alert artifacts according to policy. <br>\nRisk: Setup may install dependencies and use a model file obtained during installation or first run. <br>\nMitigation: Preinstall and pin dependencies where possible, provide a verified local ONNX model, and review network access before running setup. <br>\n\n\n## Reference(s): <br>\n- [ClawHub Skill Page](https://clawhub.ai/13681882136/kami-conflict-detection) <br>\n- [KamiClaw API and Key Registration](https://kamiclaw-skill.kamihome.com) <br>\n- [KamiClaw Privacy Policy](https://kamiclaw-skill.kamihome.com/privacy) <br>\n- [uv Python Package Manager](https://github.com/astral-sh/uv) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [Shell commands, Configuration, JSON, Files, Guidance] <br>\n**Output Format:** [Markdown guidance with shell commands, JSON alert lines, local JSONL inbox records, and saved video clip files] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [Runs as a long-running monitoring process; alerts can be emitted to stdout, a local inbox file, and optional Feishu, Discord, or Telegram channels.] <br>\n\n## Skill Version(s): <br>\n2.0.3 (source: server release metadata; artifact frontmatter says 3.0.0) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nFile v2.0.3:config.json\n\n{\r\n  \"cameras\": [\r\n    {\r\n      \"name\": \"\",\r\n      \"rtsp_url\": \"\"\r\n    }\r\n  ],\r\n  \"kami_api_key\": \"\",\r\n  \"feishu_webhook\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\n\nFile v2.0.3:requirements.txt\n\nonnxruntime\r\nopencv-python-headless\r\nnumpy\r\nrequests\r\nultralytics\n\nArchive v2.0.2: 8 files, 26060 bytes\n\nFiles: config.json (154b), conflict_detector_last.py (39313b), README.md (17759b), requirements.txt (67b), setup.sh (2246b), skill-card.md (2634b), SKILL.md (10342b), _meta.json (142b)\n\nFile v2.0.2:SKILL.md\n\n---\r\nname: kami-conflict-detection\r\ndescription: |\r\n  Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from RTSP camera\r\n  streams or local video files. Event-driven mode: the script exits immediately upon detecting\r\n  a conflict (exit code 10), outputting alert JSON to stdout. OpenClaw reads the alert, reports\r\n  to the user in chat, then automatically restarts the script for continuous monitoring.\r\nversion: 2.0.0\r\nauthor: kami-smarthome\r\ntags:\r\n  - smart-home\r\n  - conflict-detection\r\n  - fight-detection\r\n  - violence-detection\r\n  - yolo\r\n  - rtsp\r\n  - surveillance\r\n  - security\r\n  - edge-ai\r\n  - event-driven\r\n  - openclaw\r\ntriggers:\r\n  - detect fighting\r\n  - detect conflict\r\n  - detect physical conflict\r\n  - check for fighting\r\n  - is anyone fighting\r\n  - detect scuffle\r\n  - detect shoving\r\n  - monitor for fights\r\n  - start conflict monitoring\r\n  - begin violence detection\r\nmetadata:\r\n  openclaw:\r\n    requires:\r\n      bins:\r\n        - python3.10\r\n      hardware:\r\n        cpu: \"4+ cores (x86_64 / ARM64)\"\r\n        memory: \"8 GB+\"\r\n        storage: \"10 GB+\"\r\n        gpu: \"optional (speeds up ONNX inference)\"\r\n      network:\r\n        - \"RTSP camera access (LAN)\"\r\n        - \"Internet (KamiClaw API)\"\r\n      devices:\r\n        - \"RTSP IP camera\"\r\n    emoji: \"🥊\"\r\n---\r\n\r\n# Kami Conflict Detection\r\n\r\nDetect 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.\r\n\r\n## Privacy Policy\r\n\r\nFor privacy policy details, see: <https://kamiclaw-skill.kamihome.com/privacy>\r\n\r\n## How It Works\r\n\r\n1. **YOLO pre-filter** — lightweight person detection counts people in the frame (must be ≥ 2).\r\n2. **Multi-frame collection** — collects N frames with a configurable time gap.\r\n3. **LLM conflict analysis** — frames are sent to the Kami detection API for violence/conflict judgment.\r\n4. **Event-triggered exit** — on conflict detection, the script saves a video clip, prints alert JSON to stdout, and exits with code `10`. OpenClaw then restarts it.\r\n\r\n## When to Use\r\n\r\n- Monitor a camera feed for physical fights or scuffles\r\n- Detect shoving, pushing, or violent behavior between people\r\n- Run conflict detection on a local video file for testing\r\n- Set up automated surveillance alerts for physical altercations\r\n\r\n## Installation\r\n\r\n```bash\r\nbash setup.sh\r\n```\r\n\r\nNo `sudo` required. The script auto-bootstraps **python3.10** in user space (via [uv](https://github.com/astral-sh/uv) when needed), creates `.venv/`, installs dependencies, and prepares `alerts/`. Idempotent — safe to re-run.\r\n\r\n## Prerequisites\r\n\r\n- Linux/macOS shell with `curl` (or `wget`) available\r\n- `yolov8s-worldv2.onnx` model file in the skill directory\r\n- RTSP camera online, OR a local video file for testing\r\n- Kami API key (`--kami_api_key` or write to `config.json`). Register at <https://kamiclaw-skill.kamihome.com> for a free 200-credit quota.\r\n- `setup.sh` has been run at least once\r\n\r\n> Python 3.10 is **not** a manual prerequisite — `setup.sh` will install it locally without sudo if missing.\r\n\r\n## Parameters\r\n\r\nConfirm the following before running. The fields marked **(persisted in `config.json`)** can be saved to `config.json` next to the script so the user does not need to provide them every run — see [Configuration Persistence](#configuration-persistence) below.\r\n\r\n| Parameter | Default | Description |\r\n|-----------|---------|-------------|\r\n| `--rtsp_url` | *(persisted in `config.json`)* | RTSP camera URL or local video file path |\r\n| `--kami_api_key` | *(persisted in `config.json`)* | Kami API key |\r\n| `--yolo_model` | `yolov8s-worldv2.onnx` | YOLO model file path |\r\n| `--conf_threshold` | `0.25` | YOLO confidence threshold |\r\n| `--min_persons` | `2` | Minimum person count to trigger LLM analysis |\r\n| `--sample_interval` | `1.0` | YOLO pre-filter interval (seconds) |\r\n| `--multi_frame_count` | `3` | Frames per LLM analysis |\r\n| `--multi_frame_gap` | `0.5` | Gap between collected frames (seconds) |\r\n| `--buffer_seconds` | `30` | Ring buffer duration for clip export |\r\n| `--clip_before` | `5` | Seconds of video before the conflict |\r\n| `--clip_after` | `5` | Seconds of video after the conflict |\r\n| `--output_dir` | `alerts/` | Directory for saved video clips |\r\n| `--run_time` | `0` | Max single-round run time; `0` = unlimited |\r\n| `--fps` | `15` | Video stream frame rate |\r\n| `--inbox_file` | `alerts/pending.jsonl` | Alarm inbox consumed by the heartbeat task |\r\n| `--feishu_webhook` | *(persisted in `config.json`)* | Feishu custom bot webhook URL |\r\n| `--feishu_secret` | *(optional, command-line only)* | Feishu signing secret (only if signing enabled) |\r\n| `--discord_webhook` | *(persisted in `config.json`)* | Discord channel webhook URL |\r\n| `--telegram_bot_token` | *(persisted in `config.json`)* | Telegram Bot token |\r\n| `--telegram_chat_id` | *(persisted in `config.json`)* | Telegram target chat/group/channel ID |\r\n| `--proxy` | *(optional, command-line only)* | HTTPS proxy for Discord/Telegram (not used for Feishu) |\r\n\r\n**Only ask the user about a parameter if (a) it's still empty in `config.json` AND has no command-line value, OR (b) the user explicitly asks to adjust it. Do NOT pause the conversation for blanket parameter confirmation.**\r\n\r\n## Configuration Persistence (`config.json`)\r\n\r\nA `config.json` file lives next to the script with the following empty-by-default fields:\r\n\r\n```json\r\n{\r\n  \"rtsp_url\": \"\",\r\n  \"kami_api_key\": \"\",\r\n  \"feishu_webhook\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\r\n```\r\n\r\nResolution order at runtime: **command-line argument** → **`config.json`** → empty (skipped).\r\n\r\n**Workflow OpenClaw MUST follow (single-turn, no extra confirmation):**\r\n\r\n1. On first launch, read `config.json` and identify which fields are still empty.\r\n2. **Ask the user only for the empty fields** (RTSP URL, Kami API key, and which push channels to enable + their credentials).\r\n3. **Write the user's answers back into `config.json`** (preserve existing non-empty fields). Subsequent launches skip these prompts.\r\n4. **Immediately in the SAME turn**, run `bash setup.sh` (idempotent) and launch the detector. Do NOT end the turn after step 3 — do NOT wait for the user to say \"start\" or \"begin\".\r\n5. If all required fields are already non-empty on entry, skip steps 2–3 and go straight to step 4.\r\n\r\n## Alarm Push Channels\r\n\r\nAlarms can be pushed through the following channels — all optional, configure any combination:\r\n\r\n| Channel | Required Parameters |\r\n|---------|--------------------|\r\n| **Feishu** (custom bot) | `--feishu_webhook` (and optional `--feishu_secret`) |\r\n| **Discord** (channel webhook) | `--discord_webhook` |\r\n| **Telegram** (Bot API) | `--telegram_bot_token` + `--telegram_chat_id` |\r\n\r\nBeyond app push, every alarm is **always** delivered through two redundant local channels:\r\n\r\n1. **stdout JSON + exit(10)** — OpenClaw reads stdout, reports in chat, restarts the script.\r\n2. **Inbox file `alerts/pending.jsonl`** — appended on every alarm; consumed by the heartbeat task.\r\n\r\n> Refer to the official docs of each platform for how to obtain webhook URLs / bot tokens / chat IDs.\r\n> In mainland China, Discord and Telegram require a proxy (`--proxy` or `HTTPS_PROXY`).\r\n> Push card labels are language-fixed: **Feishu → Chinese**, **Discord/Telegram → English**.\r\n\r\n## Usage\r\n\r\n```bash\r\n# First time only\r\nbash setup.sh\r\n\r\n# Run with RTSP stream\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://127.0.0.1/live/YOUR-STREAM-ID \\\r\n  --kami_api_key YOUR-API-KEY\r\n\r\n# Run with local video file\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url /path/to/test_video.mp4 \\\r\n  --kami_api_key YOUR-API-KEY\r\n```\r\n\r\n## Output Format (stdout JSON)\r\n\r\nWhen a conflict is detected (exit code 10):\r\n\r\n```json\r\n{\r\n  \"alert\": \"conflict_detected\",\r\n  \"timestamp\": \"2025-01-15T14:30:22.123456\",\r\n  \"description\": \"Two people are engaged in a physical altercation\",\r\n  \"video_clip\": \"alerts/conflict_20250115_143022.mp4\",\r\n  \"clip_duration\": \"10s\",\r\n  \"message\": \"Warning: Physical conflict detected. ...\"\r\n}\r\n```\r\n\r\n## Exit Codes\r\n\r\n| Code | Meaning | OpenClaw Action |\r\n|------|---------|-----------------|\r\n| `0` | Normal exit (timeout, video ended, no event) | Inform user; optionally restart |\r\n| `10` | **Event detected** — alert JSON on stdout | Parse JSON, report to user, **immediately restart** |\r\n| `1` | Runtime error | Report error; check `conflict_detector.log` |\r\n\r\n## Strict Rules (MUST Follow)\r\n\r\n- **RULE**: Alarms flow via (a) stdout+exit(10), (b) inbox file, (c) Feishu (optional), (d) Discord (optional), (e) Telegram (optional). Never rely on a single channel.\r\n- **RULE**: Every heartbeat consumes `alerts/pending.jsonl`; non-empty → proactive chat summary; empty → `HEARTBEAT_OK`.\r\n- **RULE**: Consumed alarms are MOVED to `alerts/consumed/`, not deleted.\r\n- **RULE**: Before launch, read `config.json`; only ask the user for fields that are empty, and **write the answers back into `config.json`** so subsequent launches are non-interactive.\r\n- **RULE (auto-launch)**: Once `rtsp_url` and `kami_api_key` are present in `config.json` (either pre-existing or just written), the agent MUST run `bash setup.sh` and launch the detector **in the same conversation turn**. Never end the turn at \"config saved\" — the user does NOT need to send a second message like \"start it\" or \"begin detection\".\r\n- **RULE**: Warn the user if no push channel is configured (chat-window push still active).\r\n- **RULE**: On exit code `10`, OpenClaw MUST restart the script immediately to continue monitoring.\r\n\r\n## Troubleshooting\r\n\r\n| Problem | Fix |\r\n|---------|-----|\r\n| Virtual environment not found | Run `bash setup.sh` |\r\n| Model file missing | Place `yolov8s-worldv2.onnx` in the skill directory |\r\n| RTSP connection failure | Verify camera is online; check `--rtsp_url` |\r\n| LLM API failure | Check `KAMI_API_KEY`; verify network to the Kami API endpoint |\r\n| No alerts generated | See `conflict_detector.log`; try lowering `--conf_threshold` |\r\n| Script exits with code 1 | Check log; common causes: missing model, unreachable RTSP, missing API key |\n\nFile v2.0.2:README.md\n\n# Kami Conflict Detection\r\n\r\nReal-time physical conflict (fighting, shoving, scuffling) detection for RTSP camera streams or local video files. Uses YOLO for person pre-filtering and a remote multimodal LLM API for conflict analysis, with an event-driven architecture designed for OpenClaw scheduling.\r\n\r\n## How It Works\r\n\r\nThe detector monitors a video stream, uses YOLO to count persons in each frame, and when 2+ people are detected, collects multiple frames and sends them to the Kami detection API for conflict analysis. When a conflict is confirmed, the script saves a video clip covering the moments before and after the incident, outputs an alert JSON to stdout, and exits with code `10`. OpenClaw then reports the alert to the user and restarts the script automatically.\r\n\r\n```\r\nStart script → YOLO counts persons → 2+ people? → Collect frames → LLM analysis\r\n    ↑                                                                     ↓\r\n    └──── OpenClaw restarts ← Reports to user ← Exit(10) + JSON + video clip\r\n```\r\n\r\n## Quick Start\r\n\r\n```bash\r\n# 1. Install dependencies\r\nbash setup.sh\r\n\r\n# 2. Run detection\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --kami_api_key YOUR-API-KEY\r\n```\r\n\r\n## Installation\r\n\r\n```bash\r\nbash setup.sh\r\n```\r\n\r\nNo `sudo` required. The script will:\r\n- Auto-bootstrap **Python 3.10** in user space (via [uv](https://github.com/astral-sh/uv)) — no system-level package manager needed\r\n- Create a `.venv/` virtual environment\r\n- Install all pip dependencies (`onnxruntime`, `opencv-python-headless`, `numpy`, `requests`)\r\n- Create `alerts/` output directory\r\n\r\n## API Key\r\n\r\nThis skill requires a Kami API key for the conflict analysis LLM service.\r\n\r\n**If you don't have a key yet, register and obtain one at:**\r\n> https://kamiclaw-skill.kamihome.com\r\nYou can enjoy a free credit limit of 200 credits.\r\n\r\nProvide the key via:\r\n- `config.json` (recommended) — the value persists across runs\r\n- Command line: `--kami_api_key YOUR-KEY` (overrides `config.json` for this run only)\r\n\r\n## Configuration File (config.json)\r\n\r\nA `config.json` file in the skill directory persists user-provided values so you don't have to pass them on every run. Empty fields are ignored. Command-line arguments take priority over `config.json`.\r\n\r\n```json\r\n{\r\n  \"rtsp_url\": \"rtsp://192.168.1.100/live/stream1\",\r\n  \"kami_api_key\": \"YOUR-KAMI-KEY\",\r\n  \"feishu_webhook\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\r\n```\r\n\r\nResolution order for each field: **command-line argument** → **config.json** → empty (skipped). When OpenClaw asks the user for these values, write the answers into `config.json`.\r\n\r\n## Prerequisites\r\n\r\n- Linux/macOS shell with `curl` (or `wget`) available\r\n- `yolov8s-worldv2.onnx` model file in the skill directory (included)\r\n- RTSP camera online and network-reachable, OR a local video file for testing\r\n- Kami API key (see above)\r\n- `setup.sh` has been run at least once\r\n\r\n> Python 3.10 is **not** a manual prerequisite — `setup.sh` will install it locally without sudo if missing.\r\n\r\n## Parameters\r\n\r\n### Required\r\n\r\n| Parameter | Description |\r\n|-----------|-------------|\r\n| `--rtsp_url` | Video source. Accepts RTSP URL (e.g., `rtsp://192.168.1.100/live/stream1`) or local file path (e.g., `/path/to/video.mp4`). |\r\n| `--kami_api_key` | Kami API key for conflict analysis. Register at https://kamiclaw-skill.kamihome.com,You can enjoy a free credit limit of 200 credits. |\r\n\r\n### Optional\r\n\r\n| Parameter | Default | Type | Description |\r\n|-----------|---------|------|-------------|\r\n| `--yolo_model` | `yolov8s-worldv2.onnx` | path | Path to the YOLO ONNX model file. |\r\n| `--conf_threshold` | `0.25` | float (0-1) | YOLO detection confidence threshold. Lower detects more persons but may include false positives. |\r\n| `--min_persons` | `2` | int | Minimum number of persons in frame to trigger LLM analysis. A conflict requires at least 2 people. |\r\n| `--sample_interval` | `1.0` | float (seconds) | How often to run YOLO person detection on the stream. Lower values increase CPU usage but improve responsiveness. |\r\n| `--multi_frame_count` | `3` | int | Number of frames to collect before sending to LLM. More frames give the LLM better context but increase latency. |\r\n| `--multi_frame_gap` | `0.5` | float (seconds) | Time gap between collected frames. Spreads frames over time to capture motion progression. |\r\n| `--buffer_seconds` | `30` | int (seconds) | Ring buffer duration. Stores recent frames in memory for video clip export when a conflict is detected. |\r\n| `--clip_before` | `5` | int (seconds) | Seconds of video to include before the conflict moment in the exported clip. |\r\n| `--clip_after` | `5` | int (seconds) | Seconds of video to include after the conflict moment. The script waits this long after detection before exporting. |\r\n| `--output_dir` | `./alerts` | path | Directory where alert video clips are saved. Created automatically. |\r\n| `--run_time` | `0` | int (seconds) | Maximum run time for a single round. `0` means unlimited (runs until an event or stream ends). |\r\n| `--fps` | `15` | int | Frame rate for the video stream reader. Should match or approximate the camera's actual frame rate. |\r\n\r\n### Parameter Tuning Guide\r\n\r\n| Scenario | Adjustment |\r\n|----------|------------|\r\n| Missing persons in frame | Lower `--conf_threshold` (e.g., 0.25→0.15) |\r\n| Too many false person detections | Raise `--conf_threshold` (e.g., 0.25→0.4) |\r\n| Want to detect solo aggression | Set `--min_persons 1` (not recommended, high false positive rate) |\r\n| High CPU usage | Increase `--sample_interval` (e.g., 1.0→3.0) |\r\n| LLM analysis too slow | Reduce `--multi_frame_count` (e.g., 3→2) |\r\n| Want longer video clips | Increase `--clip_before` and `--clip_after` |\r\n| Memory constrained | Reduce `--buffer_seconds` (e.g., 30→15) |\r\n\r\n## Output Format\r\n\r\nWhen a conflict is detected (exit code `10`), the script outputs a single JSON line to stdout:\r\n\r\n```json\r\n{\r\n  \"alert\": \"conflict_detected\",\r\n  \"timestamp\": \"2025-01-15T14:30:22.123456\",\r\n  \"description\": \"Two people are engaged in a physical altercation\",\r\n  \"video_clip\": \"alerts/conflict_20250115_143022.mp4\",\r\n  \"clip_duration\": \"10s\",\r\n  \"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.\"\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `alert` | Event type, always `\"conflict_detected\"` |\r\n| `timestamp` | ISO 8601 timestamp of the alert |\r\n| `description` | LLM-generated description of the conflict |\r\n| `video_clip` | File path to the saved video clip (before + after the incident) |\r\n| `clip_duration` | Total duration of the saved clip |\r\n| `message` | Pre-formatted alert message ready for display |\r\n\r\n## Exit Codes\r\n\r\n| Code | Meaning | Typical Action |\r\n|------|---------|----------------|\r\n| `0` | Normal exit — video ended, run_time exceeded, or user interrupt. No event. | Optionally restart or end session. |\r\n| `10` | Event detected — conflict alert. JSON on stdout. | Parse JSON, report to user, restart script. |\r\n| `1` | Runtime error — model missing, stream failure, API key not set. | Check `conflict_detector.log` for details. |\r\n\r\n## Log File\r\n\r\nAll operational logs are written to `conflict_detector.log` in the script directory. Logs go to stderr (not stdout) to keep stdout clean for JSON output only.\r\n\r\n## Examples\r\n\r\n```bash\r\n# Basic usage with RTSP camera\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --kami_api_key YOUR-API-KEY\r\n\r\n# Test with a local video file\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url /home/user/test_fight_video.mp4 \\\r\n  --kami_api_key YOUR-API-KEY\r\n\r\n# Longer video clips, faster sampling\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --kami_api_key YOUR-API-KEY \\\r\n  --clip_before 10 \\\r\n  --clip_after 10 \\\r\n  --sample_interval 0.5\r\n\r\n# Limit single round to 1 hour\r\n# Recommended: write rtsp_url + kami_api_key into config.json once,\r\n# then just run the script with no extra args.\r\n.venv/bin/python conflict_detector_last.py --run_time 3600\r\n\r\n# Or pass them on the command line (they take priority over config.json):\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --kami_api_key YOUR-API-KEY \\\r\n  --run_time 3600\r\n```\r\n\r\n---\r\n\r\n## Alarm Push Channels (Detailed)\r\n\r\nBeyond the default JSON stdout output, alarms can be simultaneously pushed to external messaging platforms. These are **pure push notifications** — they only send alerts OUT, they do NOT let you interact with the detector via those apps. (For interactive control via app, see [OpenClaw Channel Integration](#openclaw-channel-integration) below.)\r\n\r\nAll channels are optional. Configure any combination via command-line arguments or `config.json`.\r\n\r\n### 1. Feishu (飞书) — Custom Bot Webhook\r\n\r\n| Parameter | config.json field | Description |\r\n|-----------|-------------------|-------------|\r\n| `--feishu_webhook` | `feishu_webhook` | Webhook URL |\r\n| `--feishu_secret` | *(command-line only)* | Signing secret (optional) |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Feishu PC/web → Go to the target group chat\r\n2. Click \"...\" (group settings) → **Bots** → **Add Bot** → **Custom Bot**\r\n3. Give it a name (e.g., \"Conflict Alert\") → **Done**\r\n4. Copy the **Webhook URL** (format: `https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx`)\r\n5. (Optional) Enable **Signing Verification** → copy the secret key\r\n\r\n> Push language: **Chinese** (中文)\r\n\r\n### 2. Discord — Channel Webhook\r\n\r\n| Parameter | config.json field | Description |\r\n|-----------|-------------------|-------------|\r\n| `--discord_webhook` | `discord_webhook` | Webhook URL |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Discord → Go to the target text channel\r\n2. Click the gear icon (Edit Channel) → **Integrations** → **Webhooks**\r\n3. Click **New Webhook** → Give it a name → Select the channel\r\n4. Click **Copy Webhook URL** (format: `https://discord.com/api/webhooks/123456/abcdef...`)\r\n\r\n> Push language: **English**\r\n> Mainland China note: Requires a proxy. Pass `--proxy http://host:port` on the command line.\r\n\r\n### 3. Telegram — Bot API\r\n\r\n| Parameter | config.json field | Description |\r\n|-----------|-------------------|-------------|\r\n| `--telegram_bot_token` | `telegram_bot_token` | Bot token |\r\n| `--telegram_chat_id` | `telegram_chat_id` | Target chat/group/channel ID |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Telegram, search for **@BotFather**\r\n2. Send `/newbot` → follow the prompts to name your bot\r\n3. Copy the **bot token** (format: `123456789:ABCdefGHI...`)\r\n4. Add the bot to your target group (or just DM the bot)\r\n5. Get the **chat ID**:\r\n   - DM `@userinfobot` → it replies with your User ID (for private messages)\r\n   - Or call `https://api.telegram.org/bot<TOKEN>/getUpdates` after sending a message in the group → find `\"chat\":{\"id\":-100xxxxx}` in the response\r\n   - Group/channel IDs are negative numbers (e.g., `-1001234567890`)\r\n\r\n> Push language: **English**\r\n> Mainland China note: Requires a proxy. Pass `--proxy http://host:port` on the command line.\r\n\r\n### Proxy Configuration\r\n\r\nFor Discord and Telegram in mainland China, pass the proxy on the command line:\r\n\r\n```bash\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --discord_webhook https://discord.com/api/webhooks/... \\\r\n  --proxy http://192.168.1.1:7890\r\n```\r\n\r\n> The proxy is only used for Discord/Telegram. Feishu does not go through the proxy.\r\n\r\n---\r\n\r\n## OpenClaw Channel Integration\r\n\r\nThe push channels above are one-way: they only send alarm notifications OUT.\r\n\r\nIf you want to **directly interact with OpenClaw via a messaging app** (e.g., send a message in Telegram to trigger detection, or receive OpenClaw's conversational responses), you need to configure **OpenClaw Channels** in `openclaw.json`. This bypasses the OpenClaw backend chat window, letting the app become the primary interface.\r\n\r\n### Feishu Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"feishu\": {\r\n      \"enabled\": true,\r\n      \"appId\": \"cli_xxxxxx\",\r\n      \"appSecret\": \"xxxxxxxxxxxxxxxx\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n**How to obtain:** Create an app in [Feishu Open Platform](https://open.feishu.cn/), get the App ID and App Secret, then enable the bot messaging capability.\r\n\r\n### Telegram Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"telegram\": {\r\n      \"enabled\": true,\r\n      \"botToken\": \"123456789:ABCdefGHIjklMNO...\",\r\n      \"dmPolicy\": \"open\",\r\n      \"proxy\": \"http://192.168.1.1:7890\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `botToken` | Same bot token from @BotFather (same one used for push, or a different bot) |\r\n| `dmPolicy` | `\"open\"` = accept messages from anyone; `\"pairing\"` = require `/pair` + approval; `\"allowlist\"` = only allow specific User IDs |\r\n| `proxy` | **Must** include protocol prefix (`http://` or `socks5://`). Required in mainland China. |\r\n\r\n**`dmPolicy` options:**\r\n\r\n| Policy | Behavior |\r\n|--------|----------|\r\n| `open` | Any Telegram user can DM the bot and interact with OpenClaw |\r\n| `pairing` | User sends `/pair` to the bot → terminal shows a CODE → run `openclaw pairing approve telegram <CODE>` to approve |\r\n| `allowlist` | Only User IDs listed in `allowFrom` are allowed. Example: `\"allowFrom\": [\"tg:123456789\"]` |\r\n\r\n> To find your Telegram User ID: DM `@userinfobot` on Telegram, or check the terminal logs during pairing.\r\n\r\n### Discord Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"discord\": {\r\n      \"enabled\": true,\r\n      \"token\": \"MTUwODM4Mzk4...\",\r\n      \"dmPolicy\": \"open\",\r\n      \"allowFrom\": [\"*\"],\r\n      \"requireMention\": true\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `token` | Bot token from [Discord Developer Portal](https://discord.com/developers/applications) → Application → Bot → Token |\r\n| `dmPolicy` | Same as Telegram: `\"open\"` / `\"pairing\"` / `\"allowlist\"` |\r\n| `allowFrom` | `[\"*\"]` = accept all; or specific User IDs like `[\"discord:123456\"]` |\r\n| `requireMention` | If `true`, the bot only responds when @mentioned; if `false`, responds to all messages in allowed channels |\r\n| `guilds` | (Optional) Restrict to specific server IDs: `[\"1234567890\"]` |\r\n\r\n**How to create a Discord bot:**\r\n\r\n1. Go to [Discord Developer Portal](https://discord.com/developers/applications)\r\n2. Click **New Application** → name it → **Bot** tab → click **Reset Token** → copy the token\r\n3. Under **Privileged Gateway Intents**, enable **MESSAGE CONTENT INTENT**\r\n4. **OAuth2** tab → **URL Generator** → select scopes: `bot` → permissions: `Send Messages`, `Read Message History` → copy the invite URL\r\n5. Open the invite URL in your browser to add the bot to your server\r\n\r\n> **Important:** Discord channel in `openclaw.json` does **NOT** support a `proxy` field. If you need a proxy for Discord, set it via environment variable:\r\n> ```bash\r\n> export HTTPS_PROXY=http://192.168.1.1:7890\r\n> ```\r\n\r\n### Push Channels vs. OpenClaw Channels — Summary\r\n\r\n| | Alarm Push Channels (this skill) | OpenClaw Channels (openclaw.json) |\r\n|---|---|---|\r\n| Direction | One-way: skill → app (notification) | Two-way: user ↔ OpenClaw (conversation) |\r\n| Purpose | Send alarm messages when events detected | Allow user to trigger/control skills via messaging apps |\r\n| Configuration | `--feishu_webhook` / `--discord_webhook` / `--telegram_bot_token` | `openclaw.json` → `channels` block |\r\n| Requires | Webhook URLs or bot token | Full bot setup + OpenClaw runtime |\r\n\r\n---\r\n\r\n## File Structure\r\n\r\n```\r\nkami-conflict-detection/\r\n├── conflict_detector_last.py   # Main detection script\r\n├── yolov8s-worldv2.onnx        # YOLO person detection model\r\n├── setup.sh                    # Environment setup script\r\n├── requirements.txt            # Python dependencies\r\n├── SKILL.md                    # OpenClaw skill definition\r\n├── README.md                   # This file\r\n├── .venv/                      # Virtual environment (created by setup.sh)\r\n├── alerts/                     # Alert video clips output\r\n│   └── conflict_YYYYMMDD_HHMMSS.mp4\r\n└── conflict_detector.log       # Runtime log file\r\n```\r\n\r\n## Troubleshooting\r\n\r\n**Virtual environment not found**\r\n→ Run `bash setup.sh`\r\n\r\n**Model file missing (`yolov8s-worldv2.onnx`)**\r\n→ Ensure the ONNX model file is in the skill directory. It should be included with the skill package.\r\n\r\n**RTSP connection failure**\r\n→ Verify camera is online, check the URL format, confirm network connectivity.\r\n\r\n**API key error**\r\n→ Ensure your Kami API key is valid. If you don't have one, register at https://kamiclaw-skill.kamihome.com. You can enjoy a free credit limit of 200 credits.\r\n\r\n**No alerts generated**\r\n→ Check `conflict_detector.log`. Common causes:\r\n  - Fewer than 2 people in frame (YOLO pre-filter not triggered)\r\n  - YOLO confidence too high — try `--conf_threshold 0.15`\r\n  - LLM API returning \"no conflict\" — review the video to confirm actual conflict exists\r\n\r\n**Script exits immediately with code 1**\r\n→ Check log for details. Usually: model file missing, stream unreachable, or API key not provided.\r\n\r\n**Feishu/Discord/Telegram push not working**\r\n→ Check:\r\n  - Webhook URL / bot token correct?\r\n  - Proxy configured? (Discord/Telegram in mainland China require proxy)\r\n  - Network reachable? (try `curl <webhook_url>` manually)\r\n  - Check `conflict_detector.log` for push error messages\n\nFile v2.0.2:_meta.json\n\n{\n  \"ownerId\": \"kn7e9156e1awf00v1sas2wkdfd85a4zh\",\n  \"slug\": \"kami-conflict-detection\",\n  \"version\": \"2.0.2\",\n  \"publishedAt\": 1779934981145\n}\n\nFile v2.0.2:skill-card.md\n\n## Description: <br>\nDetects physical conflicts such as fighting, shoving, or scuffling between two or more people from RTSP camera streams or local video files. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[13681882136](https://clawhub.ai/user/13681882136) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and operators use this skill to monitor an RTSP camera feed or local video file for physical altercations, emit an alert when conflict is detected, and preserve supporting alert clips for review. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: Camera frames are sent to the Kami service for analysis. <br>\nMitigation: Use the skill only where sending surveillance frames to that service is acceptable, and confirm the privacy policy and user consent requirements before deployment. <br>\nRisk: API keys, webhook URLs, bot tokens, clips, logs, and pending alert files can be stored on disk. <br>\nMitigation: Restrict permissions on config.json and alert directories, isolate the runtime environment, and define a retention and deletion policy for saved clips and alert files. <br>\nRisk: The setup flow can download or install code and dependencies. <br>\nMitigation: Review setup.sh before execution, pin dependencies where practical, and avoid runtime dependency installation in production environments. <br>\n\n\n## Reference(s): <br>\n- [ClawHub skill listing](https://clawhub.ai/13681882136/kami-conflict-detection) <br>\n- [Kami API key registration](https://kamiclaw-skill.kamihome.com) <br>\n- [Kami skill privacy policy](https://kamiclaw-skill.kamihome.com/privacy) <br>\n- [uv installer](https://github.com/astral-sh/uv) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [text, JSON, files, shell commands, configuration, guidance] <br>\n**Output Format:** [Markdown guidance with shell commands, configuration JSON, stdout alert JSON, local log and clip files, and optional webhook notifications.] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [Requires an RTSP camera or local video file, a Kami API key, Python 3.10, network access to the Kami service, and local storage for alert clips and logs.] <br>\n\n## Skill Version(s): <br>\n2.0.2 (source: server release evidence, created 2026-05-28) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nFile v2.0.2:config.json\n\n{\r\n  \"rtsp_url\": \"\",\r\n  \"kami_api_key\": \"\",\r\n  \"feishu_webhook\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\n\nFile v2.0.2:requirements.txt\n\nonnxruntime\r\nopencv-python-headless\r\nnumpy\r\nrequests\r\nultralytics\n\nArchive v2.0.1: 8 files, 26097 bytes\n\nFiles: config.json (154b), conflict_detector_last.py (39728b), README.md (17884b), requirements.txt (67b), setup.sh (2246b), skill-card.md (2799b), SKILL.md (9622b), _meta.json (142b)\n\nFile v2.0.1:SKILL.md\n\n---\r\nname: kami-conflict-detection\r\ndescription: |\r\n  Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from RTSP camera\r\n  streams or local video files. Event-driven mode: the script exits immediately upon detecting\r\n  a conflict (exit code 10), outputting alert JSON to stdout. OpenClaw reads the alert, reports\r\n  to the user in chat, then automatically restarts the script for continuous monitoring.\r\nversion: 2.0.0\r\nauthor: kami-smarthome\r\ntags:\r\n  - smart-home\r\n  - conflict-detection\r\n  - fight-detection\r\n  - violence-detection\r\n  - yolo\r\n  - rtsp\r\n  - surveillance\r\n  - security\r\n  - edge-ai\r\n  - event-driven\r\n  - openclaw\r\ntriggers:\r\n  - detect fighting\r\n  - detect conflict\r\n  - detect physical conflict\r\n  - check for fighting\r\n  - is anyone fighting\r\n  - detect scuffle\r\n  - detect shoving\r\n  - monitor for fights\r\n  - start conflict monitoring\r\n  - begin violence detection\r\nmetadata:\r\n  openclaw:\r\n    requires:\r\n      bins:\r\n        - python3.10\r\n      hardware:\r\n        cpu: \"4+ cores (x86_64 / ARM64)\"\r\n        memory: \"8 GB+\"\r\n        storage: \"10 GB+\"\r\n        gpu: \"optional (speeds up ONNX inference)\"\r\n      network:\r\n        - \"RTSP camera access (LAN)\"\r\n        - \"Internet (KamiClaw API)\"\r\n      devices:\r\n        - \"RTSP IP camera\"\r\n    emoji: \"🥊\"\r\n---\r\n\r\n# Kami Conflict Detection\r\n\r\nDetect 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.\r\n\r\n## Privacy Policy\r\n\r\nFor privacy policy details, see: <https://kamiclaw-skill.kamihome.com/privacy>\r\n\r\n## How It Works\r\n\r\n1. **YOLO pre-filter** — lightweight person detection counts people in the frame (must be ≥ 2).\r\n2. **Multi-frame collection** — collects N frames with a configurable time gap.\r\n3. **LLM conflict analysis** — frames are sent to the Kami detection API for violence/conflict judgment.\r\n4. **Event-triggered exit** — on conflict detection, the script saves a video clip, prints alert JSON to stdout, and exits with code `10`. OpenClaw then restarts it.\r\n\r\n## When to Use\r\n\r\n- Monitor a camera feed for physical fights or scuffles\r\n- Detect shoving, pushing, or violent behavior between people\r\n- Run conflict detection on a local video file for testing\r\n- Set up automated surveillance alerts for physical altercations\r\n\r\n## Installation\r\n\r\n```bash\r\nbash setup.sh\r\n```\r\n\r\nNo `sudo` required. The script auto-bootstraps **python3.10** in user space (via [uv](https://github.com/astral-sh/uv) when needed), creates `.venv/`, installs dependencies, and prepares `alerts/`. Idempotent — safe to re-run.\r\n\r\n## Prerequisites\r\n\r\n- Linux/macOS shell with `curl` (or `wget`) available\r\n- `yolov8s-worldv2.onnx` model file in the skill directory\r\n- RTSP camera online, OR a local video file for testing\r\n- Kami API key (`--kami_api_key` or env `KAMI_API_KEY`). Register at <https://kamiclaw-skill.kamihome.com> for a free 200-credit quota.\r\n- `setup.sh` has been run at least once\r\n\r\n> Python 3.10 is **not** a manual prerequisite — `setup.sh` will install it locally without sudo if missing.\r\n\r\n## Parameters\r\n\r\nConfirm the following before running. The fields marked **(persisted in `config.json`)** can be saved to `config.json` next to the script so the user does not need to provide them every run — see [Configuration Persistence](#configuration-persistence) below.\r\n\r\n| Parameter | Default | Description |\r\n|-----------|---------|-------------|\r\n| `--rtsp_url` | *(persisted in `config.json`)* | RTSP camera URL or local video file path |\r\n| `--kami_api_key` | *(persisted in `config.json`)* | Kami API key |\r\n| `--yolo_model` | `yolov8s-worldv2.onnx` | YOLO model file path |\r\n| `--conf_threshold` | `0.25` | YOLO confidence threshold |\r\n| `--min_persons` | `2` | Minimum person count to trigger LLM analysis |\r\n| `--sample_interval` | `1.0` | YOLO pre-filter interval (seconds) |\r\n| `--multi_frame_count` | `3` | Frames per LLM analysis |\r\n| `--multi_frame_gap` | `0.5` | Gap between collected frames (seconds) |\r\n| `--buffer_seconds` | `30` | Ring buffer duration for clip export |\r\n| `--clip_before` | `5` | Seconds of video before the conflict |\r\n| `--clip_after` | `5` | Seconds of video after the conflict |\r\n| `--output_dir` | `alerts/` | Directory for saved video clips |\r\n| `--run_time` | `0` | Max single-round run time; `0` = unlimited |\r\n| `--fps` | `15` | Video stream frame rate |\r\n| `--inbox_file` | `alerts/pending.jsonl` | Alarm inbox consumed by the heartbeat task |\r\n| `--feishu_webhook` | *(persisted in `config.json`)* | Feishu custom bot webhook URL |\r\n| `--feishu_secret` | *(env `FEISHU_WEBHOOK_SECRET`)* | Feishu signing secret (only if signing enabled) |\r\n| `--discord_webhook` | *(persisted in `config.json`)* | Discord channel webhook URL |\r\n| `--telegram_bot_token` | *(persisted in `config.json`)* | Telegram Bot token |\r\n| `--telegram_chat_id` | *(persisted in `config.json`)* | Telegram target chat/group/channel ID |\r\n| `--proxy` | *(env `HTTPS_PROXY`)* | HTTPS proxy for Discord/Telegram (not used for Feishu) |\r\n\r\n**Ask the user: do any parameters need to be changed?**\r\n\r\n## Configuration Persistence (`config.json`)\r\n\r\nA `config.json` file lives next to the script with the following empty-by-default fields:\r\n\r\n```json\r\n{\r\n  \"rtsp_url\": \"\",\r\n  \"kami_api_key\": \"\",\r\n  \"feishu_webhook\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\r\n```\r\n\r\nResolution order at runtime: **command-line argument** → **`config.json`** → empty (skipped).\r\n\r\n**Workflow OpenClaw MUST follow:**\r\n\r\n1. On first launch, read `config.json` and identify which fields are still empty.\r\n2. **Ask the user only for the empty fields** (RTSP URL, Kami API key, and which push channels to enable + their credentials).\r\n3. **Write the user's answers back into `config.json`** (preserve existing non-empty fields). Subsequent launches skip these prompts.\r\n4. Then start the detector — no need to pass these values on the command line; the script reads them from `config.json` automatically.\r\n\r\n## Alarm Push Channels\r\n\r\nAlarms can be pushed through the following channels — all optional, configure any combination:\r\n\r\n| Channel | Required Parameters |\r\n|---------|--------------------|\r\n| **Feishu** (custom bot) | `--feishu_webhook` (and optional `--feishu_secret`) |\r\n| **Discord** (channel webhook) | `--discord_webhook` |\r\n| **Telegram** (Bot API) | `--telegram_bot_token` + `--telegram_chat_id` |\r\n\r\nBeyond app push, every alarm is **always** delivered through two redundant local channels:\r\n\r\n1. **stdout JSON + exit(10)** — OpenClaw reads stdout, reports in chat, restarts the script.\r\n2. **Inbox file `alerts/pending.jsonl`** — appended on every alarm; consumed by the heartbeat task.\r\n\r\n> Refer to the official docs of each platform for how to obtain webhook URLs / bot tokens / chat IDs.\r\n> In mainland China, Discord and Telegram require a proxy (`--proxy` or `HTTPS_PROXY`).\r\n> Push card labels are language-fixed: **Feishu → Chinese**, **Discord/Telegram → English**.\r\n\r\n## Usage\r\n\r\n```bash\r\n# First time only\r\nbash setup.sh\r\n\r\n# Run with RTSP stream\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://127.0.0.1/live/YOUR-STREAM-ID \\\r\n  --kami_api_key YOUR-API-KEY\r\n\r\n# Run with local video file\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url /path/to/test_video.mp4 \\\r\n  --kami_api_key YOUR-API-KEY\r\n```\r\n\r\n## Output Format (stdout JSON)\r\n\r\nWhen a conflict is detected (exit code 10):\r\n\r\n```json\r\n{\r\n  \"alert\": \"conflict_detected\",\r\n  \"timestamp\": \"2025-01-15T14:30:22.123456\",\r\n  \"description\": \"Two people are engaged in a physical altercation\",\r\n  \"video_clip\": \"alerts/conflict_20250115_143022.mp4\",\r\n  \"clip_duration\": \"10s\",\r\n  \"message\": \"Warning: Physical conflict detected. ...\"\r\n}\r\n```\r\n\r\n## Exit Codes\r\n\r\n| Code | Meaning | OpenClaw Action |\r\n|------|---------|-----------------|\r\n| `0` | Normal exit (timeout, video ended, no event) | Inform user; optionally restart |\r\n| `10` | **Event detected** — alert JSON on stdout | Parse JSON, report to user, **immediately restart** |\r\n| `1` | Runtime error | Report error; check `conflict_detector.log` |\r\n\r\n## Strict Rules (MUST Follow)\r\n\r\n- **RULE**: Alarms flow via (a) stdout+exit(10), (b) inbox file, (c) Feishu (optional), (d) Discord (optional), (e) Telegram (optional). Never rely on a single channel.\r\n- **RULE**: Every heartbeat consumes `alerts/pending.jsonl`; non-empty → proactive chat summary; empty → `HEARTBEAT_OK`.\r\n- **RULE**: Consumed alarms are MOVED to `alerts/consumed/`, not deleted.\r\n- **RULE**: Before launch, read `config.json`; only ask the user for fields that are empty, and **write the answers back into `config.json`** so subsequent launches are non-interactive.\r\n- **RULE**: Warn the user if no push channel is configured (chat-window push still active).\r\n- **RULE**: On exit code `10`, OpenClaw MUST restart the script immediately to continue monitoring.\r\n\r\n## Troubleshooting\r\n\r\n| Problem | Fix |\r\n|---------|-----|\r\n| Virtual environment not found | Run `bash setup.sh` |\r\n| Model file missing | Place `yolov8s-worldv2.onnx` in the skill directory |\r\n| RTSP connection failure | Verify camera is online; check `--rtsp_url` |\r\n| LLM API failure | Check `KAMI_API_KEY`; verify network to the Kami API endpoint |\r\n| No alerts generated | See `conflict_detector.log`; try lowering `--conf_threshold` |\r\n| Script exits with code 1 | Check log; common causes: missing model, unreachable RTSP, missing API key |\n\nFile v2.0.1:README.md\n\n# Kami Conflict Detection\r\n\r\nReal-time physical conflict (fighting, shoving, scuffling) detection for RTSP camera streams or local video files. Uses YOLO for person pre-filtering and a remote multimodal LLM API for conflict analysis, with an event-driven architecture designed for OpenClaw scheduling.\r\n\r\n## How It Works\r\n\r\nThe detector monitors a video stream, uses YOLO to count persons in each frame, and when 2+ people are detected, collects multiple frames and sends them to the Kami detection API for conflict analysis. When a conflict is confirmed, the script saves a video clip covering the moments before and after the incident, outputs an alert JSON to stdout, and exits with code `10`. OpenClaw then reports the alert to the user and restarts the script automatically.\r\n\r\n```\r\nStart script → YOLO counts persons → 2+ people? → Collect frames → LLM analysis\r\n    ↑                                                                     ↓\r\n    └──── OpenClaw restarts ← Reports to user ← Exit(10) + JSON + video clip\r\n```\r\n\r\n## Quick Start\r\n\r\n```bash\r\n# 1. Install dependencies\r\nbash setup.sh\r\n\r\n# 2. Run detection\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --kami_api_key YOUR-API-KEY\r\n```\r\n\r\n## Installation\r\n\r\n```bash\r\nbash setup.sh\r\n```\r\n\r\nNo `sudo` required. The script will:\r\n- Auto-bootstrap **Python 3.10** in user space (via [uv](https://github.com/astral-sh/uv)) — no system-level package manager needed\r\n- Create a `.venv/` virtual environment\r\n- Install all pip dependencies (`onnxruntime`, `opencv-python-headless`, `numpy`, `requests`)\r\n- Create `alerts/` output directory\r\n\r\n## API Key\r\n\r\nThis skill requires a Kami API key for the conflict analysis LLM service.\r\n\r\n**If you don't have a key yet, register and obtain one at:**\r\n> https://kamiclaw-skill.kamihome.com\r\nYou can enjoy a free credit limit of 200 credits.\r\n\r\nProvide the key via:\r\n- Command line: `--kami_api_key YOUR-KEY`\r\n- `config.json` (recommended)\r\n- Environment variable: `export KAMI_API_KEY=YOUR-KEY`\r\n\r\n## Configuration File (config.json)\r\n\r\nA `config.json` file in the skill directory persists user-provided values so you don't have to pass them on every run. Empty fields are ignored. Command-line arguments take priority over `config.json`.\r\n\r\n```json\r\n{\r\n  \"rtsp_url\": \"rtsp://192.168.1.100/live/stream1\",\r\n  \"kami_api_key\": \"YOUR-KAMI-KEY\",\r\n  \"feishu_webhook\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}\r\n```\r\n\r\nResolution order for each field: **command-line argument** → **config.json** → empty (skipped). When OpenClaw asks the user for these values, write the answers into `config.json`.\r\n\r\n## Prerequisites\r\n\r\n- Linux/macOS shell with `curl` (or `wget`) available\r\n- `yolov8s-worldv2.onnx` model file in the skill directory (included)\r\n- RTSP camera online and network-reachable, OR a local video file for testing\r\n- Kami API key (see above)\r\n- `setup.sh` has been run at least once\r\n\r\n> Python 3.10 is **not** a manual prerequisite — `setup.sh` will install it locally without sudo if missing.\r\n\r\n## Parameters\r\n\r\n### Required\r\n\r\n| Parameter | Description |\r\n|-----------|-------------|\r\n| `--rtsp_url` | Video source. Accepts RTSP URL (e.g., `rtsp://192.168.1.100/live/stream1`) or local file path (e.g., `/path/to/video.mp4`). |\r\n| `--kami_api_key` | Kami API key for conflict analysis. Register at https://kamiclaw-skill.kamihome.com,You can enjoy a free credit limit of 200 credits. |\r\n\r\n### Optional\r\n\r\n| Parameter | Default | Type | Description |\r\n|-----------|---------|------|-------------|\r\n| `--yolo_model` | `yolov8s-worldv2.onnx` | path | Path to the YOLO ONNX model file. |\r\n| `--conf_threshold` | `0.25` | float (0-1) | YOLO detection confidence threshold. Lower detects more persons but may include false positives. |\r\n| `--min_persons` | `2` | int | Minimum number of persons in frame to trigger LLM analysis. A conflict requires at least 2 people. |\r\n| `--sample_interval` | `1.0` | float (seconds) | How often to run YOLO person detection on the stream. Lower values increase CPU usage but improve responsiveness. |\r\n| `--multi_frame_count` | `3` | int | Number of frames to collect before sending to LLM. More frames give the LLM better context but increase latency. |\r\n| `--multi_frame_gap` | `0.5` | float (seconds) | Time gap between collected frames. Spreads frames over time to capture motion progression. |\r\n| `--buffer_seconds` | `30` | int (seconds) | Ring buffer duration. Stores recent frames in memory for video clip export when a conflict is detected. |\r\n| `--clip_before` | `5` | int (seconds) | Seconds of video to include before the conflict moment in the exported clip. |\r\n| `--clip_after` | `5` | int (seconds) | Seconds of video to include after the conflict moment. The script waits this long after detection before exporting. |\r\n| `--output_dir` | `./alerts` | path | Directory where alert video clips are saved. Created automatically. |\r\n| `--run_time` | `0` | int (seconds) | Maximum run time for a single round. `0` means unlimited (runs until an event or stream ends). |\r\n| `--fps` | `15` | int | Frame rate for the video stream reader. Should match or approximate the camera's actual frame rate. |\r\n\r\n### Parameter Tuning Guide\r\n\r\n| Scenario | Adjustment |\r\n|----------|------------|\r\n| Missing persons in frame | Lower `--conf_threshold` (e.g., 0.25→0.15) |\r\n| Too many false person detections | Raise `--conf_threshold` (e.g., 0.25→0.4) |\r\n| Want to detect solo aggression | Set `--min_persons 1` (not recommended, high false positive rate) |\r\n| High CPU usage | Increase `--sample_interval` (e.g., 1.0→3.0) |\r\n| LLM analysis too slow | Reduce `--multi_frame_count` (e.g., 3→2) |\r\n| Want longer video clips | Increase `--clip_before` and `--clip_after` |\r\n| Memory constrained | Reduce `--buffer_seconds` (e.g., 30→15) |\r\n\r\n## Output Format\r\n\r\nWhen a conflict is detected (exit code `10`), the script outputs a single JSON line to stdout:\r\n\r\n```json\r\n{\r\n  \"alert\": \"conflict_detected\",\r\n  \"timestamp\": \"2025-01-15T14:30:22.123456\",\r\n  \"description\": \"Two people are engaged in a physical altercation\",\r\n  \"video_clip\": \"alerts/conflict_20250115_143022.mp4\",\r\n  \"clip_duration\": \"10s\",\r\n  \"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.\"\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `alert` | Event type, always `\"conflict_detected\"` |\r\n| `timestamp` | ISO 8601 timestamp of the alert |\r\n| `description` | LLM-generated description of the conflict |\r\n| `video_clip` | File path to the saved video clip (before + after the incident) |\r\n| `clip_duration` | Total duration of the saved clip |\r\n| `message` | Pre-formatted alert message ready for display |\r\n\r\n## Exit Codes\r\n\r\n| Code | Meaning | Typical Action |\r\n|------|---------|----------------|\r\n| `0` | Normal exit — video ended, run_time exceeded, or user interrupt. No event. | Optionally restart or end session. |\r\n| `10` | Event detected — conflict alert. JSON on stdout. | Parse JSON, report to user, restart script. |\r\n| `1` | Runtime error — model missing, stream failure, API key not set. | Check `conflict_detector.log` for details. |\r\n\r\n## Log File\r\n\r\nAll operational logs are written to `conflict_detector.log` in the script directory. Logs go to stderr (not stdout) to keep stdout clean for JSON output only.\r\n\r\n## Examples\r\n\r\n```bash\r\n# Basic usage with RTSP camera\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --kami_api_key YOUR-API-KEY\r\n\r\n# Test with a local video file\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url /home/user/test_fight_video.mp4 \\\r\n  --kami_api_key YOUR-API-KEY\r\n\r\n# Longer video clips, faster sampling\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --kami_api_key YOUR-API-KEY \\\r\n  --clip_before 10 \\\r\n  --clip_after 10 \\\r\n  --sample_interval 0.5\r\n\r\n# Limit single round to 1 hour\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --kami_api_key YOUR-API-KEY \\\r\n  --run_time 3600\r\n\r\n# Using environment variable for API key\r\nexport KAMI_API_KEY=your-key-here\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --kami_api_key $KAMI_API_KEY\r\n```\r\n\r\n---\r\n\r\n## Alarm Push Channels (Detailed)\r\n\r\nBeyond the default JSON stdout output, alarms can be simultaneously pushed to external messaging platforms. These are **pure push notifications** — they only send alerts OUT, they do NOT let you interact with the detector via those apps. (For interactive control via app, see [OpenClaw Channel Integration](#openclaw-channel-integration) below.)\r\n\r\nAll channels are optional. Configure any combination via command-line arguments or environment variables.\r\n\r\n### 1. Feishu (飞书) — Custom Bot Webhook\r\n\r\n| Parameter | Env Variable | Description |\r\n|-----------|-------------|-------------|\r\n| `--feishu_webhook` | `FEISHU_WEBHOOK_URL` | Webhook URL |\r\n| `--feishu_secret` | `FEISHU_WEBHOOK_SECRET` | Signing secret (optional) |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Feishu PC/web → Go to the target group chat\r\n2. Click \"...\" (group settings) → **Bots** → **Add Bot** → **Custom Bot**\r\n3. Give it a name (e.g., \"Conflict Alert\") → **Done**\r\n4. Copy the **Webhook URL** (format: `https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx`)\r\n5. (Optional) Enable **Signing Verification** → copy the secret key\r\n\r\n> Push language: **Chinese** (中文)\r\n\r\n### 2. Discord — Channel Webhook\r\n\r\n| Parameter | Env Variable | Description |\r\n|-----------|-------------|-------------|\r\n| `--discord_webhook` | `DISCORD_WEBHOOK_URL` | Webhook URL |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Discord → Go to the target text channel\r\n2. Click the gear icon (Edit Channel) → **Integrations** → **Webhooks**\r\n3. Click **New Webhook** → Give it a name → Select the channel\r\n4. Click **Copy Webhook URL** (format: `https://discord.com/api/webhooks/123456/abcdef...`)\r\n\r\n> Push language: **English**\r\n> Mainland China note: Requires a proxy. Pass `--proxy http://host:port` or set `HTTPS_PROXY` environment variable.\r\n\r\n### 3. Telegram — Bot API\r\n\r\n| Parameter | Env Variable | Description |\r\n|-----------|-------------|-------------|\r\n| `--telegram_bot_token` | `TELEGRAM_BOT_TOKEN` | Bot token |\r\n| `--telegram_chat_id` | `TELEGRAM_CHAT_ID` | Target chat/group/channel ID |\r\n\r\n**How to obtain:**\r\n\r\n1. Open Telegram, search for **@BotFather**\r\n2. Send `/newbot` → follow the prompts to name your bot\r\n3. Copy the **bot token** (format: `123456789:ABCdefGHI...`)\r\n4. Add the bot to your target group (or just DM the bot)\r\n5. Get the **chat ID**:\r\n   - DM `@userinfobot` → it replies with your User ID (for private messages)\r\n   - Or call `https://api.telegram.org/bot<TOKEN>/getUpdates` after sending a message in the group → find `\"chat\":{\"id\":-100xxxxx}` in the response\r\n   - Group/channel IDs are negative numbers (e.g., `-1001234567890`)\r\n\r\n> Push language: **English**\r\n> Mainland China note: Requires a proxy. Pass `--proxy http://host:port` or set `HTTPS_PROXY` environment variable.\r\n\r\n### Proxy Configuration\r\n\r\nFor Discord and Telegram in mainland China:\r\n\r\n```bash\r\n# Method 1: Command-line argument\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url ... --kami_api_key ... \\\r\n  --discord_webhook https://discord.com/api/webhooks/... \\\r\n  --proxy http://192.168.1.1:7890\r\n\r\n# Method 2: Environment variable\r\nexport HTTPS_PROXY=http://192.168.1.1:7890\r\n.venv/bin/python conflict_detector_last.py ...\r\n```\r\n\r\n> The proxy is only used for Discord/Telegram. Feishu does not go through the proxy.\r\n\r\n---\r\n\r\n## OpenClaw Channel Integration\r\n\r\nThe push channels above are one-way: they only send alarm notifications OUT.\r\n\r\nIf you want to **directly interact with OpenClaw via a messaging app** (e.g., send a message in Telegram to trigger detection, or receive OpenClaw's conversational responses), you need to configure **OpenClaw Channels** in `openclaw.json`. This bypasses the OpenClaw backend chat window, letting the app become the primary interface.\r\n\r\n### Feishu Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"feishu\": {\r\n      \"enabled\": true,\r\n      \"appId\": \"cli_xxxxxx\",\r\n      \"appSecret\": \"xxxxxxxxxxxxxxxx\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n**How to obtain:** Create an app in [Feishu Open Platform](https://open.feishu.cn/), get the App ID and App Secret, then enable the bot messaging capability.\r\n\r\n### Telegram Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"telegram\": {\r\n      \"enabled\": true,\r\n      \"botToken\": \"123456789:ABCdefGHIjklMNO...\",\r\n      \"dmPolicy\": \"open\",\r\n      \"proxy\": \"http://192.168.1.1:7890\"\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `botToken` | Same bot token from @BotFather (same one used for push, or a different bot) |\r\n| `dmPolicy` | `\"open\"` = accept messages from anyone; `\"pairing\"` = require `/pair` + approval; `\"allowlist\"` = only allow specific User IDs |\r\n| `proxy` | **Must** include protocol prefix (`http://` or `socks5://`). Required in mainland China. |\r\n\r\n**`dmPolicy` options:**\r\n\r\n| Policy | Behavior |\r\n|--------|----------|\r\n| `open` | Any Telegram user can DM the bot and interact with OpenClaw |\r\n| `pairing` | User sends `/pair` to the bot → terminal shows a CODE → run `openclaw pairing approve telegram <CODE>` to approve |\r\n| `allowlist` | Only User IDs listed in `allowFrom` are allowed. Example: `\"allowFrom\": [\"tg:123456789\"]` |\r\n\r\n> To find your Telegram User ID: DM `@userinfobot` on Telegram, or check the terminal logs during pairing.\r\n\r\n### Discord Channel\r\n\r\n```json\r\n{\r\n  \"channels\": {\r\n    \"discord\": {\r\n      \"enabled\": true,\r\n      \"token\": \"MTUwODM4Mzk4...\",\r\n      \"dmPolicy\": \"open\",\r\n      \"allowFrom\": [\"*\"],\r\n      \"requireMention\": true\r\n    }\r\n  }\r\n}\r\n```\r\n\r\n| Field | Description |\r\n|-------|-------------|\r\n| `token` | Bot token from [Discord Developer Portal](https://discord.com/developers/applications) → Application → Bot → Token |\r\n| `dmPolicy` | Same as Telegram: `\"open\"` / `\"pairing\"` / `\"allowlist\"` |\r\n| `allowFrom` | `[\"*\"]` = accept all; or specific User IDs like `[\"discord:123456\"]` |\r\n| `requireMention` | If `true`, the bot only responds when @mentioned; if `false`, responds to all messages in allowed channels |\r\n| `guilds` | (Optional) Restrict to specific server IDs: `[\"1234567890\"]` |\r\n\r\n**How to create a Discord bot:**\r\n\r\n1. Go to [Discord Developer Portal](https://discord.com/developers/applications)\r\n2. Click **New Application** → name it → **Bot** tab → click **Reset Token** → copy the \n\nArchive v2.0.0: 7 files, 24826 bytes\n\nFiles: conflict_detector_last.py (38067b), README.md (17206b), requirements.txt (67b), setup.sh (2246b), skill-card.md (2836b), SKILL.md (8282b), _meta.json (142b)\n\nArchive v1.0.1: 6 files, 20422 bytes\n\nFiles: conflict_detector_last.py (31416b), README.md (9287b), requirements.txt (67b), setup.sh (1007b), SKILL.md (15512b), _meta.json (142b)\n\nArchive v1.0.0: 6 files, 20343 bytes\n\nFiles: conflict_detector_last.py (31416b), README.md (9136b), requirements.txt (67b), setup.sh (1007b), SKILL.md (15362b), _meta.json (142b)","readmeExcerpt":"Skill: kami-conflict-detection Owner: 13681882136 Summary: Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many RTSP camera streams concurrently. Continuous mode: a single Pytho... Tags: latest:2.0.4 Version history: v2.0.4 | 2026-06-09T05:56:07.493Z | user add alert img v2.0.3 | 2026-05-29T03:10:32.629Z | user add muitl cma v2.0.2 | 2026-05-28T02:23:01.145Z | user remove env v2","codeSnippets":[],"executableExamples":[],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\r\nname: kami-conflict-detection\r\ndescription: |\r\n  Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many\r\n  RTSP camera streams concurrently. Continuous mode: a single Python process monitors every\r\n  configured camera in parallel, pushes a per-camera alert (stdout / inbox file / Feishu /\r\n  Discord / Telegram) on each detected event, and keeps running — it does NOT exit on\r\n  detection.\r\nversion: 2.0.4\r\nauthor: kami-smarthome\r\ntags:\r\n  - smart-home\r\n  - conflict-detection\r\n  - fight-detection\r\n  - violence-detection\r\n  - yolo\r\n  - rtsp\r\n  - surveillance\r\n  - security\r\n  - edge-ai\r\n  - multi-camera\r\n  - openclaw\r\ntriggers:\r\n  - detect fighting\r\n  - detect conflict\r\n  - detect physical conflict\r\n  - check for fighting\r\n  - is anyone fighting\r\n  - detect scuffle\r\n  - detect shoving\r\n  - monitor for fights\r\n  - start conflict monitoring\r\n  - begin violence detection\r\nmetadata:\r\n  openclaw:\r\n    requires:\r\n      bins:\r\n        - python3.10\r\n      hardware:\r\n        cpu: \"4+ cores (x86_64 / ARM64)\"\r\n        memory: \"8 GB+\"\r\n        storage: \"10 GB+\"\r\n        gpu: \"optional (speeds up ONNX inference)\"\r\n      network:\r\n        - \"RTSP camera access (LAN)\"\r\n        - \"Internet (KamiClaw API)\"\r\n      devices:\r\n        - \"RTSP IP camera\"\r\n    emoji: \"🥊\"\r\n---\r\n\r\n# Kami Conflict Detection\r\n\r\nDetect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many RTSP camera streams concurrently. Continuous mode — the process never exits on detection; every confirmed event is pushed as an alert tagged with the originating camera, then monitoring resumes.\r\n\r\n## Privacy Policy\r\n\r\nFor privacy policy details, see: <https://kamiclaw-skill.kamihome.com/privacy>\r\n\r\n## How It Works\r\n\r\n1. **YOLO pre-filter** — lightweight person detection counts people in each frame (must be ≥ `min_persons`, default 2).\r\n2. **Multi-frame collection** — collects N frames with a configurable time gap.\r\n3. **LLM conflict analysis** — frames are sent to the Kami detection API for violence/conflict judgment.\r\n4. **Continuous alerting** — on a confirmed conflict, the worker saves a per-camera video clip, pushes an alert with `camera = <camera_name>` to every configured channel, and **immediately resumes monitoring**. The process keeps running until the user stops it (Ctrl+C / OpenClaw shutdown).\r\n\r\n> Multi-camera: every entry in `config.json -> cameras[]` runs in its own worker thread inside the same process. The YOLO ONNX session, the conflict analyzer and all push channels are shared once across cameras. Push channels are **shared** — no per-camera webhook split. Stranger / clip / log lines are namespaced by camera name.\r\n\r\n## When to Use\r\n\r\n- Monitor one or many camera feeds for physical fights or scuffles\r\n- Detect shoving, pushing, or violent behavior between people\r\n- Run conflict detection on a local video file for testing\r\n- Set up automated surveillance alerts for physical altercations\r\n\r\n## Installation\r\n\r\n```bash\r\nbash"},{"path":"README.md","content":"# Kami Conflict Detection\r\n\r\nReal-time multi-camera physical conflict (fighting, shoving, scuffling) detection for RTSP camera streams or local video files. Uses YOLO for person pre-filtering and a remote multimodal LLM API for conflict analysis.\r\n\r\n**Multi-camera capable.** A single process can monitor an arbitrary number of RTSP cameras concurrently (e.g. `living_room` + `office_door` + …). The YOLO ONNX session and conflict analyzer are loaded **once and shared** across all cameras; each camera owns an independent frame grabber, worker thread and snapshot directory. Push channels (Feishu / Discord / Telegram) are shared — every camera uses the same webhooks. The process keeps running across detections — it does NOT exit on event.\r\n\r\n## How It Works\r\n\r\nFor each configured camera, a dedicated worker thread polls the stream, uses YOLO to count persons in each frame, and when 2+ people are detected, collects multiple frames and sends them to the Kami detection API for conflict analysis. When a conflict is confirmed, the worker saves a per-camera video clip covering the moments before and after the incident, prints an alert JSON line tagged with the camera name to stdout, pushes the alert to every configured channel, and **immediately resumes monitoring**. The process keeps running until the user stops it (Ctrl+C / OpenClaw shutdown).\r\n\r\n```\r\nFor each camera (parallel worker thread):\r\n  Read stream → YOLO counts persons → 2+ people? → Collect frames → LLM analysis\r\n                                                                        ↓\r\n                                            Conflict? → save per-camera clip\r\n                                                     → push alert (stdout / inbox / Feishu / Discord / Telegram)\r\n                                                     → resume monitoring (no exit)\r\n```\r\n\r\n## Quick Start\r\n\r\n```bash\r\n# 1. Install dependencies\r\nbash setup.sh\r\n\r\n# 2. Configure cameras and API key in config.json (recommended), then run:\r\n.venv/bin/python conflict_detector_last.py\r\n\r\n# Or for a one-off single-camera run via CLI override:\r\n.venv/bin/python conflict_detector_last.py \\\r\n  --rtsp_url rtsp://192.168.1.100/live/stream1 \\\r\n  --camera_name living_room \\\r\n  --kami_api_key YOUR-API-KEY\r\n```\r\n\r\n## Installation\r\n\r\n```bash\r\nbash setup.sh\r\n```\r\n\r\nNo `sudo` required. The script will:\r\n- Auto-bootstrap **Python 3.10** in user space (via [uv](https://github.com/astral-sh/uv)) — no system-level package manager needed\r\n- Create a `.venv/` virtual environment\r\n- Install all pip dependencies (`onnxruntime`, `opencv-python-headless`, `numpy`, `requests`)\r\n- Auto-download a pre-exported YOLO ONNX bundle from `https://publicfiles.xiaoyi.com/kami-conflict-detection-model.zip` (extracted to a temp folder, then `.onnx` is moved next to the script and the temp folder is deleted) — **no `.pt` conversion / no `ultralytics` install**.\r\n- Create `alerts/` output directory\r\n\r\n## API Key\r\n\r\nThis skill requires a Kami API key for the conflict a"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn7e9156e1awf00v1sas2wkdfd85a4zh\",\n  \"slug\": \"kami-conflict-detection\",\n  \"version\": \"2.0.4\",\n  \"publishedAt\": 1780984567493\n}"},{"path":"skill-card.md","content":"## Description:\n\nDetects physical conflicts such as fighting, shoving, and scuffling from one or more RTSP camera streams or local video files.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[13681882136](https://clawhub.ai/user/13681882136)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers, facility operators, and security teams use this skill to monitor RTSP cameras or test video files for possible physical altercations and route alerts to local output or configured messaging channels.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Selected camera frames leave the local environment for Kami conflict analysis.\n\nMitigation: Use the skill only with approved cameras and environments, review the privacy policy, and confirm that surveillance footage may be sent to the Kami service.\n\nRisk: Snapshots and alert details may be sent to configured third-party channels or public image hosting.\n\nMitigation: Use private, approved messaging channels and avoid the Feishu sm.ms fallback unless public image hosting is acceptable.\n\nRisk: Configuration and logs can contain sensitive camera URLs, API keys, webhooks, or alert details.\n\nMitigation: Protect config.json and logs with local access controls, avoid committing them, and use dedicated low-privilege camera credentials.\n\nRisk: Setup downloads dependencies and a model artifact during installation or first run.\n\nMitigation: Review and pin setup dependencies and model artifacts before deployment in controlled or regulated environments.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/13681882136/skills/kami-conflict-detection)\n- [KamiClaw service](https://kamiclaw-skill.kamihome.com)\n- [Kami conflict detection model bundle](https://publicfiles.xiaoyi.com/kami-conflict-detection-model.zip)\n- [uv Python package manager](https://github.com/astral-sh/uv)\n\n## Skill Output:\n\n**Output Type(s):** [guidance, shell commands, configuration, JSON, files]\n\n**Output Format:** [Markdown guidance with shell commands and JSON alert records; the detector also saves MP4 clips and JPEG snapshots.]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Requires configured camera sources and a Kami API key; alerts can be emitted to stdout, an inbox file, Feishu, Discord, or Telegram.]\n\n## Skill Version(s):\n\n2.0.4 (source: frontmatter and release evidence)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."},{"path":"config.json","content":"{\r\n  \"cameras\": [\r\n    {\r\n      \"name\": \"\",\r\n      \"rtsp_url\": \"\"\r\n    }\r\n  ],\r\n  \"kami_api_key\": \"\",\r\n  \"feishu_webhook\": \"\",\r\n  \"feishu_secret\": \"\",\r\n  \"feishu_app_id\": \"\",\r\n  \"feishu_app_secret\": \"\",\r\n  \"discord_webhook\": \"\",\r\n  \"telegram_bot_token\": \"\",\r\n  \"telegram_chat_id\": \"\"\r\n}"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":"Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many RTSP camera streams concurrently. Continuous mode: a single Pytho... Skill: kami-conflict-detection Owner: 13681882136 Summary: Detect physical conflicts (fighting, shoving, scuffling) between 2+ people from one or many RTSP camera streams concurrently. Continuous mode: a single Pytho... Tags: latest:2.0.4 Version history: v2.0.4 | 2026-06-09T05:56:07.493Z | user add alert img v2.0.3 | 2026-05-29T03:10:32.629Z | user add muitl cma v2.0.2 | 2026-05-28T02:23:01.145Z | user remove env v2","editorialQuality":{"score":100,"threshold":65,"status":"ready","wordCount":1449,"uniquenessScore":48,"reasons":[]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-11T14:09:10.669Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-11T14:09:10.669Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-11T17:44:17.019Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}