Cron Jobs
/cron arms a scheduled instruction on a chat. Kanna owns the timer, so the
job keeps firing across server restarts, and every run is recorded in the chat
you armed it from.
/cron check CI and report failures inline every 5m/cron write the daily standup summary spawn 0 9 * * 1-5The two run modes
Section titled “The two run modes”Every job picks one, and the difference is where the work happens.
| Mode | Where each run executes | What the arming chat becomes |
|---|---|---|
inline |
The arming chat itself | A monitoring view — context is cleared before every run |
spawn |
A brand-new chat per run, in the same project | A dashboard — one run card per fire, with a link and live status |
inline is for a recurring check you want to watch in one place. Kanna
clears the chat’s context before every cycle (the /clear machinery), so the
agent starts fresh each time and the chat never accumulates history. That means
anything you discussed in the chat by hand is wiped on the next fire — the
arming card says so.
spawn is for work that deserves its own thread. Each fire creates a chat
in the arming chat’s project and runs the instruction there; the arming chat
collects a run card showing the trigger time, the instruction, a link to the
spawned chat, and a status pill that goes Running → Completed / Failed live.
Command grammar
Section titled “Command grammar”/cron <instruction> <inline|spawn> <schedule> arm a job/cron list show this chat's jobs/cron remove <id> disarm one job/cron pause <id> stop firing, keep the job/cron resume <id> start firing again/cron usage helpThe instruction needs no quotes. Kanna anchors on the last inline /
spawn token in the line, so everything before it is the instruction verbatim
and everything after is the schedule. If your instruction genuinely ends with
the word “inline” or “spawn”, wrap it in double quotes:
/cron "audit everything inline" spawn @weeklyA chat can hold any number of jobs, each with its own id, schedule, and mode.
Schedules
Section titled “Schedules”Four syntaxes, all accepted anywhere a schedule is expected:
| Syntax | Example | Meaning |
|---|---|---|
| 5-field cron | */15 9-17 * * 1-5 |
Every 15 min, 9am–5pm, weekdays |
| 6-field cron | */30 * * * * * |
Every 30 seconds — the extra field is a leading second |
| Shortcut | @hourly @daily @weekly @monthly |
Top of the hour / midnight / Sunday / the 1st |
| Interval | every 30s every 5m every 2h |
Every N seconds, minutes, or hours from the moment you armed it |
Cron fields support *, N, N-M, */S, N-M/S, comma lists, and month /
weekday names (jan, mon). Day-of-month and day-of-week follow the standard
vixie rule: when both are restricted the day matches if either matches.
Sub-minute schedules
Section titled “Sub-minute schedules”There is no minimum cadence: every 1s and * * * * * * both arm. What
bounds a fast job is not a rule but reality — a run is a whole agent turn, so
a job scheduled every 5 seconds against work that takes 20 will spend most of
its ticks skipping.
Those skips are recorded, not hidden, but consecutive skips collapse into one
card carrying how many ticks it stands for (Cron runs skipped 9× — chat was busy). Without that, a fast job would bury its own output under skip notices.
A slow job is unaffected: an isolated skip is still reported the moment it
happens.
Pick a cadence with the work in mind. If each run takes 20 seconds, every 30s
gets you every run; every 2s gets you the same runs plus a lot of skips.
Schedules run on server-local time. Per-job timezones are not supported.
Validation catches mistakes before anything arms
Section titled “Validation catches mistakes before anything arms”A mistyped schedule is never sent to the model as a prompt. Any line starting
with /cron is intercepted, and an invalid one produces an error card showing
the line you typed and naming the exact problem — plus a complete,
ready-to-send corrected command you can copy whenever the fix is unambiguous:
| You typed | Kanna says | It suggests |
|---|---|---|
/cron check ci spwan @daily |
unknown mode “spwan” | /cron check ci spawn @daily |
/cron check ci inline every 5min |
interval unit “min” is not valid — use s, m, or h |
/cron check ci inline every 5m |
/cron nightly build spawn 0 3 * * |
cron schedule has 4 fields, expected 5 or 6 | /cron nightly build spawn 0 3 * * * |
/cron nightly build spawn 0 3 |
cron schedule has 2 fields, expected 5 or 6 | /cron nightly build spawn 0 3 * * * |
/cron check ci inline 0 9 * * 8 |
day-of-week field “8” is out of range 0-7 | — (ambiguous, no guess) |
Nothing arms until the command is valid.
When Kanna can’t fix it, the agent does
Section titled “When Kanna can’t fix it, the agent does”Some mistakes have no mechanical answer. 9am every day is English where a
schedule belongs, and when the mode is missing entirely nothing can tell
whether the job should run in this chat or spawn its own. Rather than leave you
re-typing, Kanna hands those lines to the agent, which repairs and schedules
the job — or asks what you meant:
You /cron check CI inline 9am every day
⚠ Invalid /cron command /cron check CI inline 9am every day cron schedule has 3 fields, expected 5
Claude "9am every day" is `0 9 * * *` in cron. Scheduling that. ✅ Cron armed — cron-a1b2, every day at 09:00, next run tomorrow 09:00Where your intent is genuinely ambiguous the agent asks first and schedules
your answer instead of guessing. It steps in only where Kanna had no
suggestion of its own, so every copy-a-fix case above stays instant and costs
nothing. Set KANNA_CRON_REPAIR=disabled to turn it off.
A schedule that parses but can never occur — /cron report inline 0 0 30 2 *,
February 30th — is refused at arm time and goes to the agent the same way.
When a run would overlap
Section titled “When a run would overlap”If a scheduled fire arrives while the previous run is still going, Kanna
skips that tick and says so in the chat — it never queues runs up behind a
slow one. In inline mode a busy chat (you’re mid-turn, or a question is
waiting) also skips.
Skips are visible one-liners, so a job that keeps missing its window is obvious rather than silent. Consecutive skips share one line and a count, so a fast schedule reports about once a minute instead of once per tick — the miss is never hidden, only stated once.
Restarts and missed fires
Section titled “Restarts and missed fires”Jobs are durable: they’re recorded on the chat’s event log and re-armed when the server starts. Fires that were missed while the server was down are skipped, not replayed — Kanna appends a single notice per job saying how many were missed and arms the next future occurrence. A restart never triggers a burst of catch-up runs.
Deleting a chat disarms its jobs. Chats spawned by a spawn job are ordinary
chats and survive independently.
Managing jobs
Section titled “Managing jobs”Three surfaces, all doing the same thing:
- The chat footer panel — every armed job on the current chat with its humanized schedule, mode, a live next-fire countdown, last run status, and pause / resume / remove buttons.
/cron list|pause|remove|resume— the same operations typed.- The global Cron Jobs page (
/cronin the sidebar) — every job across all projects and chats, grouped by project, with links into each job’s chat and the same controls. This is the place to answer “what do I have running anywhere?”
Chats with an armed, unpaused job are flagged in the sidebar.
Cron jobs vs. loops
Section titled “Cron jobs vs. loops”Both run work repeatedly, for different reasons:
- Cron fires on the clock, forever, whether or not there’s progress to make. Use it for polling, reports, and periodic checks.
- A loop (
setup_loop) fires on completion and stops when its goal is met, driven by a verify command and a tracking file. Use it for finishing a body of work.
A cron job has no goal and no oracle; it stops when you stop it.