iterion

Scheduling recurring bot runs (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.

Model

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.

Manifest format

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

Commands

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.

The managed crontab block

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:

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 <<<

Example — weekly self-audit

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.

Notes & limits

Implementation