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
parent 09156230b3
commit 9761082fa1
7 changed files with 894 additions and 5 deletions
+17
View File
@@ -67,6 +67,11 @@ LABELS: dict[str, str] = {
"report_search": "Reports searched",
"report_get": "Report read",
"image_generate": "Image",
# Work set up to happen later.
"schedule_create": "Scheduled",
"schedule_list": "Schedules read",
"schedule_update": "Schedule changed",
"schedule_cancel": "Schedule stopped",
"memory_add": "Memory saved",
"memory_forget": "Memory removed",
"skill_get": "Skill read",
@@ -103,6 +108,10 @@ ICONS: dict[str, str] = {
"report_search": "search",
"report_get": "file-text",
"image_generate": "image",
"schedule_create": "clock",
"schedule_list": "clock",
"schedule_update": "clock",
"schedule_cancel": "stop-circle",
"memory_add": "star",
"memory_forget": "trash",
"skill_get": "sparkle",
@@ -144,6 +153,9 @@ ACTIONS: dict[str, str] = {
"report_search": "Search reports",
"report_get": "Read a report",
"image_generate": "Generate an image",
"schedule_create": "Set up a schedule",
"schedule_update": "Change a schedule",
"schedule_cancel": "Stop a schedule",
"memory_add": "Remember something",
"memory_forget": "Forget something",
"skill_get": "Read a skill",
@@ -176,6 +188,11 @@ DETAIL_KEYS: dict[str, str] = {
# it. Also what makes the box on the card editable: a prompt corrected
# before it runs is the commonest useful edit this feature will see.
"image_generate": "prompt",
# The instruction, not the timing. An approval card has room for one line,
# and the instruction is the part a person can read and correct -- the
# timing is an object, and the tool answers with it in words afterwards,
# which is where it is actually checkable.
"schedule_create": "instruction",
}