Routines
A routine is a small program you write to do a job, such as downloading a weekly report from a site you log in to. The Mac runs it on a schedule, and Pepper watches it. Every field and rule is in Routines.
A routine is a fixed program that runs without an AI model, so it costs no tokens. When it breaks, it should
say so, by exiting with an error or printing a needs_you line, rather than improvise. Pepper never sends anything to anyone
but you. A routine you write can send things to other people, and its settings file, ROUTINE.md, says what
it sends.
Each routine is one folder under Pepper's data folder, data/routines/ by default (or
$PEPPER_DATA_DIR/routines/ if you set that). Set PEPPER_ROUTINES_DIR to keep them somewhere else. The
folder name is the routine's name.
routines/
weekly-report/
ROUTINE.md you write it: settings and a paragraph in plain words
run you write it: the program, in any language
state/ the routine's own files: cursors, downloads. Pepper never reads it
status.json Pepper writes it after every run
log/ Pepper keeps the last 30 runs hereROUTINE.md starts with a few settings:
---
name: weekly-report
description: Download the weekly sales report and file it in Documents
schedule: "0 8 * * 1" # 08:00 every Monday, in your time zone
timeout: 2m
sends: []
---
Logs in to the reporting site and saves the newest report. The password is in the Keychain
under "pepper.weekly-report". If the login breaks, run ./run login in this folder.The paragraph under the settings is for you: what it does, where its secrets are, and how to fix it.
- The routine gets none of Pepper's keys. It starts with a bare environment: the path, your home folder and user name, your language, a temp folder, your time zone, and its own name and folder. Its own secrets go in the macOS Keychain or a private file in its folder.
- Pepper reads
ROUTINE.mdandstatus.json, and keeps what the program prints. The program's output goes tolog/, and the last lines of any errors go intostatus.json; Pepper also keeps small.lockand.pausedmarkers in the folder. It never opensstate/. Keep secrets out ofROUTINE.mdand out of whatrunprints. - Everything the routine writes about itself, such as its description or summary, is shown as text. Pepper treats it like any other text from outside and never acts on it.
Steps marked You are ones only you can do.
-
Create the starter files. This writes a
ROUTINE.mdand arunthat prints a greeting as its summary:npm run routines new weekly-report -
You: write the program in
runand fill inROUTINE.md. Store any password in the Keychain yourself. -
Run it once and read the result:
npm run routines run-now weekly-reportIf it controls another app, such as Mail, macOS asks for permission the first time. You: run it once by hand at the Mac and allow it.
-
Schedule it:
npm run routines install weekly-reportInstall checks the folder first and, if something is wrong, stops and tells you why. Run it again whenever you change
scheduleinROUTINE.md; editing the file alone doesn't change when the Mac runs it.
Make run safe to repeat: record what it did in state/ only once it's done.
Never put a real routine in the Pepper repository. Keep them in the data folder, or in a private repository of your own.
The Routines tab on the dashboard lists every routine with a description, a schedule in plain words (or the cron line when it can't be put plainly), what it last did, and a state:
| State | Means |
|---|---|
| ok | The last run worked. |
| running | A run is in progress. |
| failed | The last run exited with an error, timed out, or died. |
| late | A run was due and nothing ran for longer than expect_every (twice the gap between runs unless you set it, so two weeks for a weekly routine). Usually the Mac slept. |
| broken | ROUTINE.md or run breaks the rules; the tab says how. |
| paused | You paused it. |
| not run yet | Installed; waiting for the first run. |
| not installed | The folder exists but nothing schedules it, including after uninstall. |
A routine that sends something shows a small label for each thing listed under sends in its ROUTINE.md,
such as "sends email". That list is your description of the routine, not a limit Pepper enforces.
A routine can end its run by printing one line of JSON. Its summary shows on the tab. Use needs_you when you
want Pepper to ask you to take action:
{"summary": "no new report", "needs_you": "Login expired: run ./run login"}When a routine is late, failed, broken, or sets needs_you, Pepper tells you in three places:
- on the Today page, at the top, as "Routine weekly-report needs you: Login expired: run ./run login";
- in your next brief, as one "Routines:" line;
- as a count on the Routines tab.
A healthy routine never raises an alert. It still appears in status lists and on Connections when it sends
something, and the brief's Routines line may count it among the ones that are fine. Use needs_you only
when you must act.
On the Routines tab, each row has Pause (or Resume when the routine is paused) and Run now (unless the routine is broken, paused or already running). Run now starts the routine the same way the schedule does; refresh in a moment for the result.
From a terminal on the Mac:
| Command | Does |
|---|---|
npm run routines status | Every routine's state, as on the tab |
npm run routines pause weekly-report | Stops new runs without removing the schedule; a run already underway finishes |
npm run routines resume weekly-report | Starts them again |
npm run routines uninstall weekly-report | Removes the schedule; the folder stays |
In Telegram, /routines shows the same list. Pausing Pepper with /halt does not pause your routines, but
it does stop Run now on the dashboard. Pause each routine separately.