feat(ai): dagens plan, mails der giver mening, og svar på et spørgsmål

De tre sidste af de fem. Alle tre samme sted hen: det, man ellers selv
skulle sidde og gøre klokken syv om morgenen.

Dagens plan. Én besked om morgenen om det, der forfalder i dag, og det,
der er sprunget over. Tallene tælles i basen og gives til modellen som
kendsgerninger, den ikke må regne om — en plan, der siger fire opgaver,
hvor der er tre, er værre end ingen plan. Er der ingen model, står
tallene alene, og det er stadig det, man havde brug for at vide. Er der
hverken noget, der forfalder, eller noget, der er sprunget over, kommer
der ingen besked: en morgen uden noget at gøre er en god morgen, og en
besked om ingenting lærer folk at lade være med at åbne beskeder.

Timen er personens egen — klokken syv er syv forskellige steder — og
jobbet kører hver time frem for på et klokkeslæt, så en instans, der sov,
ikke springer dagen over. Flytter man timen, ryger dagens mærke, så man
kan se virkningen i dag i stedet for i morgen.

Mails, der giver mening. Opgaven hed, hvad mailen hed: "Anders Jensen:
SV: SV: Vedr. levering uge 12". Nok til at genkende, ikke nok til at
gøre noget ved. Nu skriver modellen den handling, mailen beder om, og
lader være, hvis den ikke beder om nogen. Ét kald pr. gennemløb frem for
ét pr. mail — femogtyve mails er ellers femogtyve gange ventetid — og
emnet bliver stående i beskrivelsen, så en misforstået mail stadig kan
læses. Falder modellen ud, hedder opgaven afsender og emne som før: en
model, der er nede, må ikke kunne stoppe posten.

Og svar på et spørgsmål. "Hvad lovede jeg Anders i august?" — svaret står
spredt over tre noter, og ingen af dem indeholder ordet "lovede".
Søgningen kræver, at alle ord optræder, hvilket er rigtigt for et
søgefelt og forkert for et spørgsmål, så kandidaterne hentes ord for ord
og de noter, flere ord rammer, kommer øverst. Modellen får kun dem: den
slår ikke selv noget op, så et svar kan ikke handle om nogen andens
noter. Og svaret bærer, hvad det står på — en model, der siger "det
gjorde du den 14.", er kun brugbar, hvis man kan slå op i det, den læste
det i.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
kristianwind
2026-09-08 15:05:36 +02:00
co-authored by Claude Opus 5
parent 40102d6038
commit 8139003b35
18 changed files with 1348 additions and 15 deletions
+123
View File
@@ -3568,6 +3568,115 @@ paths:
"404": { $ref: "#/components/responses/NotFound" }
"422": { $ref: "#/components/responses/Validation" }
/api/v1/ai/plan:
get:
tags: [integrations]
summary: Whether a morning plan is sent, and at what hour.
responses:
"200":
description: OK
content:
application/json:
schema: { $ref: "#/components/schemas/DailyPlanSettings" }
put:
tags: [integrations]
summary: Turn the morning plan on or off, or move the hour.
description: |
The hour is local to the person. Moving it clears the "already sent today"
mark, so somebody who moves the plan from 07 to 16 gets it this afternoon
rather than tomorrow — a setting whose effect you have to wait a day to
see is a setting nobody dares turn on.
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
enabled: { type: boolean }
hour: { type: integer, minimum: 0, maximum: 23 }
responses:
"200":
description: OK
content:
application/json:
schema: { $ref: "#/components/schemas/DailyPlanSettings" }
"422": { $ref: "#/components/responses/Validation" }
/api/v1/ai/plan/now:
post:
tags: [integrations]
summary: Send today's plan now, to whoever asks.
description: |
The counts come from the database and the sentence from the model, in that
order: a model that counted for itself would sometimes count wrong, and a
plan that says four tasks where there are three is worse than no plan.
With no model configured the counts stand on their own, which is what you
needed to know at seven in the morning anyway.
Nothing due and nothing overdue sends nothing. A morning with nothing to
do is a good morning, and a notification saying "there is nothing" teaches
people to stop opening notifications.
responses:
"200":
description: The plan, and whether it was sent.
content:
application/json:
schema:
type: object
properties:
plan: { type: string }
sent: { type: boolean }
/api/v1/ai/ask:
post:
tags: [integrations]
summary: Ask a question of your own notes and tasks.
description: |
Search finds what contains the words. This answers the question — "what
did I promise Anders in August?" — which is not the same: the answer is
spread over three notes and a task, and none of them contains the word
"promise".
Two halves, and the order is the whole of the safety in it. The database
finds the candidates with the search that already exists and that already
only sees what this person may see. The model is given those and nothing
else — it does not look anything up and cannot ask for more.
The answer carries what it rests on. A model that says "you did, on the
14th" is only useful if you can open the note it read that in.
requestBody:
required: true
content:
application/json:
schema:
type: object
required: [question]
properties:
question: { type: string }
responses:
"200":
description: |
The answer, and the passages it rests on — only those, not everything
that was looked at. An empty answer means nothing matched.
content:
application/json:
schema:
type: object
properties:
answer: { type: string }
sources:
type: array
items:
type: object
properties:
kind: { type: string, enum: [note, task] }
id: { type: string }
title: { type: string }
"409": { $ref: "#/components/responses/Conflict" }
"422": { $ref: "#/components/responses/Validation" }
"502": { $ref: "#/components/responses/Upstream" }
/api/v1/mcp:
post:
tags: [integrations]
@@ -4351,6 +4460,20 @@ components:
note_id: { type: string }
title: { type: string }
DailyPlanSettings:
type: object
description: >
One person's morning plan. Off by default — a notification at seven in the
morning that nobody asked for is not a help.
properties:
enabled: { type: boolean }
hour:
type: integer
description: Local to the person, because seven o'clock is seven different places.
last_sent:
type: string
description: The date it last went out, in that person's own timezone.
AISuggestion:
type: object
description: >