Scheduled local dogfood verification
The local scheduler runs configured public repository and private transcript suites
through the installed praetorctl. It retains evidence for every admitted run and
creates local repair plans for failed cases. Plans select eligible models using
declared routing prices and explicit token estimates. They do not execute agents,
apply patches, promote repository stages, or send messages.
Configure a bounded schedule
Create a private (0600) schedule JSON and suite JSON outside the public checkout.
All paths are clean absolute paths. The state directory's parent must exist.
The suite guide describes pinning public repositories and
transcripts. Public cases require allow_remote: true explicitly.
{
"version": 1,
"runner_binary": "/home/example/.local/bin/praetorctl",
"suite_config": "/home/example/.config/praetor/local-suite.json",
"source_root": "/home/example/dev/praetor",
"state_dir": "/home/example/.local/state/praetor/dogfood-local",
"allow_remote": true,
"interval_seconds": 86400,
"retry_seconds": 3600,
"max_consecutive_failures": 3,
"max_runs": 32,
"max_bytes": 2147483648,
"retention": "block",
"repair_policy": {
"routing_config": "/home/example/dev/praetor/.config/models/routing.yaml",
"task": "ci_debugging",
"input_tokens": 8000,
"output_tokens": 2000,
"max_cost": 0.1
}
}
The required repair_policy fields are routing_config, task, input_tokens,
output_tokens, and max_cost. The register tuple (register, register_source,
prompt_register, prompt_register_source, max_output_tokens,
register_manifest_sha256) is resolved from the repository's canonical register
manifest using task and is never taken from the caller: any values supplied for
those fields are discarded and replaced with the manifest's resolution before the
policy is validated or run, so status and admission use the canonical tuple
regardless of what the config file contains for it.
Inspect the configuration and run one bounded tick:
praetorctl dogfood schedule status --config /absolute/schedule.json
praetorctl dogfood schedule run --config /absolute/schedule.json
Ticks use a process lock, persisted attempt state, retry cooldown, and a consecutive
failure circuit. Changed build or configuration fingerprints become eligible for
a new run. A failed or interrupted run remains visible. The retained run count,
byte limit, and 200,000 entry cap are admission thresholds, not disk quotas: an admitted suite can grow
beyond the threshold, after which subsequent admission stops. Configured retention: "block" (default)
blocks admission with status: resource_blocked without error when max_runs, max_bytes, or 200,000 entries
is exceeded. When configured with retention: "prune-oldest", the scheduler prunes the oldest completed attempt
directory before admission when retained runs exceed max_runs, entries exceed 100,000 (half of the entry cap),
or bytes reach max_bytes, persisting pruned_through with fsync before deletion and reporting pruned_runs.
Retained attempt directories must exist gapless from pruned_through + 1 through attempts.
Status reads current admission and reports what would be pruned without deleting evidence.
A due run waits for the host admission policy shared with the race stage
(admission.HostCappedPolicy). A held tick returns status: host_held and
host_reason; the next tick retries, with no attempt or failure counted.
Status-only reads stay due without reading the host. Host read errors stop the tick.
Install the user timer
Install fresh local binaries with make dev-install, then run:
python3 -B scripts/dev_schedule.py install --config /absolute/schedule.json --activate
python3 -B scripts/dev_schedule.py status
systemctl --user start praetor-dogfood-local.service
journalctl --user -u praetor-dogfood-local.service -n 40 --no-pager
The installer validates the schedule and generated units before replacing managed
files. It retains previous units and an installation manifest under
~/.local/state/praetor/dev-schedules/install-*, verifies activation, and attempts
rollback if installation fails. An interrupted process leaves backups for review.
Foreign units, overrides, symlinks, and concurrent installers are rejected.
The timer first checks after two minutes, then fifteen minutes after the previous service finishes. The scheduler independently enforces its daily interval and hourly retry policy. The oneshot service has a seventeen-minute start deadline; an active service is not started again. User timers run while the user service manager is available; the installer does not enable lingering or change system services.
Without --activate, installation preserves the previous timer activation state.
To stop future scheduling while retaining units, an active run, and all evidence:
Service success means that the tick completed according to scheduler policy; inspect the schedule report to distinguish a verified suite from a cooldown or other skipped tick. Model selection is an estimate from the configured catalog. Provider capacity, current prices, and successful agent execution require later rollout evidence.
The development MCP exposes standards_dogfood_schedule_status for the same status
read. Its config_path and every embedded read path obey the server root policy;
it never creates schedule state or starts a run. Use an explicitly configured
workstation root when inspecting private configuration outside the source checkout.