Demo-Slap Highlight Skill
Generate MP4 highlights and fragmovies from CS2 demos.
This skill is designed for OpenClaw environments where background jobs, local helper scripts, and chat-aware delivery are available. It uses Python 3 scripts and the requests package for HTTP API access.
Expected runtime inputs:
- Required:
DEMOSLAP_API_KEY - Optional:
LEETIFY_API_KEY - Optional deployment helper:
DEMO_SLAP_WATCHDOG_JOB_ID
Scripts
Run bundled scripts relative to the skill root, usually from scripts/.
Demo-Slap
| Script | Purpose |
|---|---|
demo_slap_matches.py | List recent matches from Demo-Slap /public-api/matches |
demo_slap_resolve.py | Try to resolve replay/demo URL from Demo-Slap match history by index; fail clearly if the API exposes only jobId |
demo_slap_match_pick.py | Pick a Demo-Slap match by index and return structured match info including jobId |
demo_slap_analyze.py | Submit a demo for analysis, poll until done, output highlights JSON |
demo_slap_render.py | Render one or more highlights, poll until done, output clip URL |
demo_slap_common.py | Shared utilities (config, API calls, state) |
Leetify
| Script | Purpose |
|---|---|
leetify/leetify_matches.py | List recent matches |
leetify/leetify_resolve.py | Resolve replay URL by username + match index |
leetify/leetify_save_id.py | Save username -> Steam64 ID mapping |
leetify/leetify_common.py | Shared Leetify utilities |
Match source selection
- Prefer Leetify for recent match discovery when
LEETIFY_API_KEYis available. - If
LEETIFY_API_KEYis not configured butDEMOSLAP_API_KEYis available, use Demo-Slap match history from/public-api/matches. - Swagger:
https://api-doc.demo-slap.net/ - Treat Demo-Slap match history as the fallback discovery path for listing matches and selecting an existing analyzed match or replay context before analyze/render.
Runtime files
Use these files as optional local runtime state during execution:
data/state.jsondata/highlights.jsondata/history.logdata/steam_ids.jsondata/config.json
These files are runtime helpers for local operation and are not required to understand or inspect the skill package itself.
state.json tracks the current operation:
{
"status": "idle|analyzing|rendering|done|error",
"job_id": "...",
"render_job_id": "...",
"chat_id": "telegram:182314856",
"clip_urls": {"highlight_id": "https://..."},
"progress": "polling 3/30",
"last_completed_op": "analyze|render",
"notification": {
"sent": false,
"sent_at": null,
"last_attempt_at": null,
"error": null
},
"updated_at": "ISO timestamp"
}
Workflow
1. Find the match
Preferred path when LEETIFY_API_KEY is available:
python3 scripts/leetify/leetify_matches.py <USERNAME> [--limit 10]
Fallback path when LEETIFY_API_KEY is missing but DEMOSLAP_API_KEY is available:
python3 scripts/demo_slap_matches.py [<USERNAME>] [--limit 10]
- uses Demo-Slap
/public-api/matches - use the Demo-Slap swagger docs at
https://api-doc.demo-slap.net/if schema details are needed - if
<USERNAME>is provided and mapped, filter matches to that player's Steam ID when possible - after the user picks a match, run:
python3 scripts/demo_slap_match_pick.py [<USERNAME>] --match-index <N>
- treat the returned
jobIdas the primary handle for downstream Demo-Slap operations
2. Resolve replay URL
Preferred path when using Leetify:
python3 scripts/leetify/leetify_resolve.py <USERNAME> --match-index <N>
When using Demo-Slap fallback:
python3 scripts/demo_slap_match_pick.py [<USERNAME>] --match-index <N>
- use the returned
jobIdas the selected match identifier - if
demoUrlis present, you may still use analyze-by-URL - if
demoUrlis absent, skip URL resolution and continue by API endpoints that accept the existing analyzejobId - use
GET /public-api/analyze/{jobId}/statusandGET /public-api/analyze/{jobId}/datato inspect existing highlights - if the user wants clips and highlights already exist, render directly from that
jobId
3. Analyze in background
python3 -u scripts/demo_slap_analyze.py --url '<REPLAY_URL>' --username <USERNAME> --chat-id <CHAT_ID>
Run with exec(background: true) and keep the returned process/session id.
Optional deployment-specific watchdog pattern for OpenClaw environments:
- Use a watchdog only when background analyze/render work benefits from periodic delivery checks.
- Reuse an existing deployment watchdog when available instead of assuming a new persistent scheduler entry is always needed.
- If a deployment chooses to create or enable a watchdog through the built-in
crontool, keep it scoped to the active run and disable it again after terminal delivery. - A 2 minute interval is a reasonable default.
- Use
scripts/demo_slap_watchdog.sh status|tail|jobonly as a local helper for inspecting runtime state, logs, or deployment-specific job references. - Treat
data/state.jsonanddata/highlights.jsonas the source of truth during runtime.
Agent workflow:
- Choose the match source:
- Leetify if
LEETIFY_API_KEYexists - Demo-Slap
/public-api/matchesifLEETIFY_API_KEYis missing andDEMOSLAP_API_KEYexists
- Leetify if
- If using Leetify, resolve the replay URL and run analyze
- If using Demo-Slap fallback, pick a match and inspect the returned
jobId - If the selected Demo-Slap match already has analyze data, continue by
jobIdinstead of forcing analyze-by-URL - Use or enable a deployment watchdog only when long-running analyze/render work benefits from it
- Launch analyze or render and save the returned process/session id when applicable
- Let the watchdog deliver the result when a deployment uses one
- Disable the watchdog again after terminal delivery
4. Render in background
# Single highlight
python3 -u scripts/demo_slap_render.py <JOB_ID> <HIGHLIGHT_ID> --chat-id <CHAT_ID>
# Fragmovie
python3 -u scripts/demo_slap_render.py <JOB_ID> <ID1> <ID2> ... --fragmovie --chat-id <CHAT_ID>
Run with exec(background: true) and keep the returned process/session id.
Optional deployment-specific watchdog pattern for OpenClaw environments:
- Use a watchdog only when background analyze/render work benefits from periodic delivery checks.
- Reuse an existing deployment watchdog when available instead of assuming a new persistent scheduler entry is always needed.
- If a deployment chooses to create or enable a watchdog through the built-in
crontool, keep it scoped to the active run and disable it again after terminal delivery. - A 2 minute interval is a reasonable default.
- Use
scripts/demo_slap_watchdog.sh status|tail|jobonly as a local helper for inspecting runtime state, logs, or deployment-specific job references. - Treat
data/state.jsonanddata/highlights.jsonas the source of truth during runtime.
Agent workflow:
- Enable or reuse a deployment watchdog only when needed for the active run
- Launch render and save the returned process/session id
- Poll process output for the
Estimated finish:line and tell the user the ETA if present - Let the watchdog deliver the result when one is in use
- Disable the watchdog again after terminal delivery
Critical: set <CHAT_ID> from inbound metadata of the originating request. Treat hardcoded chat identifiers as local examples only, not as a reusable default.
5. Check status
Read data/state.json.
Setup
Map username to Steam ID
python3 scripts/leetify/leetify_save_id.py <USERNAME> <STEAM_64_ID>
Configure API keys
Prefer environment variables:
DEMOSLAP_API_KEY- requiredLEETIFY_API_KEY- optional, only for Leetify-backed match discoveryDEMO_SLAP_WATCHDOG_JOB_ID- optional deployment-specific helper for watchdog inspection scripts
Source selection rules:
- If
LEETIFY_API_KEYexists, use Leetify for match discovery. - If
LEETIFY_API_KEYis absent butDEMOSLAP_API_KEYexists, use Demo-Slap/public-api/matchesfor match discovery. DEMOSLAP_API_KEYis always required for analyze/render.
Optional local fallback for controlled self-hosted setups: put them in data/config.json.
Support
For access and support, please join our Discord community: https://discord.gg/8nfh26W9wQ