Polling Best Practices
A guidance-style skill for automating long-running, asynchronous tasks using a cron-compatible polling pattern. When a task cannot complete synchronously (e.g., a CLI command that triggers a background job and returns a job ID), this skill guides the agent through: (1) deciding whether polling is appropriate, (2) pre-flight confirmation with the user, (3) setting up a task directory, (4) writing the polling script, (5) launching the background job, and (6) monitoring it to completion or timeout.
Language: All confirmation messages to the user should be written in the user's current language (check the session language — if the user is writing in Chinese, reply in Chinese; if in English, reply in English).
1. Suitability Checklist
Before proceeding, the agent must answer:
✅ Suitable for Polling — if ALL of the following are true:
- - [ ] The target command/API returns immediately with a process ID, job ID, artifact ID, or similar handle
- [ ] There is a clear, machine-parseable completion condition (e.g., a JSON/TOML field, a status string, an exit code, a file appearing)
- [ ] The condition can be checked by re-running the same command or a lightweight query command
- [ ] The wait time is predictable (typically 1–15 minutes)
- [ ] No real-time user interaction is needed during execution
❌ NOT Suitable — if ANY of the following are true:
- - [ ] The task requires complex LLM judgment to determine if it's "done" (e.g., "is this output good enough?")
- [ ] The task requires streaming or real-time output to be shown to the user
- [ ] The task outcome changes during polling based on intermediate results
- [ ] The completion condition is ambiguous or subjective
- [ ] The user wants to stop or redirect the task mid-execution
If the task is NOT suitable for polling, inform the user and propose an alternative approach (e.g., run synchronously, use a sub-agent with polling only for the final wait, etc.).
2. Pre-Flight Confirmation (One-Time, All Parameters)
Before starting any polling task, ask the user to confirm all parameters in a single message. This avoids back-and-forth and sets clear expectations.
Confirm in the user's current session language.
Example (English):
CODEBLOCK0
Example (Chinese — same structure, translated):
CODEBLOCK1
Do not begin polling until the user confirms. If the user does not respond within a reasonable time, follow up once.
3. Temp Folder Structure
Every polling task gets its own temp folder. This makes the task self-contained, resumable, and easy to inspect or clean up later.
CODEBLOCK2
Naming rules:
- - Category folder: lowercase, hyphenated, descriptive of the task type (e.g.,
notebooklm-audio, deep-research, generic-async) - Task subfolder:
YYMMDD-HHmm + _ + sanitized task name (spaces→hyphens, max 40 chars, strip special chars)
If a category folder doesn't exist yet, create it. If a task subfolder already exists (e.g., from a previous attempt), ask the user: "Resume the previous task or start fresh?"
task.json schema
CODEBLOCK3
progress.json schema
CODEBLOCK4
4. Writing the Polling Script
Write the script to the task's temp folder (<temp_dir>/poll.sh). The script must be self-contained — no external dependencies beyond standard Unix tools.
Required properties:
- -
set -euo pipefail at the top - Check for
done.flag at start — if it exists, exit 0 immediately (already done) - On any error (auth expired, command failed, timeout), log to
error.log and save progress before exiting - Save
progress.json after every poll attempt - Append every poll result to
poll.log (timestamp + truncated output) - Never delete the temp folder — the user decides when to clean up
Script template (minimal):
CODEBLOCK5
5. Launching and Monitoring
Start the background job (the thing being polled)
- 1. First, run the trigger command (e.g.,
nlm audio create <notebook_id>) to start the background task and capture its ID/handle. - Save the returned ID to
progress.json and task.json. - Then launch the polling script as a background process.
CODEBLOCK6
The polling script should outlive the OpenClaw session. The agent should not need to stay alive for polling to continue.
Monitoring strategy
- - Do not poll from within the OpenClaw session (sub-agents or exec loops waste resources and complicate recovery).
- If OpenClaw receives a user message asking "is it done yet?", the agent can check
done.flag or poll.log in the temp folder to answer without starting a new poll. - If a new session starts and the user asks to check on a task, read
progress.json to determine current status.
6. Timeout and Error Handling
| Situation | Action |
|---|
| Max polls reached (timeout) | Log to error.log, notify user (if timeout_action: notify), do NOT delete temp folder |
| Auth expired |
Log to
error.log, notify user to re-authenticate, exit |
| Download/generation failed | Log to
error.log, notify user, exit |
| Temp folder already exists (duplicate start) | Ask user: resume or restart |
After timeout/failure: Do not auto-retry. Tell the user the task did not complete and present options:
- 1. Re-run with the same parameters
- Adjust parameters and re-run
- Clean up the temp folder
7. On Completion
- 1. Verify the output file exists and has content (
[[ -s "$output_path" ]]) - Create INLINECODE24
- If
output_path is set and user confirmed a destination, move/copy the file there - Notify the user:
- Task is complete
- Where the output is saved
- How many polls it took and how long
- Temp folder path (for manual inspection if needed)
- 5. If user previously confirmed temp folder retention: leave the folder; if not, offer to clean up
Language for notification: Use the user's current session language.
8. Template-Ready Tasks (Frequent Patterns)
If the same type of task is performed frequently (e.g., NotebookLM audio generation, Gemini Deep Research status checks), extract the polling logic into a reusable script template stored in a category-level folder:
CODEBLOCK7
The per-task poll.sh either copies from the template or is generated from it, keeping the per-task folder minimal.
9. Summary Checklist
Before launching a polling task, confirm ALL of:
- - [ ] Task is suitable for polling (all suitability ✅)
- [ ] User confirmed all parameters in one message
- [ ] Temp folder created with correct
task.json and INLINECODE28 - [ ] Trigger command run, ID/handle captured
- [ ]
poll.sh written and tested for syntax (bash -n) - [ ] Background process started with INLINECODE31
- [ ] User informed: task started, how to check status, what happens on completion
轮询最佳实践
一种指导式技能,用于使用 cron 兼容的轮询模式 自动化长时间运行的异步任务。当任务无法同步完成时(例如,CLI 命令触发后台作业并返回作业 ID),此技能指导代理完成以下步骤:(1) 判断轮询是否合适,(2) 与用户进行启动前确认,(3) 设置任务目录,(4) 编写轮询脚本,(5) 启动后台作业,以及 (6) 监控其完成或超时。
语言: 所有发送给用户的确认消息应使用用户当前的语言(检查会话语言——如果用户使用中文,则用中文回复;如果使用英文,则用英文回复)。
1. 适用性检查清单
在继续之前,代理必须回答:
✅ 适合轮询 —— 如果满足以下所有条件:
- - [ ] 目标命令/API 立即返回一个进程 ID、作业 ID、工件 ID 或类似的句柄
- [ ] 存在一个明确的、机器可解析的完成条件(例如,JSON/TOML 字段、状态字符串、退出码、文件出现)
- [ ] 该条件可以通过重新运行相同的命令或一个轻量级的查询命令来检查
- [ ] 等待时间是可预测的(通常为 1–15 分钟)
- [ ] 执行期间不需要实时用户交互
❌ 不适合 —— 如果满足以下任何条件:
- - [ ] 任务需要复杂的 LLM 判断来确定是否完成(例如,这个输出够好吗?)
- [ ] 任务需要流式或实时输出展示给用户
- [ ] 任务结果在轮询期间根据中间结果发生变化
- [ ] 完成条件是模糊或主观的
- [ ] 用户希望在任务执行中途停止或改变方向
如果任务不适合轮询,请告知用户并提出替代方案(例如,同步运行,使用仅用于最终等待的子代理进行轮询等)。
2. 启动前确认(一次性,所有参数)
在开始任何轮询任务之前,要求用户在一条消息中确认所有参数。这可以避免来回沟通,并设定明确的期望。
使用用户当前会话语言确认。
示例(英文):
Before starting, please confirm the following:
① Polling target
- Task: [brief description]
- Command to check status: [exact command]
- Expected completion condition: [e.g., output contains status: completed]
② Poll interval: every [X] minutes (default: 5 minutes)
③ Max duration: up to [Y] polls = [Z] minutes max (default: 40 min / 8 polls)
④ On completion: [download file / run command / send message / do nothing]
⑤ On failure/timeout: [notify me / stay silent]
⑥ Output directory: [path] (default: ~/Downloads or relevant workspace folder)
⑦ Temp folder retention: keep for review after completion? [yes / no]
Reply with any changes, or ok to proceed with defaults.
示例(中文 —— 相同结构,已翻译):
启动前请确认以下参数:
① 轮询对象
- 任务:[简短描述]
- 状态查询命令:[具体命令]
- 成功判定条件:[例如输出包含 status: completed]
② 轮询频率:每 [X] 分钟一次(默认:5 分钟)
③ 最长持续时间:最多 [Y] 次轮询 = [Z] 分钟(默认:40 分钟 / 8 次)
④ 完成后动作:[下载文件 / 运行命令 / 发消息 / 不做处理]
⑤ 失败/超时时:[通知我 / 不通知]
⑥ 产物保存位置:[路径](默认:~/Downloads 或相关工作目录)
⑦ 临时文件夹保留:完成后保留供复查?[是 / 否]
直接回复修改项,或确认以默认参数启动。
在用户确认之前不要开始轮询。 如果用户在合理时间内没有回应,请跟进一次。
3. 临时文件夹结构
每个轮询任务都有自己的临时文件夹。这使得任务自包含、可恢复,并且易于后续检查或清理。
/tmp// ← 类别:例如 notebooklm, deep-research, generic
_/ ← 每个任务的时间戳文件夹
task.json ← 任务元数据和所有参数
progress.json ← 当前轮询状态(轮询次数、上次检查时间、句柄)
poll.log ← 每次轮询尝试的日志(时间戳 + 结果)
error.log ← 遇到的错误
done.flag ← 空文件,成功完成时创建
命名规则:
- - 类别文件夹:小写、连字符连接、描述任务类型(例如 notebooklm-audio、deep-research、generic-async)
- 任务子文件夹:YYMMDD-HHmm + _ + 清理后的任务名称(空格→连字符,最多 40 个字符,去除特殊字符)
如果类别文件夹不存在,则创建它。如果任务子文件夹已存在(例如,来自之前的尝试),请询问用户:恢复之前的任务还是重新开始?
task.json 模式
json
{
category: notebooklm-audio,
task_name: example-notebook-audio,
pollcommand: nlm studio status id>,
parse_rule: {
type: json,
path: .[0].status,
success_value: completed,
failure_value: failed
},
oncompletecommand: nlm download audio id> --id id> -o ,
verify_output: true,
pollintervalseconds: 300,
max_polls: 8,
timeout_action: notify,
failure_action: notify,
output_path: /path/to/output.m4a,
tempdir: /tmp/notebooklm-audio/260325-1400example-audio,
created_at: 2026-03-25T22:00:00Z,
user_confirmed: true
}
progress.json 模式
json
{
poll_count: 3,
lastpollat: 2026-03-25T22:15:00Z,
lastpollresult: in_progress,
artifact_id: abc123...,
current_handle: ...
}
4. 编写轮询脚本
将脚本写入任务的临时文件夹(/poll.sh)。脚本必须是自包含的 —— 除了标准 Unix 工具外没有外部依赖。
必需属性:
- - 顶部设置 set -euo pipefail
- 在开始时检查 done.flag —— 如果存在,立即退出 0(已完成)
- 任何错误(身份验证过期、命令失败、超时),在退出前记录到 error.log 并保存进度
- 每次轮询尝试后保存 progress.json
- 将每次轮询结果追加到 poll.log(时间戳 + 截断的输出)
- 永远不要删除临时文件夹 —— 由用户决定何时清理
脚本模板(最小化):
bash
#!/bin/bash
set -euo pipefail
TASKDIR=/tmp/category/YYMMDD-HHmmtaskname
cd $TASK_DIR
检查是否已完成
[[ -f done.flag ]] && echo Already complete. && exit 0
加载进度
POLL
COUNT=$(grep pollcount progress.json 2>/dev/null | sed s/[^0-9]//g) || POLL_COUNT=0
MAX_POLLS=8
INTERVAL=300
while true; do
POLLCOUNT=$((POLLCOUNT + 1))
if [[ $POLLCOUNT -gt $MAXPOLLS ]]; then
echo [$(date)] TIMEOUT after $MAX_POLLS polls >> error.log
exit 1
fi
echo [$(date)] Poll $POLLCOUNT/$MAXPOLLS >> poll.log
# 运行轮询命令
RESULT=$( 2>&1) || true
echo $RESULT >> poll.log
# 解析结果 —— 根据命令的输出格式进行调整
if echo $RESULT | grep -q status: completed; then
touch done.flag
# 如果设置了完成命令则运行
echo Done. >> poll.log
exit 0
fi
# 保存进度
sed -i s/\poll_count\: [0-9