# Proactive routines MausBot keeps an eye on the person's day with one ordinary routine, "Keep an eye on my day". It is made once, with no button, on a personal install or Cloud that can reach connected apps, and it is built from four upgrades every routine can use, plus the helper models for the inbox. The bot that is proactive is the one `proactiveOwner` names (`server/host/proactive-owner.ts`): the place's MausBot, shown in the sidebar or not, and the main Chief only where there is no MausBot. A Team Cloud member's MausBot is never the one. There is no second bot and no separate watcher: the routine engine (`server/routines.ts`) runs it like any other routine, on the desktop, headless and on a Cloud. ## Who owns it - **A new install.** Its first bot is MausBot, which is also its Chief. The routine, the brief, the add-a-key card and the intro's line about the day are MausBot's. - **An install that had a Chief before MausBot.** The Chief stays the Chief. The first time the server starts with MausBot there, the Chief's "Keep an eye on my day" becomes MausBot's. It is the same routine, moved, so everything the person set stays: on or paused, the instructions they edited, the checks' cursors and seen ids, and the day's run count. The brief's chat becomes MausBot's own conversation, and its next card says again what it does. Cards already posted stay where they were. - **The handover is safe to repeat.** It waits while a run of the routine is queued or working. `watch.json` records which bot each briefing routine was handed to, so it happens once: a routine the person later puts back on the Chief stays there. A restart between the steps finishes them at the next start, and a computer frozen by a move to My Cloud hands nothing over. - **One on at a time.** When a briefing routine lands on MausBot, handed over or arrived with it in a move, it is the one. Every other briefing routine is paused, never deleted, so the inbox is never read twice and a paused routine stays paused. - **Hidden from the sidebar.** MausBot keeps working: the brief is posted to its chat, and the notification and the first open of the day open that chat. ## What the person sees - **The brief.** One card a day in a fixed chat of MausBot's, edited in place, built with no AI. It exists only once it has something for the person (something that needs them, an important email or a meeting today); an empty brief is never posted. It opens on the first open of the day and after three hours away. Any other moment, it never takes the screen from the chat in use. Its first appearance says what it does and that the person can tell MausBot to stop or change it. Sections: 1. **Needs you**: emails waiting on a reply, failed or missed routines, meetings that clash, an app that can't be read ("Couldn't read Gmail · Reconnect Gmail in Connected apps"), a signed-out AI, a usage limit, a question a bot is waiting on; 2. **Your day**: today's meetings, with Join for an https meeting link; 3. **Important emails**: what the watch picked, each with a one-line why, **Draft a reply**, **Open in Gmail** and **Dismiss**; 4. **Routines**: other routines' results today. - **Meeting prep**: a card in the same chat when a meeting with other people is within four hours. - **The 10-minute reminder**: a card posted by the server, with no AI. - One notification per update that adds something that needs the person. Pausing or deleting the routine in Automations is the off switch: with it off there is no brief at all. Its row says "reads and drafts only" and "checked … , nothing new". ## The four routine upgrades, and the helper models 1. **Checks before the model.** A routine can name `checks`: `calendar` (the next 36 hours), `mail` (new inbox mail since the cursor) and `runs` (other routines' finished runs). They are plain code over one connected-apps session per tick, as the default account of each app, and only for apps the bot's own app switches let it read. Nothing new starts no turn and leaves no run, only "checked at". Reminders, clashes and Your day need no AI. Email triage and meeting prep go to **one** batched run, each item in a records block. The cursor moves only once that run's answer is kept, and items are deduplicated by id. A failed or misshapen read is never "nothing new": it keeps the cursor, backs off and shows its trouble. 2. **Nothing to report, structured.** A routine that delivers to the brief answers with one small JSON object: `{"quiet": true}`, or important emails and preps by item id. The server reads it. An answer it cannot read fails the run and is never posted, and its items wait for the next check. Every other routine keeps the NOTHING NEW convention in `server/automation-reports.ts`. 3. **Read-and-draft runs** (`access: "read-and-draft"`), in `server/read-and-draft.ts`. Everything is allow-only: - the run runs at Ask, and the server refuses every request in it outright, never as a card; - its OpenMausBot routes are conversation reads, its own results, the engine's hooks and the connected-apps relay; - through the relay it reads Gmail and Google Calendar, and may write one draft per thread, replying to that thread's sender, in a thread its checks handed it; - Gmail's and Calendar's answers reach it as records; - no web search, browser, computer, phone or other tools; no memory, recent work, team notes or skills in its prompt; nothing captured into memory; - its conversation stays out of recall, recent work, `list_threads` and Chief notices. The model work needs an engine whose every tool use reaches OpenMausBot's answerer (Claude today). On any other engine the watch prepares no meeting, says so in the brief, and still does what needs no AI. 5. **Helper models sort the inbox** (`server/host/inbox-triage.ts`). With a decision model set up (Settings → Decision and extraction: the person's own Cloudflare Workers AI or Jev key, or Cloud's included one), new mail is sorted with no AI turn, on every engine: Clairic reads each email (sender, the ask, any deadline or amount, whether it waits on a reply, what kind of mail it is) and Clef decides important, needs a reply, or skip, hearing the senders the person recently dismissed. Only important and needs-a-reply mail becomes rows; the why is built in plain code from what was read. The helper models can't act, so no fence is needed. If they fail, the mail waits for the next check. A full AI turn runs only for meeting prep, or when the person presses Draft a reply. Without any helper model, the AI run sorts mail as above, on Claude only. 4. **Deliver to the brief** (`deliver: "brief"`): results become brief rows, not chat lines of their own. ## Reliability, for every routine with checks - **Overlap.** While a run works, checks still run (reminders stay on time), but hand the AI nothing until it ends. - **Catch-up.** However late the computer wakes, missed checks merge into one, never a missed run. - **Backoff.** After a failed run the next waits 15 minutes, doubled each time, at most 4 hours, with jitter. The owner hears once per failure streak. - **Busy.** A run of checked items waits for a busy bot without a notice and never fails for being busy. - **Throttle.** At most 24 AI runs in any 24 hours; then items wait. - **Boot.** The first checks wait two minutes after start. - **Wake.** Only the checks' next on-time job (a reminder, a prep) keeps the desktop awake or wakes a sleeping Cloud. Plain mail checks run whenever the machine is awake anyway. - Every other routine keeps main's rules: one quick automatic retry, usage limits waited out, one notice per owner cause. ## State and privacy - `routine-checks.json`: per routine, cursors, judged ids, meetings prepped and reminded, and the items a run holds. Ids and times only. - `brief.json`: the brief's home chat and today's card, presence, the zone of record (from the person's device, so a Cloud is not stuck on UTC), the important rows by id, and recent dismissals with the sender's address. The senders and subjects it shows are read back from Gmail by id after a restart. - `watch.json`: that the default routine was made, so it is never made again, and the bot each briefing routine was handed to. - A card the server built carries `serverCard`. A bot can't edit it, and it replays into a turn only as records. Dismiss works only for the owner or an admin, only on the brief, checks thread ownership before reading a widget, and starts no turn. Recent dismissals go into the next triage as records. - A hosted team workspace or Team Cloud gets no watch and no brief. Presence is recorded for the owner only. - A personal Cloud that began with its first hour (`server/host/first-hour.ts`) also has a morning time, 8:00 in the person's zone: the day's brief is posted or refreshed then and pushed, with its first line saying what was done since the person was last here (emails sorted, reply drafts written, meetings prepared, from `value.json`), and only what was. A watch run still sorting the night's mail gets 20 minutes first, and a sleeping Cloud is woken at 7:50 for it (`nextWakeAt`). The very first morning push says it is the first brief. - An install that can't reach connected apps gets no watch, and so no brief, until it can. It checks once a minute, since a Cloud's access arrives after start. A scripted test install without the fake connected-apps service behaves as before. - Routines carry `checks`, `access` and `deliver` through Cloud moves and team backups. The watch moves to My Cloud with MausBot. A move carries MausBot when it has a routine the person set up, paused or changed, even if nobody has opened MausBot; the watch exactly as the server made it does not count. On My Cloud the arrived watch pauses My Cloud's own. The move freeze pauses the watch like any routine, so two homes never watch the same inbox. MausBot never moves into a team. ## Not in v1 - More than one account per app. - Phone push when the app is closed (there is no caller of the push relay yet). - Quiet hours. - A sweep of old run conversations. - A run against a real Google account: the Composio slugs and answer shapes follow its documentation and the fixtures in `server/testing/fixtures/`.