Jobs will fail. The LLM will time out. The API key will expire. The run script will have a typo. The question isn't whether things break — it's how fast you find out why.
Where Logs Live
Every job gets its own log files:
workdir/logs/{job-name}/stdout.log
workdir/logs/{job-name}/stderr.log
Stdout is your job's output. Stderr is where errors go. The CLI wraps both:
bun run src/cli.ts logs hello-world
The Doctor
jobs doctor runs a systematic check on every job:
bun run src/cli.ts doctor
It checks: schedule file valid? Run script exists and is executable? Shebang present? Plist validates? Job loaded in launchd? Exit code non-zero? Stderr has content?
Each issue comes with a severity and a fix:
{
"severity": "error",
"message": "Run script is not executable",
"fix": "chmod 755 system-jobs/my-job/run"
}
Doctor a specific job:
bun run src/cli.ts doctor hello-world
Common Failures
"env: bun: No such file or directory" in stderr
launchd runs with a minimal PATH. The manager injects your PATH into the plist, but if you installed bun AFTER the last sync, re-sync:
bun run sync
Non-zero exit code but no stderr
The job errored but swallowed the error. Add error handling to your run script:
#!/bin/bash
set -euo pipefail # Exit on error, undefined vars, pipe failures
Or in bun:
main().catch((error) => {
console.error("[job] Failed:", error);
process.exit(1);
});
Job doesn't run on schedule
# Is it loaded?
launchctl list | grep aijs
# Force-run it
bun run src/cli.ts kick my-job
# Did it produce output?
bun run src/cli.ts logs my-job
If kick works but the schedule doesn't fire, check the schedule format. A common mistake: {"Hour": 9} without "type": "scheduled" — the parser might not infer the type correctly.
The Debugging Workflow
jobs doctor <name>— systematic checkjobs logs <name>— what did it output?jobs kick <name>— can it run at all?jobs plist <name>— is the generated plist correct?launchctl list | grep <label>— does launchd know about it?
This sequence finds 95% of problems. The other 5% is usually a run script bug — test your script directly with bun run system-jobs/my-job/run before relying on launchd.
What You Learned
- Every job gets stdout.log and stderr.log in
workdir/logs/ jobs doctoris the first thing to run when something breaks- PATH issues are the #1 launchd gotcha — re-sync after installing new tools
- Test your run script directly before relying on launchd to run it