Something a model could not do, and so wrote a note about instead

Asked to remind somebody every Monday, a model looked down its tool list, found
notes_create described as "something worth having in a later conversation" and
memory_add beginning with the word Remember, wrote a note, and reported that it
had scheduled something. Every screen agreed with it. There was no scheduling
tool at all -- the near-misses were the only thing there was to reach for, and
nothing anywhere said the thing it was being asked for existed.

The seam had been left open on purpose: Schedule.origin has defined
ORIGIN_MODEL, with no writer, since scheduling shipped, and services/schedules.py
says in its first line that it holds what the routes *and the tools* both need.
This is the tool that was meant to go through it.

Four of them, and a thin layer: rule.validate is still the one total normaliser
the form and the compile share, schedules.create still writes the row and the
task chat together, and rule.describe still says what came out. A second dialect
for models would mean two definitions of "every other Tuesday" and one of them
going quietly wrong.

The result is that description, never "done". A schedule is invisible until it
fires, which may be days away, so the sentence in the reply is the only moment
anybody can check that Monday was read as Monday -- and the tool says so, in the
text the model reads back. The list badges the ones nobody typed.

Gated on schedule.use rather than a permission of its own: somebody who may set
one up by hand may say so to a model instead, and a second checkbox beside the
first would only ever be answered "the same as that one".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jaroslav Beneš
2026-08-06 10:28:05 +02:00
co-authored by Claude Opus 5
parent 09156230b3
commit 9761082fa1
7 changed files with 894 additions and 5 deletions
+48 -2
View File
@@ -988,7 +988,9 @@ BUILTIN: tuple[Fragment, ...] = (
"a summary of a long document. Correct one with notes_edit when it turns out "
"to be wrong, and remove it with notes_delete when it is no longer true — a "
"stale note is worse than no note. Anything short and durable about the "
"person themselves is a memory rather than a note."
"person themselves is a memory rather than a note, and anything that should "
"*happen* at a time — later, tomorrow, every week — is a schedule rather than "
"either, because a note does nothing at the time it describes."
),
),
Fragment(
@@ -1014,7 +1016,9 @@ BUILTIN: tuple[Fragment, ...] = (
"health details they have not asked you to keep. Anything longer than a "
"sentence, or about the work rather than about them, does not belong here. "
"When something you remembered turns out to be wrong, remove it with "
"memory_forget, quoting it in full, rather than adding a correction beside it."
"memory_forget, quoting it in full, rather than adding a correction beside it. "
"“Remind me to…” is not a memory: remembering that something should happen "
"does not make it happen, and a schedule does."
),
),
Fragment(
@@ -1216,6 +1220,48 @@ BUILTIN: tuple[Fragment, ...] = (
"recurring report so this one can say what changed."
),
),
Fragment(
key="tool.schedule",
label="Scheduling",
group=GROUP_TOOLS,
order=248,
families=("schedule",),
variables=("now",),
hint="Appears when the scheduling tools are offered. Most of this is the "
"rule vocabulary, which is also in the tool's own schema — repeated "
"here because the failure it prevents is expensive and silent: a "
"schedule that names the wrong day looks exactly like a working one on "
"every screen, and nobody finds out until it fires. The opening "
"sentence is the one that matters most, and it is here because of what "
"happened without it: asked to schedule something, a model wrote a "
"note, because a note was the nearest thing in its tool list and "
"nothing said scheduling existed.",
default=(
"- You can make things happen later. schedule_create sets up work that runs "
"because time has passed rather than because somebody asked just now — once, "
"or on a repeat. Use it whenever the person says *when*: “in ten minutes”, "
"“every Monday at noon”, “each morning”, “remind me”. Writing a note or a "
"memory instead makes nothing happen at the time; those are read only when "
"somebody goes looking. schedule_list shows what already exists, "
"schedule_update changes one and schedule_cancel stops it.\n"
"- It is {{now}} where this person is, and every time you write is read in "
"their zone. Work “in ten minutes” and “tomorrow at nine” out from that clock "
"rather than guessing.\n"
'- Use "every" for a plain timer and "at" for a calendar: "in ten minutes" is '
'{"every": {"minutes": 10}} with a start, and "every Monday at noon" is '
'{"at": {"weekdays": [0], "times": ["12:00"]}}. Monday is 0 — count the days '
"off rather than guessing, because naming the wrong one still looks like a "
"working schedule.\n"
"- Choose where the result goes. A reminder or a short daily fact goes to "
"messages; something to read and keep goes to a report; work that builds on "
"the previous run stays in its own chat.\n"
"- Write the instruction so it stands alone. It is read days later by a model "
"that was not here, with nobody to ask what you meant.\n"
"- Say the resulting timing back in your reply — the tool gives it to you in "
"words. That sentence is the only chance the person has to notice a mistake "
"before the first run."
),
),
Fragment(
key="context.knowledge_scope",
label="Which knowledge bases",