Skip to content

Triggers & daemon

threadle daemon is serve with --no-open: long-lived API + session watchers, plus config-file triggers. Canvas trigger nodes are still future. V1 uses ~/.config/threadle/triggers.json.

Terminal window
cp examples/triggers/triggers.example.json ~/.config/threadle/triggers.json
# edit graphId / paths / cron / projectDir
threadle daemon
# or: threadle --no-open (same trigger load)

Bare threadle / threadle serve also load triggers when the server starts.

FieldMeaning
idStable id (logs / job labels)
graphIdSaved graph under ~/.config/threadle/graphs/
kind: cron5-field cron (min hour dom mon dow). Tick ~every 15s
kind: watchchokidar on paths (relative to projectDir unless absolute)
approveAlltrue auto-passes approval / live-handoff / wait-idle park (no splice). Omit / false → gated graphs are skipped. Prefer gate-free graphs for unattended runs.
paramsOptional {{param:…}} map
projectDirCwd for agent CLIs

On load, threadle daemon warns how many triggers use approveAll vs how many would skip gated graphs.

Detached readiness still applies (session-sourced or Library context, models set). See Detached runs.

Terminal window
threadle run <graphId|file> --watch --approve-all [--dir <project>]

Poor-man’s single-graph trigger:

  1. Graph file mtime. Portable / example .json reloads into the same graph id when the file changes.
  2. Git changes. Poll HEAD + git status under --dir (or cwd).
  3. Fallback. Directory fs watch when not a git repo and there is no graph file.

Not with --detach / --ephemeral. Prefer triggers.json + threadle daemon for scheduled / multi-graph automation. Details: CLI. Watch mode.

launchd (~/Library/LaunchAgents/sh.threadle.daemon.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>sh.threadle.daemon</string>
<key>ProgramArguments</key>
<array>
<string>/usr/local/bin/threadle</string>
<string>daemon</string>
</array>
<key>RunAtLoad</key><true/>
<key>KeepAlive</key><true/>
</dict>
</plist>

systemd user unit (~/.config/systemd/user/threadle.service):

[Unit]
Description=threadle daemon
After=default.target
[Service]
ExecStart=%h/.local/bin/threadle daemon
Restart=on-failure
[Install]
WantedBy=default.target

Adjust the binary path to your install (which threadle).