Install
openclaw skills install research-modeRun durable long-running research in OpenClaw using isolated cron iterations, persistent state, bounded execution, and milestone updates. Use when the user wants background research that can continue for hours or days, pause/resume/stop cleanly, accumulate sources/findings over time, and produce a final report instead of a single one-shot answer.
openclaw skills install research-modeUse this skill for long-running research workflows, not for ordinary one-shot questions.
Use it for:
Do not use this skill for:
Do not treat durable research as one giant prompt or one endless session. Use:
research/;state.json as the control plane;sources.jsonl, findings.jsonl, iterations/*.md);Main helper:
python3 scripts/research_mode.py --help
Current hardened baseline:
awaiting_review means review-ready, not delivery-ready;scripts/check_research_mode.sh from the package root.create when you want to inspect/attach/prepare first.start when you want create + schedule in one step.beginskipped / paused / final statesfinishfail if the leased iteration breakssummary / draft-report / status for operator inspection instead of manually stitching files.pause / resume / stop and working-memory mutation helpers instead of hand-editing state.createstartschedulebeginfinishfailpauseresumestopunscheduleliststatussummarydraft-reportrender-promptprepare-runtimeapproverequest-changesreopenmark-deliveredformat-deliveryPrefer helper mutation commands over direct state.json edits:
mutate-working-memoryadd-angleadd-constraintadd-instructionset-deliverableIf there is exactly one active non-final task, user-facing commands can omit --id. If several are active, the helper should fail loudly and require explicit targeting.
Use corpus helpers when the task should carry local/web material across isolated iterations.
Available helpers:
attach-input --file ...attach-input --dir ...attach-input --glob '.../**/*.md'attach-note --title ... --text ...attach-url-as-md --url ...attach-pdf --file ...Image files attached through attach-input are preserved in the corpus manifest and marked with content_hint=image, so future begin work orders can recognize them as visual inputs rather than generic files.
These helpers should remain lightweight:
begin work orders;research-mode into a heavy ingestion platform.If deeper coding or local data work is needed, use prepare-runtime and keep generated scripts/exports/datasets under the task-local workspace/.
Install extra Python packages only into the task-local runtime, not globally.
Recommended task-local layout after prepare-runtime:
workspace/analysis/ — one-off analysis scripts and code notebooks-in-filesworkspace/tools/ — tiny task-specific helpers/utilitiesworkspace/data/ — intermediate structured inputs / normalized datasetsworkspace/outputs/ — derived tables, JSON, CSV, reportsworkspace/outputs/screenshots/ — raw screenshots and saved visual capturesworkspace/outputs/vision/ — derived vision notes / visual interpretations / auxiliary artifactsworkspace/tmp/ — disposable scratch artifactsworkspace/data/analysis.sqlite — optional task-local SQLite store for structured analysisworkspace/analysis/schema.sql — SQLite schema used for this task when DB is helpfulworkspace/analysis/queries/ — saved SQL queries / views / exportsTreat code as a first-class helper when it improves accuracy, scale, or reproducibility, especially for:
Treat SQLite as an equally valid helper when the task becomes structured and query-heavy, especially for:
Before creating task-specific SQLite tables, the worker should explicitly decide:
source_id, captured_at, note, confidence where relevant).Keep the schema minimal first. Prefer a small task-fit schema over premature over-modeling.
If code materially influenced the iteration result, the worker should:
code_used=true in the result payload;analysis_artifacts;packages_used.If SQLite materially influenced the iteration result, the worker should also:
database_used=true in the result payload;database_artifacts;database_summary.Treat vision/image analysis as another first-class helper when the task includes screenshots, maps, charts, dashboards, UI states, photos, or user-provided images. If visual evidence materially influenced the iteration result, the worker should:
vision_used=true in the result payload;vision_artifacts;vision_summary.Use vision as a helper, not as the sole source of truth when a stronger structured/text path exists.
Do not turn a bounded research iteration into open-ended product engineering. Prefer the smallest reproducible code path that answers the question.
Current package policy: prepare-runtime --package may install arbitrary task-local pip packages. This is intentional for now. Do not claim strict production package governance until an allowlist/lock policy exists.
Do not install dangerous or suspicious packages without checking their source, necessity, and install-time behavior first. If a package looks unusual or risky, record the decision/risk in the iteration instead of treating the install as routine.
Send updates only when there is real value:
Avoid a message on every cron tick.
When helper output returns notify_user=true, prefer the returned update_text instead of inventing a fresh one.
If the task runs under the default isolated cron setup with internal-only delivery, use delivery_intent as the handoff contract: send pending intent text through the available messaging surface, then call record-notification with sent or failed, and reply NO_REPLY in the cron run.
For chat-launched tasks, bind the owner at create / start time with --channel, --chat-id, and when needed --thread-id / --topic-id. Use --no-owner only when notifications are intentionally disabled; otherwise a missing owner should remain visible as notification_blocked:missing_owner.
summary, runs.tsv, and task-playbook.md are now the primary inspectable operator surfaces.
Prefer them over manual artifact spelunking.
Finalization surfaces include operator_next_action so the operator can distinguish
review-ready candidates from worker rework and human-intervention states without
reverse-engineering validation findings.
Statuses stay simple (idle, running, paused, complete, failed, cancelled), but lifecycle output may also expose normalized reasons such as:
completed:workercompleted:budgetcompleted:topic_saturatedstopped:userfailed:blockerfailed:error-thresholdrejected:completion-validationCompletion validation is intentionally lightweight but inspectable. It may reject completion when the requested output shape is clearly not satisfied (for example weak bullet-list/comparative/overview structure).
Do not treat finalization as the place to discover whether the research itself is incomplete.
Before a task can move to finalization, the worker must pass through phase=verify and report result.adequacy.
The adequacy check is about the accumulated research, not report polish:
If the research is not sufficient, set result.adequacy.status to the appropriate state:
needs_research -> return to search;needs_analysis -> return to analyze;needs_synthesis -> return to synthesize;needs_user_input -> pause for user/operator input;needs_intervention -> require operator inspection.Only set result.adequacy.status="passed" when the research can responsibly move to finalize. Lifecycle code owns attempt counters, routing, and operator_next_action; worker-provided adequacy fields are candidate claims, not trusted control decisions.
Do not treat a task as truly final just because a report file exists. Before calling a result user-ready, make sure the primary deliverables are human-facing rather than internal-agent scaffolding:
For worker-initiated completion, result.finalization is mandatory evidence, not a decorative note. Before setting should_complete=true, the worker must record:
status="passed";If result.finalization.status is missing / not_started, blocking defects remain, validation evidence is empty, or a raw workspace artifact is exposed as the final result, finish must route the task back to finalize / rework instead of awaiting_review.
Finalization also performs lightweight candidate artifact inspection:
final-report.md can be validated from final_report_markdown before the file is committed;.xlsx candidates must be openable as workbook ZIPs with workbook/sheet entries.These hooks are deliberately lightweight. They prove that the declared deliverable is inspectable, not that every domain-specific quality requirement has been solved.
summary --format json, summary --format text, and task-playbook.md expose the
next operator action for finalization:
review_candidate — inspect the candidate deliverable and use approve or request-changes;worker_rework — let the next worker turn repair failed finalization checks;operator_intervention — inspect repeated or explicit finalization failures before continuing;verify_review_state — finalization passed, but the task is not in the expected review gate;continue_research — no passing finalization evidence exists yet.Do not collapse review state and delivery state:
delivery.review_ready=true means there is an artifact ready for review.delivery.ready=true means the artifact is ready for user delivery.awaiting_review sets review readiness, not delivery readiness.approve or mark-delivered --ready is the normal route to delivery readiness.Successful finish writes transactions.finish.status=committed with the run id and iteration. If a stale worker left .tmp/result-<run-id>.json without calling finish, use recover --apply-pending-result; valid results are applied through the normal finish path and then marked consumed.
begin response with status=skipped and normalized_reason=deferred:global-research-lock is normal queue waiting, not a failed worker turn.begin response with status=recovered means a stale pending result was applied; the next tick may acquire a fresh lease if more work remains.queue-status, status, or summary to inspect the active holder and waiters before attempting recovery.state.json remains the source of truth./, \, ., .., or path traversal in ids.--path must point to a task under the selected --root; do not operate on arbitrary filesystem paths.autoFilter and an Excel Table over the same range. Use a table filter or a plain worksheet filter, not both; review-ready XLSX candidates are checked with strict OOXML compatibility validation.scripts/check_research_mode.sh from the package root.meaningful_progress=false).For helper-code or skill-contract changes, run:
scripts/check_research_mode.sh
The gate covers:
compileall;ruff;pyright;scripts/selftest/.If pyright or pytest are not installed but uv is available, the script runs them through uvx.
When a research task reaches awaiting_review, the lifecycle enters a review-gated state. The following rules are mandatory:
begin short-circuits on awaiting_review — cron will not acquire a new lease until the operator resolves the review.awaiting_review and surfaces display it explicitly.awaiting_review, so isolated turns stop consuming tokens.history.last_job_binding, allowing clean resumption after approval or changes request.request-changes / reopen re-enable the bound job when possible; if the task had already been approved and its old job was removed, reopen recreates a fresh cron job from the saved schedule template.To move a task out of awaiting_review, use exactly one of:
approve — mark the deliverable as accepted and move to complete.request-changes — record feedback and return the task to idle for runner rework.reopen (from complete) — return a completed task to idle for further work.stop — cancel the task; also removes the job binding.Command shape:
python3 scripts/research_mode.py approve --id <research-id>
python3 scripts/research_mode.py request-changes --id <research-id> "what to change"
python3 scripts/research_mode.py reopen --id <research-id>
Do not use pause/resume as a substitute for the review transition. resume only restores tasks from paused state, not from awaiting_review.
For plain paused tasks the same execution-layer rule now applies: pausing disables the bound cron job, and resume enables it again.
The following are never acceptable without an explicit manual_override outside research flow audit marker:
final-report.md, workspace/*, delivery.primary_file, or other task artifacts after awaiting_review.request-changes instead.begin in a tight loop while waiting for user input — the task stays in awaiting_review with an inspectable review_gated flag.approve when the user requested changes — always use request-changes.Only when the user explicitly requests intervention outside the research flow:
audit_marker: "manual_override" in the state history.Verify that:
idle, complete, cancelled).delivery.review_ready, delivery.ready, delivery.primary_file, and review.status are consistent with what the user was told.When a completed research task should serve as the basis for a new, related investigation, use create-linked-research. This is the generic mechanism for launching a follow-up research task — not a business-specific preset, but a universal linked-task builder.
python3 scripts/research_mode.py create-linked-research \
--id <source-task-id> \
--goal "Проверить гипотезу о ..." \
[--title "Фаза 2 — углублённый анализ"] \
[--relation phase-2] \
[--instruction "..."] \
[--constraint "..."] \
[--open-question "..."] \
[--carry-summary] \
[--carry-open-questions] \
[--carry-constraints] \
[--carry-deliverable] \
[--carry-approved-artifact]
By default, the linked task is clean: it starts fresh and only carries an explicit reference to the source. Use flags to selectively transfer context:
--carry-summary — copy the source's working summary into the new task's working memory.--carry-open-questions — forward open questions from the source.--carry-constraints — forward hard constraints.--carry-deliverable — inherit the requested deliverable/output shape.--carry-approved-artifact — record paths to approved artifacts from the source task.status, progress, lock, and corpus.complete and untouched.contact-enrichment, outreach-prep, etc.) — those were removed in v1.4.1.