Debugging and cleanup
Open this when a scheduler is silent, fires twice, exits early, or must be
retired. Diagnose in order; do not assume that a successful scheduler exit means
that the work or wake reached the agent.
Silent scheduled work
- Did the scheduler fire? macOS:
launchctl list <label> and inspect
PID/LastExitStatus; Linux: systemctl --user list-timers; cron: inspect
/var/log/cron or journalctl -u cron for CMD. Check unit syntax
(plutil -lint or systemctl --user status), loaded/disabled state, sleep
catch-up behavior, and clock time.
- Did the script run? Read its own append-only log, not only scheduler
stdout/stderr. A missing
[fire] means an early launch failure; a [fire]
without completion means an in-script failure. Keep set -euo pipefail and
log the command boundary that failed.
- Did work land? Compare the script's audit evidence with the expected
artifact/commit/message. A logged success with no artifact is script logic,
not a scheduler mystery.
- Did the agent see the wake? For mailbox work, inspect human
mailbox/outbox/<uuid>, then mailbox/sent/<uuid>, then the recipient's
mailbox/inbox/<uuid>. Validate malformed JSON and confirm the recipient.
A queued mail waits for the next turn; use the scheduler reference's
.refresh rule only when prompt pickup is required.
Retire without a janitor race
First obtain explicit authority for stopping/removing the named scheduler and
review a dry-run. Then:
- Unload the unit (
launchctl unload <plist> or
systemctl --user disable --now <timer>), and verify it is gone.
- Only then remove the unit and script; archive logs if history matters.
- Record the unit name and retained evidence. Never delete the script first,
remove
.agent.lock, or launch a parallel relaunch: the kernel owns its
flock and refresh watcher. On macOS, a scheduler may reap descendants when
its process exits; read the scheduled-work process-tree warning before
intentionally launching a long-lived child.
Shell footprint
Shell may create scripts, logs, downloads, virtualenvs, scheduler units, and
build artifacts. Retain artifacts by default. Cleanup is command-specific: show
a dry-run and obtain explicit human authorization before destructive removal.
For inspection, call psyche(action="skills", input={}), then follow
skills-manual to reference/cleanup-footprint-contract.md and its shared
footprint recipe. Combine it with this task's selected paths in one
script. Inspection writes nothing. If the human selected an audit, append to
logs/cleanup.jsonl and record retired scheduler units.
1---2name: bash-debugging-cleanup3description: Nested shell-manual reference for debugging silent scheduled jobs and retiring schedulers safely: scheduler, script, work, wake, launchd, cleanup, and shell work-footprint checks.4---56# Debugging and cleanup78Open this when a scheduler is silent, fires twice, exits early, or must be9retired. Diagnose in order; do not assume that a successful scheduler exit means10that the work or wake reached the agent.1112## Silent scheduled work13141. **Did the scheduler fire?** macOS: `launchctl list <label>` and inspect15 `PID`/`LastExitStatus`; Linux: `systemctl --user list-timers`; cron: inspect16 `/var/log/cron` or `journalctl -u cron` for `CMD`. Check unit syntax17 (`plutil -lint` or `systemctl --user status`), loaded/disabled state, sleep18 catch-up behavior, and clock time.192. **Did the script run?** Read its own append-only log, not only scheduler20 stdout/stderr. A missing `[fire]` means an early launch failure; a `[fire]`21 without completion means an in-script failure. Keep `set -euo pipefail` and22 log the command boundary that failed.233. **Did work land?** Compare the script's audit evidence with the expected24 artifact/commit/message. A logged success with no artifact is script logic,25 not a scheduler mystery.264. **Did the agent see the wake?** For mailbox work, inspect human27 `mailbox/outbox/<uuid>`, then `mailbox/sent/<uuid>`, then the recipient's28 `mailbox/inbox/<uuid>`. Validate malformed JSON and confirm the recipient.29 A queued mail waits for the next turn; use the scheduler reference's30 `.refresh` rule only when prompt pickup is required.3132## Retire without a janitor race3334First obtain explicit authority for stopping/removing the named scheduler and35review a dry-run. Then:36371. Unload the unit (`launchctl unload <plist>` or38 `systemctl --user disable --now <timer>`), and verify it is gone.392. Only then remove the unit and script; archive logs if history matters.403. Record the unit name and retained evidence. Never delete the script first,41 remove `.agent.lock`, or launch a parallel relaunch: the kernel owns its42 flock and refresh watcher. On macOS, a scheduler may reap descendants when43 its process exits; read the scheduled-work process-tree warning before44 intentionally launching a long-lived child.4546## Shell footprint4748Shell may create scripts, logs, downloads, virtualenvs, scheduler units, and49build artifacts. Retain artifacts by default. Cleanup is command-specific: show50a dry-run and obtain explicit human authorization before destructive removal.51For inspection, call `psyche(action="skills", input={})`, then follow52`skills-manual` to `reference/cleanup-footprint-contract.md` and its shared53footprint recipe. Combine it with this task's selected paths in one54script. Inspection writes nothing. If the human selected an audit, append to55`logs/cleanup.jsonl` and record retired scheduler units.