Troubleshooting
Common issues, FAQ, and debugging tips for loop-task.
Daemon won't start
The daemon starts automatically when you run any loop-task command, but sometimes it fails to launch. Here's how to diagnose it:
-
Check if another daemon is already running - the daemon writes a PID file to
~/.loop-cli/daemon.pid. If that file exists and the process is still alive, a new daemon will refuse to start.cat ~/.loop-cli/daemon.pid ps -p $(cat ~/.loop-cli/daemon.pid) # macOS/Linux -
Kill a stale process - if the PID file exists but the process is dead (zombie or crashed), remove it:
kill $(cat ~/.loop-cli/daemon.pid) 2>/dev/null || true rm ~/.loop-cli/daemon.pid -
Check the daemon log - the daemon writes diagnostic output to
~/.loop-cli/daemon.log. This is the first place to look when something goes wrong:cat ~/.loop-cli/daemon.log -
Restart cleanly -
loop-task restartkills any running daemon and starts a fresh one in one step.
Loop not running
A loop exists but never executes, or stops unexpectedly:
-
Check status -
loop-task statusshows every loop and its current state. Look for the Status column. -
Paused or stopped - loops can be paused (
loop-task pause <id>) or stopped (loop-task stop <id>). A paused loop retains its schedule and resumes where it left off; a stopped loop stays idle until started again.loop-task status --json | grep '"status"' -
Max runs reached - if a loop was created with
--max-runs, it stops automatically after that many executions. Check the loop config:loop-task inspect <id> -
Check logs - each loop records its execution history. Fetch the last 50 log entries:
curl http://127.0.0.1:8845/api/loops/<id>/logs?tail=50Or open the TUI board and select the loop to see its run history.
-
Verify the command works - the most common silent failure is a command that works in your shell but not when run by the daemon. The daemon has no interactive shell, no aliases, and no PATH extensions from
.bashrc/.zshrc. Run the command manually:# what loop-task actually runs (no shell wrapping): /bin/sh -c '<your command>'
Socket conflicts (macOS/Linux)
The daemon communicates with the CLI over a Unix socket at ~/.loop-cli/loop-task.sock.
-
Stale socket file - if the daemon crashes without cleaning up, the socket file stays on disk. Delete it and restart:
rm ~/.loop-cli/loop-task.sock loop-task restart -
Check what's using it - if another process holds the socket:
lsof ~/.loop-cli/loop-task.sock -
Port clash - if you changed the HTTP server port and something else is on that port, the daemon starts but the API is unreachable. Check with
curl http://127.0.0.1:8845/api/health.
Windows named pipe issues
On Windows, the daemon uses a named pipe: \\.\pipe\loop-task.
-
Stuck pipe - if the daemon exits uncleanly, the pipe may remain in a half-open state. Use
loop-task restartto force a clean reconnect. -
Multiple processes - check Task Manager for leftover
loop-taskprocesses. End any that are unresponsive, then start fresh. -
Permission denied - the named pipe is created with the current user's security context. If you run
loop-taskas a different user (e.g., viaRun as Administrator), the pipe won't be visible to your normal user session. Use the same user consistently.
Log file permissions
All logs are stored in ~/.loop-cli/logs/.
-
Write access - ensure the user running the daemon has write permission to the
~/.loop-cli/directory tree:ls -la ~/.loop-cli/ chmod -R u+w ~/.loop-cli/logs # macOS/Linux -
Docker volumes - if running in a container, make sure the mounted volume has correct ownership. The daemon runs as the container's default user (often
nodeorroot). Check with:docker exec <container> ls -la /home/node/.loop-cli/logs -
Disk full - the daemon logs silently. If the disk fills up, loops will fail without clear error messages. Check available space:
df -h ~/.loop-cli/logs
Reset everything (nuclear option)
If loops, the daemon, or the data directory is in an unrecoverable state:
loop-task restartIf the daemon won't stop even with restart:
rm -rf ~/.loop-cli
loop-task startThis deletes all loops, tasks, projects, logs, and configuration. You will lose every loop you created. Only use this when nothing else works.
Debugging tips
| What | How |
|---|---|
| Machine-readable status | loop-task status --json - parse with jq or any JSON tool |
| Daemon diagnostics | cat ~/.loop-cli/daemon.log - timestamps every daemon action |
| Verbose loop creation | loop-task new --verbose 30m -- npm test - see every step |
| Full state inspection | curl http://127.0.0.1:8845/api/loops - raw JSON of all loops |
| API playground | Open http://127.0.0.1:8845/api/docs in your browser for Swagger UI |
| Watch live logs | tail -f ~/.loop-cli/daemon.log - follow new entries in real time |
| Environment snapshot | loop-task env - dump PATH, working directory, and relevant env vars |
FAQ
Do loops survive reboots?
Yes. All loop state is persisted to disk as JSON files in ~/.loop-cli/. When the daemon starts (manually or via loop-task), it reads the data directory, restores every loop, and accounts for any time that elapsed while the daemon was off. A loop scheduled every hour that missed two runs during a reboot will run immediately on daemon startup and then settle into its normal cadence.
Can I run multiple daemons?
No - only one daemon per machine is allowed. The PID file at ~/.loop-cli/daemon.pid prevents a second instance from starting. If you need isolated instances with separate data (e.g., for testing), set a different data directory:
LOOP_CLI_HOME=/tmp/my-test-instance loop-task startThis creates a completely separate environment with its own daemon, socket, and data files.
How do I export/import?
Export all loops, tasks, and projects to a portable JSON file:
loop-task export backup.jsonImport from a backup:
loop-task import backup.jsonImports are additive - they merge with existing data. If a loop ID already exists, the import skips it unless you pass --force.
What happens if a command fails?
The loop captures the exit code and standard error, logs the failure, and waits for the next interval. It does not stop or self-destruct on failure - a failing loop keeps trying on schedule.
If you need failure handling, use task chaining with onFailureTaskId to trigger a recovery task or alert when a command exits non-zero.
Can I edit the JSON files directly?
Yes. All loop state is stored as plain JSON in ~/.loop-cli/loops/. The daemon uses a FileWatcher that detects external changes and hot-reloads them in real time. Just save the file and the daemon picks it up.
# Example: edit a loop's interval directly
code ~/.loop-cli/loops/<id>.json
# Change "interval": "30m" to "interval": "1h"
# Save - the daemon applies it immediatelyBe careful: the daemon also writes to these files. Avoid editing while the daemon is actively running a loop to prevent race conditions. If in doubt, stop the loop first.
How does scheduling work?
Execution times are distributed across the interval using spread scheduling - the daemon computes hash(loopId) % interval to offset each loop within its window. This prevents the thundering herd problem where hundreds of loops scheduled every hour all fire at minute 0. See the Architecture docs for details.