The Build Without Scheduling Pitfall
Code merged, tests passing, feature never runs. Three real examples from Knox's fleet and the five-point definition of done that prevents autonomous features from launching without their ops wiring.
In April 2026, Knox ran a systematic review of the Mac Mini fleet and found a recurring pattern across multiple projects: features had been built, PRs had merged, tests had passed, and the features were not running. Not broken — just never scheduled.
This pattern has a name: build without scheduling. The code exists. The ops wiring to make it autonomous does not.
Three Real Examples
Example 1 — Intelligence router reading the wrong source
The intelligence router was supposed to pull from a database of enriched signals and display them in the mission control dashboard. Instead, it was pulling from a live API endpoint — the same one used in early development before the pipeline was built.
The result: the dashboard showed real-time data from the external API rather than processed, enriched data from the internal pipeline. Both were structurally identical JSON. No error. No alert. The wrong thing worked correctly.
Root cause: when the pipeline was built and the DB read was added to the code, the hardcoded live endpoint was not removed. The feature was "done" because tests passed — but the tests were running against the endpoint, not the database.
Example 2 — Council sessions stale for days
The council session generator was a scheduled job that ran nightly, synthesizing the day's agent activity into a structured session record for review. For several days, the dashboard showed no new sessions.
No errors in any log. The generator code was correct. The tests passed.
Root cause: the launchd plist had never been created. The job ran once manually during development to verify it worked, was confirmed as working, and was merged. Nobody created the plist. The job ran exactly once.
Example 3 — Pulse events empty
The pulse event writer was designed to write structured events to a specific path that the pulse reader monitored. The reader was finding nothing.
The writer code was correct. The reader code was correct. The path configured in the writer did not match the path the reader was watching.
Root cause: the writer had been developed on a different machine with a different directory structure. The path constant was updated for the local environment but not for the production environment. The feature shipped with a storage location mismatch baked in.
The Five-Point Definition of Done
These three failures share a structure: the code was correct, the local verification was correct, and the production integration was not verified. The "definition of done" stopped at PR merge.
For any feature that runs autonomously in production, the definition of done requires five confirmations:
Code merged ✓
Tests passing ✓
Launchd plist wired ✓ (or cron entry created)
First run confirmed ✓ (logs show success on the production machine)
Monitoring registered ✓ (watchdog knows about this process)
The five points are not bureaucratic checkboxes. Each one catches a specific class of failure:
- Tests passing catches code logic errors
- Launchd plist wired catches the council session problem
- First run confirmed catches path mismatches and environment differences
- Monitoring registered catches the scenario where the feature breaks two weeks later and nobody notices
Skipping any of the last three produces a feature that exists in the codebase but does not exist in production.
The Grep Check
Before calling any background-runner feature done, run a grep check on the related code:
# Check for existing launchd plist
ls ~/Library/LaunchAgents/ | grep <feature-name>
# Check for cron entry
crontab -l | grep <feature-name>
# Check for watchdog registration
grep -r "<feature-name>" ~/dev/watchdog/
If none of these produce results, the feature is not scheduled. This check takes fifteen seconds. It is the simplest possible gate between "code merged" and "running in production."
Why Agents Generate This Pattern
The build-without-scheduling pattern is especially common in agent-driven development, and for a structural reason: agents optimize for the criteria they are given.
When an agent is asked to build a scheduled pipeline, the criteria it can verify are:
- Does the code run without errors? (yes, test it)
- Do the tests pass? (yes, run them)
- Does the PR merge? (yes, check the CI status)
The criteria it cannot verify without explicit instruction are:
- Is the launchd plist deployed to the production machine?
- Did the job run successfully on the production machine?
- Does the watchdog know about this process?
The agent has no natural checkpoint for these questions. Its task is complete when the PR merges. Whether the feature runs in production is a different task that nobody assigned.
This is not a criticism of agent behavior — it is a description of how task scope works. The agent completed what it was asked to do. The gap is that the task description stopped at code delivery and did not include ops delivery.
The Skill as a Completion Gate
The fix for this pattern is to make the ops wiring checklist a skill that the agent must invoke before reporting completion.
When the skill exists as a discrete step — "before closing this ticket, invoke the ops-wiring-check skill" — the agent cannot skip it. The skill runs the grep checks, verifies the plist, confirms the first run log, and returns a pass/fail result. If it fails, the ticket remains open.
A skill that cannot be skipped is a completion gate. A mental note is not.
The difference matters because agent sessions end. A mental note that "I should check the launchd plist" disappears when the session ends. A skill invocation requirement in the ticket template persists across sessions, across agents, and across humans who pick up the ticket later.
Wiring the Plist
For reference, a minimal launchd plist for a scheduled Python script looks like this:
<?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>com.operator.feature-name</string>
<key>ProgramArguments</key>
<array>
<string>/opt/homebrew/bin/python3</string>
<string>/Users/operator/dev/project/script.py</string>
</array>
<key>StartInterval</key>
<integer>3600</integer>
<key>KeepAlive</key>
<false/>
<key>StandardOutPath</key>
<string>/tmp/feature-name.log</string>
<key>StandardErrorPath</key>
<string>/tmp/feature-name.error.log</string>
</dict>
</plist>
After creating the plist:
launchctl load ~/Library/LaunchAgents/com.operator.feature-name.plistlaunchctl start com.operator.feature-name- Wait 30 seconds, then check
cat /tmp/feature-name.logfor the first run
The first run log is the completion artifact. Not the plist. Not the launchctl load. The log entry proving the code ran successfully on the production machine.
Until that log entry exists, the feature has not shipped.