Cron mode
PIBOX_CRON_MODE=1 + PIBOX_CRON_MODE_FILE=/path/to/cron.yaml. YAML-defined scheduled jobs on six-field croniter schedules. Each job fires Pi with its instruction.
Setup
# cron.yaml
jobs:
- name: morning-standup
schedule: "0 0 9 * * 1-5"
instruction: |
Summarize what changed in /workspace since yesterday.
Be brief. One paragraph max.
workspace: myproject
telegram_chat_id: -100123
model: your-model-id
thinking: low
# docker-compose.yml
services:
pibox:
image: psyb0t/pibox:latest
environment:
- PIBOX_CRON_MODE=1
- PIBOX_CRON_MODE_FILE=/home/aicode/.aicodebox/cron.yaml
- PIBOX_PROVIDER_BASE_URL=https://api.z.ai/api/anthropic
- PIBOX_PROVIDER_API=anthropic-messages
- PIBOX_PROVIDER_API_KEY=your-z-ai-api-key
- PIBOX_PROVIDER_MODEL=your-model-id
volumes:
- ~/.aicodebox:/home/aicode/.aicodebox
- ~/workspaces:/workspace
The schedule field has six fields with seconds first, so "0 0 9 * * 1-5" is 09:00:00 on weekdays.
File format
The file is a mapping with a jobs list. Keys at the top level, next to jobs, set defaults for every job.
| Key | Where | Meaning |
|---|---|---|
jobs | top level | Required, a non-empty list |
name | job | Required, unique, letters, digits, _ and - only |
schedule | job | Required, a six-field cron expression |
instruction | job | Required, the prompt Pi runs |
workspace | job | Workspace subpath to run in. Default ., the workspace root |
no_continue | job | true starts a fresh session each run. Default false, which continues the last session in that workspace |
model | job or top level | Model for the run |
thinking | job or top level | Pi thinking level |
effort | job or top level | Used as the thinking level when thinking is not set |
system_prompt | job or top level | Replaces the system prompt |
append_system_prompt | job or top level | Appended to the system prompt |
telegram_chat_id | job or top level | Chat that receives the result. 0 on a job opts out of the top-level default |
An invalid file stops the scheduler with a message naming the job and the key.
Run history
PIBOX_CRON_MODE_HISTORY_DIR (default $HOME/.aicodebox/cron) is the whole cron state root. Each run gets a history directory under <root>/history/<workspace>/<timestamp>-<job>/ with meta.json, stdout.log, stderr.log and result.txt. If Telegram is configured, telegram.json lands there too, and the next run’s prompt gets a “prior run” hint so Pi can read its own history without you wiring it up. A per-job summary is appended to <root>/<job>.jsonl.
Setting the variable moves the whole root, including run history, job summaries, and the Telegram reply bridge’s telegram_messages.json. Do not point it at the history child directory.
Notifications
A job with telegram_chat_id set sends its result to that chat when it finishes. That needs Telegram mode running in the same container, see below. A successful job with an explicit recipient notifies even when its result text is empty, and a failed job sends a failure notice.
Cron mode environment variables
| Var | Default | What it does |
|---|---|---|
PIBOX_CRON_MODE | 0 | Boot the cron scheduler (foreground, or inside the bot when Telegram is also on) |
PIBOX_CRON_MODE_FILE | none | Path to the cron file |
PIBOX_CRON_MODE_HISTORY_DIR | ~/.aicodebox/cron | Cron state root. Run history, job summaries and the Telegram reply bridge’s message inbox all live under it |
Every
PIBOX_*variable is an alias for theAICODEBOX_*equivalent read by the base image. If both are set,AICODEBOX_*wins.
Combined with Telegram mode
Setting PIBOX_TELEGRAM_MODE=1 alongside cron runs the scheduler inside the bot, which is what makes telegram_chat_id on a job deliver its result to a chat. See Telegram mode.
Combined with MCP mode
Cron is a foreground mode, so MCP runs as a sidecar next to it: scheduled jobs on their own schedule, and the same box reachable as a tool the whole time.