iterion schedule)Some bots are meant to run on a clock, not on demand — a weekly
security audit, a nightly docs-refreshment pass, a periodic dependency
sweep. iterion schedule wires those into the host’s own cron so
they fire on time without keeping an iterion process resident. This
is the complement to iterion dispatch: the dispatcher
is an always-on loop reacting to a tracker; the scheduler is a set of
cron triggers reacting to the clock.
A declarative manifest is the single source of truth. schedule
install materialises it into a managed block of the host crontab; each
cron line calls iterion schedule run <name>, which re-reads the
manifest and executes the run in-process. Because the host scheduler is
the trigger, nothing iterion needs to stay running between firings.
~/.iterion/schedules.yaml # the manifest (override with --manifest or $ITERION_SCHEDULES_FILE)
~/.iterion/logs/schedule-<name>.log # per-schedule stdout+stderr, appended each run
host crontab # a managed block, markers below, regenerated by `schedule install`
The manifest is host-wide (a host has one crontab), and every entry
carries its own workdir, so a single manifest can schedule bots across
several repositories.
version: 1
schedules:
- name: sec-audit-source-weekly # unique; used in the crontab line + log filename
cron: "0 2 * * 1" # standard 5-field expression, passed opaquely to host cron
bot: bots/sec-audit-source/main.bot
workdir: /home/jo/lab/ai/iterion # cd here before running; bot path resolves against it
store_dir: "" # optional --store-dir (default <workdir>/.iterion)
sandbox: "" # optional --sandbox override (none|auto)
timeout: "2h" # optional max run duration (guards a hung run)
vars: # optional --var overrides (commas kept verbatim)
label_source: sec-audit-self
description: Weekly SAST self-audit # optional; emitted as a crontab comment
disabled: false # keep in the manifest, leave out of the crontab
| Command | What it does |
|---|---|
iterion schedule add <name> --cron … --bot … [--workdir …] [--var k=v]… [--store-dir …] [--sandbox …] [--timeout …] [--description …] [--disabled] |
Add or update an entry (upsert by name). |
iterion schedule list [--json] |
List manifest entries. |
iterion schedule remove <name> |
Delete an entry from the manifest. |
iterion schedule run <name> [--dry-run] |
Execute one entry now — what cron invokes. --dry-run prints the resolved iterion run command without executing. |
iterion schedule install [--print] [--tz UTC] |
Sync the manifest into the host crontab. --print renders the block to stdout without touching the crontab (works even where crontab is absent). |
iterion schedule uninstall |
Remove the iterion-managed block from the host crontab (manifest left intact). |
--manifest <path> is available on every subcommand.
add/remove only edit the manifest — run schedule install
afterwards to push the change into the crontab.
schedule install reads the current crontab, replaces (or appends) the
block delimited by:
# >>> iterion schedules (managed by `iterion schedule install`) >>>
…
# <<< iterion schedules <<<
User-authored crontab lines outside the markers are preserved untouched, and re-installing is idempotent (the block is replaced, never duplicated). Two details make scheduled runs actually work in cron’s minimal environment:
CRON_TZ=UTC (override with --tz) — honoured by cronie/Vixie
cron so schedules fire in the intended zone regardless of host local
time; on other cron implementations it is a harmless env var, so
verify the firing time against your cron’s timezone semantics.PATH=<install-time PATH> — captured when you run schedule
install, so docker, git, and any scanner binaries the bot needs
are reachable from cron.A rendered block looks like:
# >>> iterion schedules (managed by `iterion schedule install`) >>>
# Managed by iterion — edit the manifest then `iterion schedule install`.
# Remove with `iterion schedule uninstall`.
CRON_TZ=UTC
PATH=/usr/local/bin:/usr/bin:/bin:…
# Weekly SAST self-audit
0 2 * * 1 cd /home/jo/lab/ai/iterion && /usr/local/bin/iterion schedule run sec-audit-source-weekly --manifest /home/jo/.iterion/schedules.yaml >> /home/jo/.iterion/logs/schedule-sec-audit-source-weekly.log 2>&1
# <<< iterion schedules <<<
iterion schedule add sec-audit-source-weekly \
--cron "0 2 * * 1" --bot bots/sec-audit-source/main.bot --workdir "$PWD"
iterion schedule add sec-audit-deps-weekly \
--cron "0 3 * * 1" --bot bots/sec-audit-deps/main.bot --workdir "$PWD"
iterion schedule run sec-audit-source-weekly --dry-run # sanity-check the resolved command
iterion schedule install # write the crontab block
crontab -l # verify
The audit bots label their findings source:sec-audit-self on the
native board (see Security in CLAUDE.md). They
pin the iterion-sandbox-sec image via sandbox.image, so the host
needs that image present (CI publishes it; for a local loop, docker
tag your build to ghcr.io/socialgouv/iterion-sandbox-sec:edge).
Note:
sec-audit-source(SAST) is production-ready.sec-audit-deps(SCA) is currently an enumerate + LLM-review pass — its heuristic scanner layer is still a scaffold and a run self-labels with a “⚠ Coverage” banner. Schedule it for the LLM-review pass, but treat it as incomplete until the implementation ticket lands.
iterion only
checks the field count (5); range validity is the host cron’s job.schedule install/uninstall shell out to
crontab. On a host without it (e.g. a minimal container, Windows),
use schedule install --print and wire the block into whatever
scheduler you run (systemd timer, Task Scheduler, a CI cron). The
manifest + schedule run <name> work everywhere.iterion resume),
not block the cron job.