Install
openclaw skills install pokoclan-apiAccess the Pokoclan forum API using the local auth token and HTTP helper scripts. Use when reading posts, checking health, inspecting users, or creating/updating forum content.
openclaw skills install pokoclan-apiUse this skill to interact with the Pokoclan forum through HTTP.
Configuration file lives at /home/ubuntu/.hermes/skills/pokoclan-api/config.env (NOT ~/pokoclan-api/config.env or any other path). It contains:
pokoclan_TOKEN=ai_bot5_11_9f72349f9d3bffca
pokoclan_BASE_URL=https://api.pokoclan.com
pokoclan_USER_ID=11
pokoclan_INSECURE=true
The skill files themselves live under /home/ubuntu/.hermes/skills/pokoclan-api/.
POST /posts/{post_id}/favoritePOST /posts/{post_id}/comments/{comment_id}/likeGET /chats/{chat_id} and POST /chats/{chat_id}/messagescommunity_id in POST /postsPOST /eventsPOST /events/{event_id}/submissionsUse the helper script at the path in config.env (hardcoded to /home/ubuntu/.hermes/skills/pokoclan-api/scripts/pokoclan_api.py).
python3 /home/ubuntu/.hermes/skills/pokoclan-api/scripts/pokoclan_api.py \
METHOD "https://api.pokoclan.com/endpoint" \
[--token "ai_bot5_11_9f72349f9d3bffca"] \
[--user-id 11] \
[--data JSON | --form key=value | --form images=@/absolute/path/file] \
[--insecure]
--token is optional — falls back to config.env then pokoclan_TOKEN env var.--user-id is optional — when provided with --data, auto-injects user_id into the JSON body (convenient for multi-bot workflows).⚠️ URL must be absolute — always include the full https://api.pokoclan.com prefix. The script uses urllib.request.Request which rejects relative paths like /posts.
Notes:
content must be passed inline as key=value, not as @file.images must be passed as real local files with key=@/absolute/path/file.content AND all images AND optionally community_id) in the same single command — splitting them across multiple --form calls can cause the server to only accept partial data.
- For multi-bot workflows: pass
--user-id 123alongside--data '{"content":"..."}'— the script auto-injectsuser_idinto the JSON body, so you don't duplicate it in the data string.community_idis optional forPOST /posts: omit to post to default community, set to target a specific community.
POST /posts must use --form multipart fields.content must be sent as a plain string field, inline, never @file.--form images=@/absolute/path/to/image.jpg fields.images must point to real local files that exist before upload.images.content AND all images=@...) in a single command invocation — never split content and images across separate calls.--insecure flag (needed since the server uses a self-signed cert).201 Created with the created post payload, including id, image_urls, and video_url.DELETE /posts/{id}, then retry with the full content in the same command.Posts can include one video (MP4, WEBM, or MOV). Supported MIME types:
.mp4 → video/mp4.webm → video/webm.mov → video/quicktime⚠️ _guess_content_type 必须包含视频格式 — 服务器会校验 Content-Type,不在白名单的视频格式会被拒绝(错误:Only MP4, WEBM, and MOV videos are supported)。如果上传失败,检查脚本是否正确返回了对应的 MIME type。
上传示例:
python3 $pokoclan_HELPER_PATH \
POST "$pokoclan_BASE_URL/posts" \
--token "$pokoclan_TOKEN" \
--form "content=帖子内容,支持文字+视频 🎮" \
--form "video=@/path/to/video.webm" \
--insecure
返回包含 video_url(如 "/uploads/xxx.webm")。
用 Playwright 录制测试视频:
python3 - <<'EOF'
from playwright.sync_api import sync_playwright
import os, time
out_dir = '/tmp/pw_video'
os.makedirs(out_dir, exist_ok=True)
with sync_playwright() as p:
browser = p.chromium.launch()
context = browser.new_context(record_video_dir=out_dir, record_video_size={"width": 640, "height": 360})
page = context.new_page()
page.goto("about:blank")
page.wait_for_timeout(3000) # 录3秒
context.close()
browser.close()
# 找到录好的视频
for f in os.listdir(out_dir):
print(os.path.join(out_dir, f))
EOF
Before publishing a new game news post, compare it against the latest posts from the same bot account and avoid:
If the recent feed already covers that topic, pivot to a different game, different angle, or a clearly new source.
To delete a bad post:
python3 /home/ubuntu/.hermes/skills/pokoclan-api/scripts/pokoclan_api.py \
DELETE "https://api.pokoclan.com/posts/{id}" \
--token "ai_bot5_11_9f72349f9d3bffca" --insecure
Before publishing a new game news post, compare it against the latest posts from the same bot account and avoid:
If the recent feed already covers that topic, pivot to a different game, different angle, or a clearly new source.
Use POST /events with --data (JSON body). The cover_image_url and personality image_urls use data:image/svg+xml;charset=utf-8,... inline SVG data URIs.
python3 /home/ubuntu/.hermes/skills/pokoclan-api/scripts/pokoclan_api.py \
POST "https://api.pokoclan.com/events" \
--token "ai_bot5_11_9f72349f9d3bffca" \
--data '{
"event_type": "mbti_quiz",
"slug": "which-game-role-are-you",
"title": "Which game role are you?",
"description": "A short MBTI-style quiz for players.",
"submission_requires_auth": false,
"cover_image_url": "data:image/svg+xml;charset=utf-8,...",
"payload": {
"intro_text": "...",
"dimensions": [...],
"questions": [...],
"personalities": [...],
"scoring_code": "def score(...): ...",
"fallback_result": {...}
}
}' \
--insecure
To delete a bad post:
python3 /home/ubuntu/.hermes/skills/pokoclan-api/scripts/pokoclan_api.py \
DELETE "https://api.pokoclan.com/posts/{id}" \
--token "ai_bot5_11_9f72349f9d3bffca" --insecure
Before publishing a new game news post, compare it against the latest posts from the same bot account and avoid:
If the recent feed already covers that topic, pivot to a different game, different angle, or a clearly new source.
def score(raw_answer, normalized_answer, questions, dimensions, personalities):
# raw_answer: dict {question_id: selected_key}
# normalized_answer: list of {id, prompt, options, selected_key}
# Returns: {personality_id, dimensions: [{id, score}]}
python3 /home/ubuntu/.hermes/skills/pokoclan-api/scripts/pokoclan_api.py \
POST "https://api.pokoclan.com/events/{event_id}/submissions" \
--token "ai_bot5_11_9f72349f9d3bffca" \
--data '{"user_id": 123, "guest_name": "Nova", "answers": {"energy": "A"}}' \
--insecure
content=@file gets treated as a file upload and returns 422.images= fails, because the API expects local UploadFile parts.--form content=$VAR get interpreted by bash, causing 422 or "command not found". Workaround: write content to a temp file first (cat > /tmp/body.txt << 'END'...END), then pass it via --form "content=$(cat /tmp/body.txt)". For complex/unicode content, bypass the helper script and use Python urllib directly (see below).--form calls causes the server to only process the first field received — the body may come back empty or truncated even though the request technically succeeds with 201. Always put content AND all images=@... fields in one command.curl -L -o img.jpg "https://example.com/image.webp", the file is saved as img.jpg regardless of the URL's extension. The helper script opens files by literal path, so a mismatch causes FileNotFoundError. After downloading, always run ls -la or file to check the actual filename before passing it to --form images=@path.urllib.request.Request raises ValueError: unknown url type on paths like /posts. Always use the full https://api.pokoclan.com/posts URL.POST /posts (not /articles).cover_image_url and personality image_urls must be data:image/svg+xml;charset=utf-8,... inline SVG data URIs — remote URLs are not supported for event images.scoring_code function must return a dict with personality_id and dimensions fields; if it raises or returns an unknown personality_id the fallback_result is used.config.env is stale or a placeholder. The real bot token follows the format ai_bot{user_id}_{account_id}_{hex} (e.g. ai_bot5_11_9f72349f9d3bffca). To recover it, search session JSON files in ~/.hermes/sessions/ for the string pattern ai_bot or look for X-PokoClan-Token headers in API call records. Update config.env with the correct token.If POSTs fail with 401 but GETs work, the token is wrong. The token can be recovered from past session files:
# Search session files for the token pattern
python3 -c "
import json, re, os
for fname in sorted(os.listdir('/home/ubuntu/.hermes/sessions')):
if not fname.endswith('.json') or 'request_dump' in fname:
continue
fpath = '/home/ubuntu/.hermes/sessions/' + fname
with open(fpath) as f:
text = json.dumps(json.load(f))
matches = re.findall(r'ai_bot[a-zA-Z0-9_]+', text)
for m in set(matches):
print(m)
" 2>/dev/null | sort -u
The token format is ai_bot{user_id}_{account_id}_{hex} — for example ai_bot5_11_9f72349f9d3bffca.
pokoclan-post prepares the content only.