Dry-running apps
Dry-run executes the full agent loop without performing writes. Use it to:
- Verify a new skill before enabling it
- Validate a cron schedule fires at the expected time
- Estimate token cost before committing to a run
- Debug an app that's failing in production without touching the live system
Skill dry-run
insightworker skill run my-skill --dry-run
What this does:
- Runs the agent loop with the skill's prompt
- Read tools (file reads, JIRA search, SharePoint list/read) execute normally — the agent needs to see state to plan correctly
- Write tools are intercepted — the agent's intent is logged but no mutation happens
- Output includes a "would have done" summary
Sample output:
[dry-run] Skill: gather-incident-data
Read tools (executed):
sharepoint_search "incident response" → 12 results
jira_search "project = OPS AND created >= -7d" → 8 issues
Write tools (intercepted):
edit_file path=reports/weekly-incidents.md
diff (40 lines, 2 sections added/updated)
graph_send_email to="oncall@example.com" subject="Weekly Incident Digest"
body length: 1240 chars
Token use: 18,234 in / 4,891 out
Estimated cost: $0.18 (Sonnet 4.6 pricing)
The intercepted writes show the exact parameters that would have been sent. You can paste those parameters into a real run to validate.
Schedule dry-run
insightworker schedule dry-run morning-digest
What this does:
- Parses the cron expression and reports the next N fires
- Does not run the skill itself
- Use this purely to validate the cron expression
Next 5 fires for "morning-digest":
2026-05-04 09:00:00 America/New_York
2026-05-05 09:00:00 America/New_York
...
To dry-run the skill that the schedule will invoke (full agent loop, no writes):
insightworker schedule dry-run morning-digest --execute
This combines schedule resolution + skill dry-run.
What read vs write means here
InsightWorker classifies each tool as read or write in its metadata:
| Read (executes during dry-run) | Write (intercepted) |
|---|---|
| read_file, list_files, grep, glob | edit_file, write_file |
| jira_search, jira_issue | jira_create_issue, jira_comment |
| sharepoint_list, sharepoint_search, sharepoint_read | sharepoint_write (when enabled) |
| perplexity_search, web_fetch | graph_send_email |
bash (with safe: true) | bash (default, treated as write) |
bash defaults to write because shell can do anything. In a dry-run, all bash calls are intercepted and reported; if you need a specific bash call to execute (e.g. read-only git log), tag it with safe: true in the skill's tool config.
Limits of dry-run
- State drift after read: read tools see live state; if you dry-run at 09:00 and run-for-real at 10:00, the state may have changed
- Side effects via APIs that don't support a dry mode: e.g. some external services don't have a "preview" — InsightWorker can't preview what it can't preview
- Cascading effects: if Tool A's output drives Tool B's params, intercepting Tool A means Tool B gets a synthetic placeholder. The plan still validates, but the params for B are approximate.
For high-stakes apps, dry-run + a manual review of the "would have done" output before promoting to a real run.
See also
- cron-syntax.md — schedule expressions
- daemon-mode.md — running schedules continuously
- extending/skills.md — defining skills
Source: docs/workflows-and-scheduling/dry-run.md in the public repo. Open a PR with corrections.
