Jobs and schedules¶
Jobs make Push useful while you are not in a conversation. Each job is a
user-owned Markdown runbook in the configured assistant repository's jobs/
directory. TOML frontmatter defines execution policy; the Markdown body is
sent verbatim to a fresh backend session.
The schedule definition lives in the same Markdown file as the job. Push evaluates that definition and stores its run and delivery state. For every run:
SOUL.mdis supplied automatically as identity and working instructions;- files under
context/are optional shared information and are not inserted automatically; keep task-specific instructions in the job; - the job body is the fresh request, without chat history or template expansion;
primary_deliveryin Push configuration selects where scheduled results go.
Create a job¶
Create <assistant_root>/jobs/repo-review.md:
+++
version = 1
timeout = "5m"
backend = "codex"
+++
Review repositories with uncommitted work. Summarize the risk and the next
useful action. Do not change files or remote state.
Job names are lowercase ASCII slugs made from letters, digits, and hyphens.
Files must be regular UTF-8 Markdown files directly inside the derived
<assistant_root>/jobs directory.
Subdirectories and symlinks are rejected.
Frontmatter fields:
| Field | Required | Meaning |
|---|---|---|
version |
yes | Format version, currently 1 |
timeout |
yes | Positive duration no greater than jobs_max_timeout |
workdir |
no | Existing working directory for the backend; defaults to assistant_root |
backend |
no | claude, codex, or pi; defaults to jobs_agent, then root agent |
evals |
no | Reusable Markdown agent eval names from <assistant_root>/evals/ |
triggers |
no | One or more cron trigger tables |
Unknown fields are errors. The assistant repository is a valid work directory. A job work directory may not overlap Push state, database, audit log, job lock paths, or a loaded config stored outside the assistant repository.
Validate and inspect jobs¶
Validation reports every valid and invalid file. An invalid job is disabled individually and does not stop messaging or other valid jobs.
Evaluate completed work¶
Jobs can assign one or more reusable agent evals:
Each name resolves to one non-empty regular Markdown file directly under
<assistant_root>/evals/. Names use the same lowercase ASCII slug format as
jobs. Symlinks, missing files, duplicate names, invalid UTF-8, more than 16
assigned evals, files larger than 64 KiB, and assigned evals larger than 256 KiB
in total are rejected during job validation. Assigned eval contents are included
in the validated job snapshot, so changing an eval changes the snapshot used for
future claims.
For example, create <assistant_root>/evals/writing-style.md:
After a job returns successfully, Push starts one fresh evaluator session using
the same backend, timeout, and work directory. The evaluator receives the
original job, final response, and every assigned eval, then must finish with
VERDICT: PASS or VERDICT: FAIL. Push disables evaluator shell access,
external MCP tools, extensions, browser integrations, and session persistence.
Codex project instructions are also disabled. Some backends may retain
non-mutating built-in utility tools. The first version evaluates the returned
response and does not inspect work-directory artifacts.
Evaluation is recorded separately as running, passed, failed, error, or
not_requested. A failed or malformed evaluation does not rewrite the result,
rerun the job, or change a successful execution into a failed execution.
Scheduled delivery includes the evaluation verdict and failure details.
Run a job manually¶
A manual run executes in the invoking CLI process and prints its result there. It does not proactively message a channel. Push records and claims the run in SQLite before starting the backend and holds a non-blocking per-job advisory lock for the run's lifetime.
If the same job is already active, the new attempt is recorded as
skipped_overlap. A fresh claim can recover a stale claim only after acquiring
the released OS lock, so a live process is not reclaimed from database state
alone.
Schedule a job¶
Add one or more five-field cron triggers:
[[triggers]]
id = "weekday-morning"
kind = "cron"
schedule = "0 8 * * 1-5"
timezone = "Europe/London"
enabled = true
Then configure a delivery destination:
Scheduling starts only when the primary destination is enabled and allowlisted. A missing or invalid destination disables new scheduled starts without affecting conversations or manual jobs.
Push runs at most jobs_max_workers scheduled jobs concurrently. It does not
catch up cron occurrences missed while offline. Daylight-saving gaps are
skipped; repeated local times run once at their first instant. Cron expressions
whose selected months and days can never form a calendar date are rejected
during job validation.
Complete assistant example¶
The daily inbox triage job keeps global identity separate while making the scheduled runbook self-contained:
That one job file contains its schedule, triage priorities, output format, and
safety rules. It uses email tools configured in the selected agent, drafts no
replies, and performs no external side effects. Its schedule is disabled by
default. Set enabled = true in the job only after configuring the email tools
and primary delivery destination.
Execution and delivery guarantees¶
- Every job and evaluator run uses a fresh backend session, without chat history.
- Codex and Claude jobs bypass interactive permissions so unattended work can complete. Evaluators remain restricted.
- Push does not retry failed or timed-out backend execution because the agent may have completed external side effects before failing.
- Success, failure, timeout, overlap, and delivery state are stored separately.
- Scheduled output is persisted before delivery.
- Delivery retries use the stored result and never rerun the backend.
- Delivery is claimed across gateway processes. Normal partial-message retries resume from the first unsent chunk. Push checkpoints each successful chunk and bounds a delivery attempt below its claim lease so an active worker cannot be reclaimed. Delivery can still produce an at-least-once duplicate after a process crash between a channel send and its checkpoint, or after a delivery-state persistence failure, because channel APIs do not provide atomic delivery.
- Queued runs and pending delivery survive restart. Interrupted execution is not automatically replayed.
Use push job runs [<name>] to inspect execution state, evaluation state,
delivery attempts, destination, bounded results, and error details.
Agent-created jobs¶
When a user asks for a job, the assistant writes the complete runbook directly
to <assistant_root>/jobs/<lowercase-slug>.md and runs push job validate.
There is no separate draft or approval step. The selected agent's filesystem
permissions control whether it can change the assistant repository.
For an assistant repository created before this change, replace any AGENTS.md
instruction that says to propose jobs through approval with the direct-write
rule above. The gateway's runtime instruction overrides that old rule, but
updating the repository keeps its checked-in guidance accurate.
Pending job approvals from older Push versions are cancelled during database migration. Replying to one explains that the job must be requested again.
Warning
Jobs have no interactive approval path. Push runs Codex jobs with full
access and no prompts and Claude jobs in bypassPermissions mode. Treat
every enabled job as code execution by the Push service user, review
changes to the assistant repository, and allow only trusted senders.