# Reminders

> How Fermix stores personal dates and reminds you about them: storing a date, reminder plans, delivery and retry, snoozing, cancelling, listing, and the boundary against scheduled jobs.

Tell Fermix "Sarah's birthday is September 14" or "remind me Friday to submit the report" in any chat, and it stores the date and confirms the exact plan it will follow: which reminders it will send, when, and where. Reminders are delivered to the background channel configured under `[fermix_core.jobs] default_delivery_target`, not to the conversation you happened to be in when you asked. When that key is not set, Fermix derives your inbox from the first channel configured with an explicit owner id — Telegram, then Signal, then WhatsApp — and the confirmation both names the channel and says the choice was derived, so you can move it by asking. Storing a date fails rather than guessing. If `default_delivery_mode` in that same section is set to `none`, `origin`, or `local`, the store is refused before any inbox is derived: those modes switch background delivery off, and a reminder needs the mode set to `channel` or left unset. A configured target that cannot carry a reminder — a `cli` platform, or one with no destination — fails there rather than falling through to derivation. And with no target configured at all, it fails when there is also no owner-configured channel to derive from, with setup guidance naming both remedies (see [configuration](/docs/configuration)). Fermix never quietly promises a reminder that would arrive nowhere, and never falls back to the chat you are in.

No model runs when a reminder fires. Fermix renders the message from the stored date and sends it, so a reminder cannot be reworded, embellished, or lost to a provider outage. That is also the line between a reminder and a [scheduled job](/docs/scheduled-jobs), which runs a real agent turn — see [reminders or a scheduled job](#reminders-or-a-scheduled-job) below.

## Storing a date

Any ordinary message that states a date is enough; there is no command to learn. The agent stores it and replies with what was actually persisted — the stored date named absolutely with its weekday (never just "tomorrow", so a late-night request can't silently land on the wrong day), the recurrence, every planned reminder time, and the channel they will arrive on. And because "tomorrow" said just after midnight is genuinely ambiguous, a small-hours request for "tomorrow morning" gets one question naming both candidate days before anything is stored.

A stored date is either **one-time** (an appointment, a deadline, a one-off "remind me on Friday") or **yearly** (a birthday or anniversary). A yearly date stays one stored event with one id forever; its next occurrence is computed with calendar arithmetic, not by adding 365 days, so it does not drift.

Fermix reads your timezone from `[fermix_core.personalization] timezone` unless you name an IANA zone (the standard timezone label, such as `America/New_York`) yourself. A missing or invalid timezone fails the store rather than assuming UTC. A local time that is ambiguous or does not exist because of a daylight-saving change is refused with a typed error, and Fermix asks which instant you meant instead of picking one.

A yearly February 29 date needs a decision Fermix will not make for you: it asks whether you want the reminder on February 28 or March 1 in non-leap years, and stores your answer with the event.

## Reminder plans

A plan is finite by construction — it is never a nag loop that repeats until you acknowledge it. What you get by default depends on the kind of date and whether you gave a time:

| Date | Default reminders |
|------|-------------------|
| Birthday or anniversary | 7 days before, and on the day, both at 09:00 local time |
| Appointment, deadline, or event with a time | 24 hours before, and 1 hour before |
| Appointment, deadline, or event on a date only | 7 days before, 1 day before, and on the day, at 09:00 local time |
| An explicit "remind me at 4pm on the 16th" | Exactly that one reminder, at that time |
| An explicit "remind me on Friday", with no time | On the day, at 09:00 local time |

Ask for something else and your plan replaces the defaults rather than adding to them, up to 10 rules per date. Lead rules that have already passed are skipped, and the confirmation says so — store a birthday three days out and Fermix tells you the week-before reminder is not scheduled. A combination with no default (a birthday given as a precise time, for example) makes Fermix ask you for the plan rather than inventing one. You can also store a date with no reminders at all, when you only want Fermix to know it.

## Where reminders arrive

Reminders use the same destination scheduled jobs use, `[fermix_core.jobs] default_delivery_target`: Telegram, Slack, Discord, Signal, or WhatsApp. A `cli` platform is a valid target for a scheduled job but is refused for a reminder — a reminder exists to reach you when you are not looking at a terminal.

```toml
[fermix_core.jobs.default_delivery_target]
platform = "telegram"
chat_id = "123456789"
```

An explicitly configured target always wins. Derivation only fills in when the key is absent, and only from channels where your owner id is itself a sendable destination — Telegram, Signal, or WhatsApp, never Discord or Slack, where a bare user id is not a channel. The confirmation's "derived" note is the tell that Fermix chose for you.

The target is copied onto each date when it is stored, whether configured or derived. Changing the config afterward does not retarget dates you already stored, exactly as it does not retarget existing jobs; ask Fermix to move a specific event to the current default and it rebinds that event explicitly. It never falls back to the chat you are in.

## When a send fails

A failed send is retried durably on the same channel, five attempts in all: at the due time, then 1 minute, 5 minutes, 15 minutes, and 60 minutes later. A rate-limit hint from the platform is honored, and every attempt is clamped by that reminder's validity window, so a reminder is never delivered so late that it has stopped meaning anything. After the last attempt the reminder fails visibly and shows up with its error when you ask Fermix to list your dates.

Fermix never fails over to a different channel. A reminder promised to Telegram arrives on Telegram or not at all — a delivery that quietly relocated would be indistinguishable from one that worked.

If an earlier reminder for the same date is still failing when a later one comes due, the earlier one is superseded. A channel that recovers after an outage delivers "today is the day", not "one week before" and "today" arriving together.

## The follow-up check-in

Store a date that is more than logistics — a birthday, an anniversary, an occasion you might want help acting on — and Fermix may mark it for a follow-up check-in. That judgment is the agent's own, made once when the date is stored, never at delivery time, and it is not silent: the confirmation names the check-in when it is set, and asking Fermix to add or drop it for any date is an ordinary edit.

When a reminder for a marked date is delivered, the reminder itself arrives exactly as rendered, and then a separate short agent turn runs. It can offer to help — draft a message, recall something relevant you once told Fermix, ask one focused question — or say nothing at all when there is nothing worth adding. It sends at most one short message into the same conversation as the reminder (the delivery rail enforces that cap; it is not left to the model's judgment), it cannot edit or cancel your dates (the editing tools refuse every background run), and it writes a one-line note into that conversation's memory, so replying "yes, help me with that" lands with context.

The check-in is a courtesy, not a promise. It runs only after the reminder has already been delivered, so a model outage, a slow response, or a daemon restart can never cost you the reminder — the worst any failure can do is skip the check-in, and a skipped check-in is silent. There is no global setting to turn it on or off; the per-date flag, visible in the confirmation and changeable by asking, is the whole control surface.

## Snoozing a reminder

Reply "snooze that for two hours" right after a reminder arrives and Fermix defers it. It resolves what "that" means on its own: the most recent reminder it delivered into that exact conversation within the last 24 hours. Nothing is guessed across chats, and if there is nothing to resolve, Fermix asks which date you mean. You can also name a specific reminder by its id.

The new time is either a duration (minutes, hours, or days) or a specific date and time; both are capped at 90 days out. A snooze that would land at or after the event itself needs your explicit confirmation first, because a reminder arriving after the thing it warns about is a different promise from the one you made.

One snooze is active per reminder. Snoozing again with a new time replaces the first rather than stacking a second, and repeating the identical request changes nothing. A snooze never edits the stored plan, and the reminder that already arrived stays in your history.

## Cancelling

"Cancel that", right after a reminder, cancels the whole date behind it — resolved the same way a snooze is, from the last reminder delivered into that conversation within 24 hours. The confirmation names the date and its recurrence, so cancelling a yearly birthday reads as yearly: every future occurrence goes with it, not just the next one.

Cancelling is soft. Unsent reminders are dropped, and the record of reminders already delivered is kept, so the history of what Fermix actually sent you stays readable.

A reminder that is mid-send blocks both a cancel and an edit of that date: a message already handed to a channel cannot be recalled, so Fermix refuses with a typed error and asks you to retry in a moment rather than reporting that it withdrew something you have already received.

Changing a stored date takes an explicit step. A change to the date itself is refused unless the call quotes your own words directing it — a code-enforced floor, and a mechanical one: it checks that a quote is present and short, never what the quote says. So whether the agent quotes you or stops to ask when you merely restate a date under an already-stored name ("Sarah's birthday is June 10" when a different date is stored) is its own judgment applied through its instructions; it is told to ask which you meant — the same event to correct, or a different person who needs their own entry. A change you did ask for is applied in one step, and its confirmation states what the date was before as well as what it is now. Storing a new date likewise lists your other entries of the same kind in its confirmation, so an accidental near-duplicate under a similar name is visible the moment it is created.

## Listing what is stored

Ask what is coming up and Fermix lists active dates from today onward. Ask for history, or name a date range, and past and cancelled dates come back too. Each entry carries the next occurrence, the planned reminders, the next one due, and the last delivery result including any error — which is how you find a reminder that has been failing.

That listing covers dates stored in Fermix and nothing else. An answer about your schedule is wider: the agent is instructed to consult every calendar surface you have connected — your stored dates alongside a [calendar plugin](/docs/plugins) such as Google Calendar — to attribute each entry to where it came from, and to say when a source was not consulted or could not be reached. That is the agent following its instructions, not a gate that blocks a one-sided answer.

Fermix does not sync with a connected calendar, in either direction. Creating a Google Calendar event does not create a Fermix reminder, and a stored date is not written to your calendar — a mirror that went stale would be worse than two sources you can tell apart. Before storing a date your calendar likely already tracks, the agent is told to ask whether you want Fermix reminders for it too, so two systems do not remind you about the same thing.

## Reminders or a scheduled job?

Both fire in the future, and Fermix picks between them by what has to happen when the time comes.

- **A reminder** when the only future action is notifying you. The text is rendered from what you stored, no model call is made, and delivery is the whole job. "Remind me about my dentist appointment at 3" is a reminder.
- **A [scheduled job](/docs/scheduled-jobs)** when the future run has to reason, use tools, read something that changes, or produce a digest. "Check flight prices tomorrow and tell me the cheapest" is a job, because nothing useful can be written down today.

Say either in plain language; you do not choose the mechanism, and Fermix tells you which one it used.

## Who can use it

Storing, changing, cancelling, and snoozing dates are available only on an attended, top-level owner turn: an interactive chat or CLI turn you typed, or a live voice call. Listing has one deliberate exception — a scheduled job you created can read your stored dates, so a daily digest job can include upcoming reminders. Guests, background work, delegated sub-agents, and coding-run continuations neither see any of these tools nor can call them by name, and scheduled jobs see only the listing tool. The rule is enforced twice — once when the tool list is built for the model, and again when a call is dispatched — so a call arriving from a context that should not have it is refused rather than executed. See [ingress and trust](/docs/ingress-and-trust).

Per-tool parameters and failure tags are on the [tool reference](/docs/tool-reference).
