Logs, Errors, and Debugging
Where logs go, what to do when jobs fail, how to diagnose.
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.logStdout is your job's output. Stderr is where errors go. The CLI wraps both:
bun run src/cli.ts logs hello-worldThe Doctor
jobs doctor runs a systematic check on every job:
bun run src/cli.ts doctorIt 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-worldCommon 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 syncNon-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 failuresOr 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-jobIf 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
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.