Daemon mode
The scheduler daemon is a long-running process that watches ~/.insightworker/schedules.yaml and fires skills on their cron schedules. Use it for unattended apps: morning digests, periodic data syncs, monitoring, etc.
Not to be confused with
--workermode. The scheduler daemon runs your schedules.yaml on a cron.insightworker --workeris a different daemon that joins an InsightStudio coordinator's farm and runs whatever jobs the Studio UI enqueues. You can run both at once — they're independent processes.
Start the daemon
insightworker --daemon
Runs in the foreground. To background it during a manual session:
nohup insightworker --daemon > ~/.insightworker/daemon.log 2>&1 &
For long-running setups use a system service (launchd / systemd — see below).
List what's loaded
insightworker schedule list
Output:
Schedules: 4 active, 1 paused
morning-digest Next: 2026-05-04 09:00 EDT
hourly-jira-sync Next: 2026-05-03 14:00 EDT
daily-sharepoint Next: 2026-05-04 06:00 EDT
weekly-report Next: 2026-05-09 17:00 EDT [paused]
Stop
The daemon runs in the foreground or as a managed service — there's no explicit stop subcommand. Use the platform's standard control:
# Foreground: Ctrl-C
# Backgrounded: kill the PID
kill $(pgrep -f 'insightworker --daemon')
# launchd: launchctl unload ~/Library/LaunchAgents/com.verticalserve.insightworker.plist
# systemd: systemctl --user stop insightworker
Schedule file
~/.insightworker/schedules.yaml:
schedules:
- name: morning-digest
cron: "0 9 * * MON-FRI"
timezone: America/New_York
skill: pm-agent-sprint-digest
args:
project: PROJ
recipients: ["pm@example.com"]
enabled: true
- name: hourly-jira-sync
cron: "0 * * * *"
skill: jira-to-sharepoint-sync
enabled: true
The daemon hot-reloads this file every 10 seconds — edits take effect without restart. If the file is malformed, the daemon logs the error and keeps the previous valid version active.
Run as a system service
macOS (launchd)
~/Library/LaunchAgents/com.verticalserve.insightworker.plist:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.verticalserve.insightworker</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/insightworker</string>
<string>--daemon</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardOutPath</key>
<string>/tmp/insightworker.out</string>
<key>StandardErrorPath</key>
<string>/tmp/insightworker.err</string>
</dict>
</plist>
Load:
launchctl load ~/Library/LaunchAgents/com.verticalserve.insightworker.plist
Linux (systemd, user mode)
~/.config/systemd/user/insightworker.service:
[Unit]
Description=InsightWorker daemon
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/insightworker --daemon
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
Enable:
systemctl --user daemon-reload
systemctl --user enable insightworker
systemctl --user start insightworker
Linux (systemd, system mode)
For multi-user servers, run as a dedicated insightworker user with ~/.insightworker/ in that user's home. Standard systemd service config under /etc/systemd/system/insightworker.service.
Logs
| What | Where |
|---|---|
| Daemon stdout/stderr | /tmp/insightworker.{out,err} (launchd) or journalctl --user -u insightworker (systemd) |
| Per-run transcripts | ~/.insightworker/sessions/<timestamp>.jsonl |
| Scheduler events (fires, skips) | ~/.insightworker/daemon.log |
Concurrency
By default, the daemon runs one skill at a time. If a skill is still running when its next fire is due, the second fire is skipped (logged, not queued).
To run skills concurrently:
# ~/.insightworker/schedules.yaml
options:
max_concurrent: 3 # up to 3 skills running simultaneously
schedules:
...
Be careful with concurrent runs that touch the same files — the agent's edit-file tool detects conflicts but the user-defined skill might not.
Failure handling
If a skill fails (any unhandled error or MAX_AGENT_ITERATIONS), the daemon:
- Logs the failure to
daemon.logwith the full transcript path - Sends a notification (if configured — see below)
- Continues — does not retry the failed run automatically
- The next scheduled fire happens normally
To configure failure notifications:
options:
on_failure:
- type: email
to: oncall@example.com
- type: slack
webhook: https://hooks.slack.com/services/...
Auto-approve tools (required for daemon)
In daemon mode there's no human to approve tool calls. Either:
- Set
AUTO_APPROVE_ALL=true(not recommended — too permissive) - Set
AUTO_APPROVE_TOOLS=...listing every tool your skills need
Any tool call not on the auto-approve list causes the run to fail. See permissions-and-safety/auto-approve-tools.md.
Resource limits
For unattended use, consider:
# ~/.insightworker/.env
MAX_AGENT_ITERATIONS=80 # raise for complex apps
MAX_TOOL_OUTPUT_LENGTH=20000 # cap per-tool output
DAEMON_MEM_LIMIT_MB=2048 # OOM-kill if agent burns memory
See also
- cron-syntax.md — expression reference
- dry-run.md — verify before enabling
- permissions-and-safety/auto-approve-tools.md — required for unattended runs
- extending/skills.md — defining the skills the daemon runs
Source: docs/workflows-and-scheduling/daemon-mode.md in the public repo. Open a PR with corrections.
