2026-10-23 14:47:04 +02:00
|
|
|
|
# ADR 0021: A private instance: approved sign-ups and an assistant the operator grants
|
|
|
|
|
|
|
docs(adr): ADR 0021 accepted, the assistant's boundaries (D7–D30)
The developer's decisions of 25 Oct, reviewing ADR 0021 whole:
- What an assistant may see and do (D7–D12): the scope of each question
(the parts ticked, the studyset, its tree, the library), looked up
through read-only tools the app answers on the device; private
studysets out of a wider scope unless switched on, and a warning
whenever one's content would go to a remote model, Lumo included, as
no provider keeps a question confidential while its model answers;
changes only as drafts; progress never; text first, an image when
ticked or asked for.
- What it keeps, does and where it lives (D13–D18): conversations kept
sealed with the person's own key; four features (questions about what
is open, cards from text, explaining a miss, checking a written
answer); grants and limits in halkyon_base, the adapters in a package
of their own (halkyon_llm, BSD-3-Clause); the proposal's points 4–8
and 10 as written; the warning once per studyset and assistant; built
for v0.21.0.
- Sign-ups and operators (D19–D26): SIGN_UP open, approval or closed;
the first operator by SQL, others named in the app; suspending an
approved account; a wait screen with a matching code the operator
checks with the person; 14 days, 10 waiting.
- What people are told and what never goes (D27–D30): the app and a
privacy page of each instance's own; others' posts only with their
author's switch, a copy's licence being its agreement; an opaque ID
per person for the provider.
ADR 0022 and Learn's AGENTS.md now point to it as accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 13:36:56 +01:00
|
|
|
|
- **Status:** accepted 25 Oct 2026, to be built for v0.21.0 (D18). Decided by the
|
|
|
|
|
|
developer: D1–D6 on 23 Oct; on 25 Oct what an assistant may see and do (D7–D12), what it
|
|
|
|
|
|
keeps and does, where it lives, the proposal's points 4–8 and 10, how often it warns and
|
|
|
|
|
|
when it is built (D13–D18), who signs up and who operates (D19–D22), waiting accounts
|
2026-10-25 16:52:21 +01:00
|
|
|
|
(D23–D26), what people are told and what never goes (D27–D30), how the first step is
|
feat(learn): conversations with assistants, kept sealed (ADR 0021, step 3)
The first part of step 3, decided as D47 to D52 in ADR 0021: where a
conversation shows (a sheet over the screen), where kept ones are found
(the field), the scope's chip and that it starts with only what is
ticked, how conversations are kept, and what a device that can't seal
does.
Two synced tables: assistant_conversation (its title, assistant and
scope) and assistant_turn (one question and everything up to its answer,
never changed once written, ADR 0001, rule 2), so two devices continuing
a conversation offline lose nothing. SyncConversationGateway seals every
row with the person's key, a turn bound to its conversation, and reads
no row that isn't sealed: a device that can't seal keeps nothing (D52,
ConversationNotKept). Deleting one blanks it and its turns first (ADR
0002, rule 2). A turn keeps every message a follow-up sends back (tool
calls and results, the providers' own blocks), but no image, only that
one was sent.
The instance's privacy page says conversations are kept, encrypted, and
what the instance sees of them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 19:48:00 +01:00
|
|
|
|
built (D31–D34), the second (D35–D46) and the third (D47–).
|
2026-10-23 15:08:40 +02:00
|
|
|
|
- **Builds on:** ADR 0016 (the register), ADR 0019 (private studysets), ADR 0020
|
|
|
|
|
|
(SimpleLogin), ADR 0022 (the hand-off and the connector gone).
|
2026-10-23 14:47:04 +02:00
|
|
|
|
- **Changes:** the rule of 10 Oct 2026 that Halkyon calls no language model with an API
|
|
|
|
|
|
key, for an instance whose operator opts in.
|
|
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
The developer may stop the public instance and run halkyon.li for themselves and their
|
|
|
|
|
|
close family instead. They don't know in advance which addresses their family will sign in
|
|
|
|
|
|
with, and with SimpleLogin (ADR 0020) the instance keeps no addresses anyway.
|
|
|
|
|
|
|
|
|
|
|
|
On 10 Oct the developer ruled out API keys for language models: on a public instance anyone
|
|
|
|
|
|
could drive up the bill, and each person should decide what a model sees. Assistants came
|
|
|
|
|
|
through people's own subscriptions instead: the connector (ADR 0006) and the hand-off to
|
2026-10-23 15:08:40 +02:00
|
|
|
|
Claude or Lumo, both gone since 23 Oct (ADR 0022). A family instance whose operator
|
|
|
|
|
|
approves every account takes away the first reason; the second holds if the app shows
|
|
|
|
|
|
what it sends.
|
|
|
|
|
|
|
|
|
|
|
|
People in one family may prefer different providers (the developer: "I might use myself
|
|
|
|
|
|
the Claude API while other might want to use the OpenAI API, then one other the Proton
|
|
|
|
|
|
Lumo API"). A plan for Claude's or ChatGPT's apps is no API access: the APIs are billed
|
|
|
|
|
|
apart, by their providers' consoles.
|
2026-10-23 14:47:04 +02:00
|
|
|
|
|
|
|
|
|
|
Two protocols reach nearly every provider: Anthropic's Messages API (Claude), and the
|
|
|
|
|
|
OpenAI-compatible chat completions (OpenAI, Mistral, Google Gemini's compatibility
|
|
|
|
|
|
endpoint, OpenRouter, local models through Ollama, llama.cpp or vLLM). Proton announced a
|
|
|
|
|
|
Lumo API for autumn or winter 2026 without publishing its format; community projects
|
docs(adr): ADR 0021 accepted, the assistant's boundaries (D7–D30)
The developer's decisions of 25 Oct, reviewing ADR 0021 whole:
- What an assistant may see and do (D7–D12): the scope of each question
(the parts ticked, the studyset, its tree, the library), looked up
through read-only tools the app answers on the device; private
studysets out of a wider scope unless switched on, and a warning
whenever one's content would go to a remote model, Lumo included, as
no provider keeps a question confidential while its model answers;
changes only as drafts; progress never; text first, an image when
ticked or asked for.
- What it keeps, does and where it lives (D13–D18): conversations kept
sealed with the person's own key; four features (questions about what
is open, cards from text, explaining a miss, checking a written
answer); grants and limits in halkyon_base, the adapters in a package
of their own (halkyon_llm, BSD-3-Clause); the proposal's points 4–8
and 10 as written; the warning once per studyset and assistant; built
for v0.21.0.
- Sign-ups and operators (D19–D26): SIGN_UP open, approval or closed;
the first operator by SQL, others named in the app; suspending an
approved account; a wait screen with a matching code the operator
checks with the person; 14 days, 10 waiting.
- What people are told and what never goes (D27–D30): the app and a
privacy page of each instance's own; others' posts only with their
author's switch, a copy's licence being its agreement; an opaque ID
per person for the provider.
ADR 0022 and Learn's AGENTS.md now point to it as accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 13:36:56 +01:00
|
|
|
|
(lumo-tamer, an unofficial tracker) show an OpenAI-compatible interface. Still none by
|
|
|
|
|
|
25 Oct, but for the unofficial tracker's "early access".
|
|
|
|
|
|
|
|
|
|
|
|
No remote provider keeps what it is asked confidential while its model answers: the model
|
|
|
|
|
|
reads plain text. Lumo too: its prompts are encrypted beyond TLS on their way to Proton's
|
|
|
|
|
|
servers, decrypted there to be answered and, Proton says, discarded; its zero-access
|
|
|
|
|
|
encryption covers the chats it stores, which an API call doesn't make. What keeps a
|
|
|
|
|
|
private studyset private there is a promise, not cryptography. Only a model on the
|
|
|
|
|
|
person's own machine does without one.
|
2026-10-23 14:47:04 +02:00
|
|
|
|
|
|
|
|
|
|
## Decisions (23 Oct 2026, the developer's)
|
|
|
|
|
|
|
|
|
|
|
|
- **D1 Sign-ups wait for the operator's approval** (over invitation links, which were
|
|
|
|
|
|
recommended, and a sign-up window): anyone can sign up; nothing works until the operator
|
|
|
|
|
|
approves them.
|
|
|
|
|
|
- **D2 The assistant runs on the instance's key, granted per person** (recommended, over
|
|
|
|
|
|
each person's own key and both): the operator pays and switches it on for whom they
|
|
|
|
|
|
choose.
|
|
|
|
|
|
- **D3 Individual limits and statistics** (the developer: "so I can see after the fact who
|
|
|
|
|
|
potentially drove up the bill"): each person's use is limited and counted, and the
|
|
|
|
|
|
operator sees it per person.
|
2026-10-23 15:08:40 +02:00
|
|
|
|
- **D4 Several providers, all on the operator's keys** (over personal keys alone, and over
|
|
|
|
|
|
both, which was recommended): the operator sets up the assistants the instance offers
|
|
|
|
|
|
and grants each person one or more.
|
|
|
|
|
|
- **D5 Personal keys stay on the person's devices** (recommended, over keeping them on the
|
|
|
|
|
|
instance): the app calls the provider itself, and the instance sees neither key nor
|
|
|
|
|
|
text.
|
|
|
|
|
|
- **D6 Personal keys only where the operator allows them** (over every instance, which was
|
|
|
|
|
|
recommended): an instance setting, off unless switched on.
|
2026-10-23 14:47:04 +02:00
|
|
|
|
|
docs(adr): ADR 0021 accepted, the assistant's boundaries (D7–D30)
The developer's decisions of 25 Oct, reviewing ADR 0021 whole:
- What an assistant may see and do (D7–D12): the scope of each question
(the parts ticked, the studyset, its tree, the library), looked up
through read-only tools the app answers on the device; private
studysets out of a wider scope unless switched on, and a warning
whenever one's content would go to a remote model, Lumo included, as
no provider keeps a question confidential while its model answers;
changes only as drafts; progress never; text first, an image when
ticked or asked for.
- What it keeps, does and where it lives (D13–D18): conversations kept
sealed with the person's own key; four features (questions about what
is open, cards from text, explaining a miss, checking a written
answer); grants and limits in halkyon_base, the adapters in a package
of their own (halkyon_llm, BSD-3-Clause); the proposal's points 4–8
and 10 as written; the warning once per studyset and assistant; built
for v0.21.0.
- Sign-ups and operators (D19–D26): SIGN_UP open, approval or closed;
the first operator by SQL, others named in the app; suspending an
approved account; a wait screen with a matching code the operator
checks with the person; 14 days, 10 waiting.
- What people are told and what never goes (D27–D30): the app and a
privacy page of each instance's own; others' posts only with their
author's switch, a copy's licence being its agreement; an opaque ID
per person for the provider.
ADR 0022 and Learn's AGENTS.md now point to it as accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 13:36:56 +01:00
|
|
|
|
On 25 Oct, what an assistant may see and do (the developer: "Only what is chosen, within a
|
|
|
|
|
|
studyset, within a tree of studysets, and a complete library (maybe even an option
|
|
|
|
|
|
including/excluding private studysets?)"):
|
|
|
|
|
|
|
|
|
|
|
|
- **D7 The person chooses the scope of each question:** the parts they tick (the field's
|
|
|
|
|
|
chips, as for a web search), this studyset (the one open, with everything inside it, as
|
|
|
|
|
|
studying it covers), its tree (from its top studyset down), or their library (decided
|
|
|
|
|
|
over a scope for a studyset without its topics). Beyond the parts ticked, nothing is
|
|
|
|
|
|
put into the request whole, as a library outgrows any model's context: the model looks
|
|
|
|
|
|
things up through tools the app answers on the device, read-only and within the scope,
|
|
|
|
|
|
each lookup shown in the conversation and counted in the person's limits.
|
|
|
|
|
|
- **D8 Private studysets stay out of a wider scope unless switched on** (recommended, over
|
|
|
|
|
|
taking them in with the warning, and over never sending them): beside the scope,
|
|
|
|
|
|
"Include private studysets", off for every question.
|
|
|
|
|
|
- **D9 A warning whenever a private studyset's content would go to a remote model**
|
|
|
|
|
|
(recommended): it leaves end-to-end encryption; the warning names the provider and links
|
|
|
|
|
|
its terms. The same for every remote provider, Lumo included (see *Context*), not
|
|
|
|
|
|
graded by promises the app can't verify, and with no exception for an address on the
|
|
|
|
|
|
local network, which may be a company's or a shared one; none for a model at a loopback
|
|
|
|
|
|
address, on the device itself. Shown for parts ticked as for the switch of D8.
|
|
|
|
|
|
- **D10 Changes only as drafts** (recommended, over answers alone and over writes with
|
|
|
|
|
|
Undo): the model proposes cards, notes or edits, which open in the composer or editor;
|
|
|
|
|
|
nothing is saved until the person accepts it, so neither a wrong answer nor
|
|
|
|
|
|
instructions hidden in a copied studyset (prompt injection) change the library.
|
|
|
|
|
|
- **D11 Progress never goes along** (over a chip for it, which was recommended): no
|
|
|
|
|
|
reviews, ratings, statistics or study time, in any scope.
|
|
|
|
|
|
- **D12 Text first, images when ticked or asked for** (the developer: "Can't it generally
|
|
|
|
|
|
be text, only images if necessary (e.g. graphs within a PDF)?"; then the recommended
|
|
|
|
|
|
way): text by default, a PDF's as PDFium reads it; where a part in scope holds an image
|
|
|
|
|
|
(a card's picture, a PDF page with figures), its image is a chip of its own, off; and
|
|
|
|
|
|
the model may ask for one, which the person approves each time. Only for an assistant
|
|
|
|
|
|
that reads images. The app can't tell by itself when an image is needed: a graph is
|
|
|
|
|
|
often drawn as lines, not stored as a picture.
|
|
|
|
|
|
- **D13 Conversations are kept, sealed** (recommended, over this device only and over
|
|
|
|
|
|
none): in a synced table sealed with the person's own key (ADR 0019, as their settings
|
|
|
|
|
|
and tags), so they reach all their devices and the instance can't read them, as Proton
|
|
|
|
|
|
can't read Lumo's stored chats; kept until the person deletes one.
|
|
|
|
|
|
- **D14 The first version does four things:** answers questions about what is open, in
|
|
|
|
|
|
the field on Home, in the Library, on a studyset and in a session (D7's scopes); makes
|
|
|
|
|
|
cards from text (a paragraph, a note, a PDF page) as drafts (D10); explains, in a
|
|
|
|
|
|
session after Bad, why the answer is what it is, from the card's own parts; and checks a
|
|
|
|
|
|
written answer or a sentence written in the studyset's language, saying what is wrong
|
|
|
|
|
|
and why, as feedback, changing nothing.
|
|
|
|
|
|
- **D15 The module and a package of its own** (recommended, over Learn alone first):
|
|
|
|
|
|
grants, limits, statistics and the forwarding are halkyon_base's, the register's, one
|
|
|
|
|
|
per instance as accounts are, so a person's grant and limits hold in every service of
|
|
|
|
|
|
the instance; the two adapters (5) are `halkyon_llm`, a pure Dart package, BSD-3-Clause
|
|
|
|
|
|
as `halkyon_oidc` is, in the monorepo, its publishing to pub.dev asked first; the field,
|
|
|
|
|
|
the scopes and their tools are Learn's.
|
|
|
|
|
|
- **D16 Points 4 to 8 and 10 of the proposal stand as written** (recommended, over going
|
|
|
|
|
|
through them one by one); what comes up while building is put to the developer.
|
|
|
|
|
|
- **D17 The warning of D9 is asked once per studyset and assistant** (recommended, over
|
|
|
|
|
|
once per session and every time), as explaining a miss and checking an answer go out
|
|
|
|
|
|
once per card: the answer is kept in the person's sealed settings, the studyset's
|
|
|
|
|
|
privacy dialog shows it with Take back, and the assistant's button in that studyset
|
|
|
|
|
|
carries a mark while it holds.
|
|
|
|
|
|
- **D18 Built for v0.21.0** (over shipping the batch held for it first, which was
|
|
|
|
|
|
recommended, and over later): the batch on `feat/remove-github` (GitHub's removal,
|
|
|
|
|
|
build 24) waits for it.
|
|
|
|
|
|
- **D19 `SIGN_UP` takes three values** (recommended, over approval on or off alone and
|
|
|
|
|
|
over invitation links now): `open`, `approval`, `closed` (point 1).
|
|
|
|
|
|
- **D20 The first operator by SQL** (recommended, over a one-time setup code, over a
|
|
|
|
|
|
handle in `deploy/.env` and over the instance's first account): the operator signs up
|
|
|
|
|
|
in the app, then, on the server, one statement written here makes that account an
|
|
|
|
|
|
operator and approves it. No code hands out the role, so nothing is there for a
|
|
|
|
|
|
stranger to guess; whoever runs an instance reaches its database anyway.
|
|
|
|
|
|
- **D21 Further operators are named in the app** (recommended, over SQL for each): an
|
|
|
|
|
|
operator names another by handle and can take it back; the last operator can't be
|
|
|
|
|
|
removed.
|
|
|
|
|
|
- **D22 An operator can suspend an approved account** (recommended, over deleting it too
|
|
|
|
|
|
and over grants alone): its sessions end and it waits again, nothing syncing, its data
|
|
|
|
|
|
kept, until an operator approves it anew. Deleting stays the person's own act, or the
|
|
|
|
|
|
operator's SQL.
|
|
|
|
|
|
- **D23 A waiting account shows a wait screen only** (recommended, over using the app on
|
|
|
|
|
|
the device until approved): it says the account waits for the operator, and offers to
|
|
|
|
|
|
delete it; nothing syncs or uploads, so a refusal loses nothing.
|
|
|
|
|
|
- **D24 A matching code tells the operator who waits** (recommended, over an
|
|
|
|
|
|
introduction line and over the handle alone): the wait screen shows a short code of
|
|
|
|
|
|
four words, and the operator sees the same code beside the handle, asking the person
|
|
|
|
|
|
(by phone, in person) what theirs says; a stranger who took a family member's handle
|
|
|
|
|
|
can't know it.
|
|
|
|
|
|
- **D25 The limits stand as proposed** (recommended, over 7 days and over 30): deleted
|
|
|
|
|
|
after 14 days unapproved, at most 10 waiting at once, sign-ups per network limited as
|
|
|
|
|
|
today's, a badge in the operator's app as the only notice.
|
|
|
|
|
|
- **D26 Someone refused may sign up again and wait again** (recommended, over refusing
|
|
|
|
|
|
their SimpleLogin identity for 30 days): nothing about them is kept; the cap and the
|
|
|
|
|
|
network limits hold strangers back.
|
|
|
|
|
|
- **D27 Each instance says what its assistants do, in the app and on a page of its own**
|
|
|
|
|
|
(over the app alone, which was recommended, and over the website's page alone, which
|
|
|
|
|
|
describes learn.halkyon.eu): the consent sheet when a grant is first used, the same
|
|
|
|
|
|
facts in Settings › Assistant at any time, and `/privacy` on the instance's web server,
|
|
|
|
|
|
made from its settings in English and German as the profile pages are, readable before
|
|
|
|
|
|
signing up (point 9).
|
|
|
|
|
|
- **D28 Others' posts go to a model only with their author's agreement** (the developer:
|
|
|
|
|
|
"not to send the content from others without their explicit (direct or indirect)
|
|
|
|
|
|
agreement to LLM providers"; recommended, over a licence for one's posts and over
|
|
|
|
|
|
never): a switch in the account's settings, "Others may send my posts to their AI
|
|
|
|
|
|
assistant", off unless switched on and shown on the profile; while it is on, their
|
|
|
|
|
|
posts in discussions and feedback threads are chips like the others, off. The rule
|
|
|
|
|
|
binds what Halkyon sends on a person's behalf: someone who copies text into a model by
|
|
|
|
|
|
hand acts on their own, and the app doesn't try to stop it. No standard says this yet
|
|
|
|
|
|
(25 Oct): the IETF's AI preferences are drafts naming training and search, not a
|
|
|
|
|
|
model's answer; Creative Commons' signals are still being worked out. Should one come,
|
|
|
|
|
|
the switch can be expressed in it.
|
|
|
|
|
|
- **D29 A copy's licence is its agreement** (recommended, over an author's switch per
|
|
|
|
|
|
studyset): publishing takes a licence that allows passing on (ADR 0005), so a copy is
|
|
|
|
|
|
the person's own to send.
|
|
|
|
|
|
- **D30 The provider learns an opaque ID per person** (recommended, over nothing): with the
|
|
|
|
|
|
operator's key, each request carries an ID the instance derives from the account with a
|
2026-10-25 17:38:53 +01:00
|
|
|
|
key of its own (OpenAI's `safety_identifier`, OpenRouter's `user`, Anthropic's
|
|
|
|
|
|
`metadata.user_id`; servers with no such field get none), never the handle, so
|
docs(adr): ADR 0021 accepted, the assistant's boundaries (D7–D30)
The developer's decisions of 25 Oct, reviewing ADR 0021 whole:
- What an assistant may see and do (D7–D12): the scope of each question
(the parts ticked, the studyset, its tree, the library), looked up
through read-only tools the app answers on the device; private
studysets out of a wider scope unless switched on, and a warning
whenever one's content would go to a remote model, Lumo included, as
no provider keeps a question confidential while its model answers;
changes only as drafts; progress never; text first, an image when
ticked or asked for.
- What it keeps, does and where it lives (D13–D18): conversations kept
sealed with the person's own key; four features (questions about what
is open, cards from text, explaining a miss, checking a written
answer); grants and limits in halkyon_base, the adapters in a package
of their own (halkyon_llm, BSD-3-Clause); the proposal's points 4–8
and 10 as written; the warning once per studyset and assistant; built
for v0.21.0.
- Sign-ups and operators (D19–D26): SIGN_UP open, approval or closed;
the first operator by SQL, others named in the app; suspending an
approved account; a wait screen with a matching code the operator
checks with the person; 14 days, 10 waiting.
- What people are told and what never goes (D27–D30): the app and a
privacy page of each instance's own; others' posts only with their
author's switch, a copy's licence being its agreement; an opaque ID
per person for the provider.
ADR 0022 and Learn's AGENTS.md now point to it as accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 13:36:56 +01:00
|
|
|
|
the provider can act against one person's abuse without blocking the operator's key,
|
|
|
|
|
|
and can't tell who it is.
|
|
|
|
|
|
|
2026-10-25 14:28:47 +01:00
|
|
|
|
On 25 Oct, how the first step is built (sign-ups and operators):
|
|
|
|
|
|
|
|
|
|
|
|
- **D31 A waiting account has no session** (recommended, over a session with a `waiting`
|
|
|
|
|
|
scope that every endpoint, the sync and the uploads would have to refuse): every
|
|
|
|
|
|
session on every service is made in one place (`issueSession`), which refuses while
|
|
|
|
|
|
the account waits and hands the device a waiting pass instead (a random secret, kept as
|
|
|
|
|
|
its hash) with the matching code. The pass opens only the wait screen's calls: whether
|
2026-10-25 15:04:21 +01:00
|
|
|
|
the account still waits, deleting the account, and forgetting the pass. Once approved,
|
|
|
|
|
|
the wait screen says so, the pass going with that answer, and the person signs in once
|
|
|
|
|
|
more as they did before (the developer's choice, recommended, over the pass handing
|
|
|
|
|
|
over a session): that sign-in opens the keys and, after a password's sign-up, sets up
|
|
|
|
|
|
the authenticator as every sign-in does, and a pass is never worth a session. The pass
|
|
|
|
|
|
deletes only a new account that was never approved: a suspended one keeps its data,
|
|
|
|
|
|
and deleting it takes its owner's password and a code, as ADR 0017 has every deletion.
|
|
|
|
|
|
A pass holds 30 days, at most five per account. A member asks the register before it
|
|
|
|
|
|
makes a session, as it asks everything else about accounts (ADR 0016).
|
2026-10-25 14:28:47 +01:00
|
|
|
|
- **D32 The operator role is a scope**, `operator`, on the account and its sessions, as
|
|
|
|
|
|
`identified` is (recommended, over a table of operators): every operator's call requires
|
|
|
|
|
|
it (`requiredScopes`). The first operator, once signed up, is made by two statements on
|
|
|
|
|
|
the register's database, run as `deploy` in the deploy's folder: the scope onto the
|
|
|
|
|
|
account, and onto its sessions, as scopes are copied onto them (handle in lower case):
|
|
|
|
|
|
|
|
|
|
|
|
```sql
|
|
|
|
|
|
BEGIN;
|
|
|
|
|
|
UPDATE "serverpod_auth_core_user"
|
|
|
|
|
|
SET "scopeNames" = ("scopeNames"::jsonb || '["operator"]')::json
|
|
|
|
|
|
WHERE "id" = (SELECT "authUserId" FROM "public_profile" WHERE "handleKey" = 'their_handle')
|
|
|
|
|
|
AND NOT ("scopeNames"::jsonb ? 'operator');
|
|
|
|
|
|
UPDATE "serverpod_auth_core_session"
|
|
|
|
|
|
SET "scopeNames" = ("scopeNames"::jsonb || '["operator"]')::json
|
|
|
|
|
|
WHERE "authUserId" = (SELECT "authUserId" FROM "public_profile" WHERE "handleKey" = 'their_handle')
|
|
|
|
|
|
AND NOT ("scopeNames"::jsonb ? 'operator');
|
|
|
|
|
|
COMMIT;
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
and an operator never waits: the wait screen's next look approves them and gives them
|
|
|
|
|
|
their session.
|
|
|
|
|
|
- **D33 The matching code is four words of BIP-39's English list, read by the operator**
|
|
|
|
|
|
(the developer's "Four words" over six digits, which were recommended; then the
|
|
|
|
|
|
operator reading and BIP-39's list, both recommended, over the person reading theirs
|
|
|
|
|
|
out and over EFF's short list): the operator reads the words beside the handle and asks
|
|
|
|
|
|
whether the person sees them, who only says yes or no. The wait screen says that
|
|
|
|
|
|
Halkyon never asks anyone to read words out, as a recovery phrase is words too, of the
|
|
|
|
|
|
same list (already in the repository under the MIT License, unique by their first four
|
|
|
|
|
|
letters; four words hold 44 bits).
|
|
|
|
|
|
- **D34 The operator's section is a card in Settings**, "This instance", below the
|
|
|
|
|
|
account's (recommended, over the Profile tab): halkyon_app's, shown to operators alone,
|
|
|
|
|
|
opening the waiting accounts, the accounts and the operators; a badge on the Settings
|
|
|
|
|
|
cog while someone waits, as the sync trouble dot is.
|
|
|
|
|
|
|
2026-10-25 16:52:21 +01:00
|
|
|
|
On 25 Oct, how the second step is built (the assistants, their grants and figures):
|
|
|
|
|
|
|
|
|
|
|
|
- **D35 The answer streams over Serverpod's own stream** (recommended, over the whole
|
|
|
|
|
|
answer at once and over a route sending Server-Sent Events): `assistant.ask` is an
|
|
|
|
|
|
endpoint method returning a stream, over the WebSocket the client already keeps, signed
|
|
|
|
|
|
in as every call is (Caddy upgrades it as it is). Text appears as the model writes it,
|
|
|
|
|
|
and a round of the tools' loop ends as soon as its tool call is complete. A route of
|
|
|
|
|
|
our own would have needed its own check of the session, for nothing Serverpod's stream
|
|
|
|
|
|
lacks.
|
|
|
|
|
|
- **D36 The adapters are tested on replies written from the providers' documentation
|
|
|
|
|
|
first, and on recorded ones later** (recommended, over recording first, which would
|
|
|
|
|
|
have held the step up until the developer had keys, and over the documentation alone):
|
|
|
|
|
|
the fixtures follow Anthropic's and OpenAI's documented stream formats event by event;
|
|
|
|
|
|
`tool/record_llm.dart`, which the developer runs once with their own key, writes the
|
|
|
|
|
|
real replies beside them, and the tests run on both, so a provider that strays from its
|
|
|
|
|
|
documentation is caught there, not in someone's hands.
|
|
|
|
|
|
- **D37 The assistants are set in `deploy/assistants.env`** (recommended, over the whole
|
|
|
|
|
|
of `deploy/.env` going to the server and over three fixed numbered slots): Compose names
|
|
|
|
|
|
every variable it passes to a container, and the IDs an operator chooses can't be named
|
|
|
|
|
|
in `compose.yaml` ahead. The file of their own is passed whole to the server alone
|
|
|
|
|
|
(`env_file`, optional, so an instance without it starts as before), git-ignored,
|
|
|
|
|
|
mode 600, with an example committed. It holds the keys too (`ASSISTANT_CLAUDE_KEY`):
|
|
|
|
|
|
everything about the assistants is in one place, outside the database and its backups,
|
|
|
|
|
|
and nothing of `deploy/.env` reaches the server that doesn't today. It holds the key of
|
|
|
|
|
|
D30's IDs as well (`ASSISTANT_ID_KEY`, at least 32 characters, or a server with
|
|
|
|
|
|
assistants doesn't start): changing it gives everyone a new ID at the providers, and
|
|
|
|
|
|
costs nothing else.
|
|
|
|
|
|
- **D38 Prices sit beside the model** (recommended, over typing them in the app):
|
|
|
|
|
|
`ASSISTANT_CLAUDE_PRICE_INPUT` and `_PRICE_OUTPUT`, per million tokens, in
|
|
|
|
|
|
`ASSISTANT_CURRENCY` (USD unless set, as the providers bill), so a model and its price
|
|
|
|
|
|
change together, with one restart. A request's cost is worked out when it is counted
|
|
|
|
|
|
and kept with the figures, so a later price leaves the past as it was billed. A limit
|
|
|
|
|
|
is checked before each request against what was counted: the last request before it
|
|
|
|
|
|
may go past it by its own answer, which the request's ceiling on output tokens keeps
|
|
|
|
|
|
small.
|
|
|
|
|
|
- **D39 The instance's `/privacy` describes the whole instance** (recommended, over the
|
|
|
|
|
|
assistants alone): made from its settings on its web server, in English and German as
|
|
|
|
|
|
the profile pages are, readable before signing up: who may sign up, where data and
|
|
|
|
|
|
backups are, what is kept (addresses only as hashes, no IP address past the hour its
|
|
|
|
|
|
limits count, sessions), private studysets, then each assistant (provider, model, what
|
|
|
|
|
|
goes, D27) and whether personal keys are allowed. halkyon.li has no website page, and a
|
|
|
|
|
|
family member reads this one before they sign up.
|
|
|
|
|
|
- **D40 The agreement is kept on the grant** (recommended, over the person's sealed
|
|
|
|
|
|
settings): the grant records when the person agreed and to which provider (its
|
|
|
|
|
|
protocol and host), and `assistant.ask` refuses (`notAgreed`) until they have, so a
|
|
|
|
|
|
modified app can't skip it and every device of theirs knows. Should the operator move
|
|
|
|
|
|
an assistant to another provider, the person is asked again; a new model of the same
|
|
|
|
|
|
provider asks nothing. The operator sees that they agreed, and when.
|
|
|
|
|
|
- **D41 Figures are kept 3 months** (the developer's choice, over 13 months, which were
|
|
|
|
|
|
recommended, and over keeping them as long as the account): enough for the last bills,
|
|
|
|
|
|
less kept about each person. Older days are deleted daily, and all of them with the
|
|
|
|
|
|
account.
|
|
|
|
|
|
- **D42 Days and months are UTC's** (recommended, over the instance's time zone, which no
|
|
|
|
|
|
setting holds today): the providers bill by UTC, so the figures add up to their bills;
|
|
|
|
|
|
a day's limit resets at midnight UTC, which the app shows in the person's own time.
|
|
|
|
|
|
- **D43 A member service offers no assistant yet** (recommended, over building the
|
|
|
|
|
|
register's routes for grants now): grants and figures live on the register (Learn's
|
|
|
|
|
|
server), whose service asks. Todo, a member, answers that it has none, until a member
|
|
|
|
|
|
needs the assistant; then the member asks the register before forwarding, as it asks
|
|
|
|
|
|
everything about accounts (ADR 0016).
|
|
|
|
|
|
- **D44 Nobody is granted an assistant that isn't set**: a grant names the assistant by
|
|
|
|
|
|
its ID, and stays, unused, should the operator remove that assistant from the file;
|
|
|
|
|
|
put back, it holds again, with the person's agreement if the provider is the same.
|
2026-10-25 17:38:53 +01:00
|
|
|
|
- **D45 Chat completions are sent in each known host's dialect, and in a common one to
|
|
|
|
|
|
every other** (recommended, over the fields every service takes, which loses OpenAI's
|
|
|
|
|
|
`store: false` and its reasoning models' ceiling, and over a dialect the operator
|
|
|
|
|
|
names): OpenAI, Mistral and Gemini refuse a field they don't know, and they differ in
|
|
|
|
|
|
the ceiling's field (`max_completion_tokens`, `max_tokens`), in usage asked for or
|
|
|
|
|
|
always sent, and in `store`. By the base URL's host, OpenAI (api.openai.com), Mistral,
|
|
|
|
|
|
Gemini and OpenRouter each get only their fields; any other host gets what Ollama,
|
|
|
|
|
|
vLLM and llama.cpp all take. Replies are read leniently whatever the host, as each
|
|
|
|
|
|
streams usage, tool calls and errors in its own way.
|
|
|
|
|
|
- **D46 OpenAI's Responses API is a third protocol, `openai-responses`** (recommended,
|
|
|
|
|
|
over chat completions alone): from GPT-5.4 on, OpenAI's models call tools in chat
|
|
|
|
|
|
completions only without reasoning, and GPT-6 Astra and 6.1 Sol only through the
|
|
|
|
|
|
Responses API. Stateless: `store: false`, so OpenAI keeps no conversation, and each
|
|
|
|
|
|
request carries the whole of it, with the model's encrypted reasoning items as it
|
|
|
|
|
|
streamed them, sent back in their place (as Anthropic's thinking blocks are), and the
|
|
|
|
|
|
`phase` of its messages. Ollama, vLLM and OpenRouter speak it as well.
|
2026-10-25 16:52:21 +01:00
|
|
|
|
|
feat(learn): conversations with assistants, kept sealed (ADR 0021, step 3)
The first part of step 3, decided as D47 to D52 in ADR 0021: where a
conversation shows (a sheet over the screen), where kept ones are found
(the field), the scope's chip and that it starts with only what is
ticked, how conversations are kept, and what a device that can't seal
does.
Two synced tables: assistant_conversation (its title, assistant and
scope) and assistant_turn (one question and everything up to its answer,
never changed once written, ADR 0001, rule 2), so two devices continuing
a conversation offline lose nothing. SyncConversationGateway seals every
row with the person's key, a turn bound to its conversation, and reads
no row that isn't sealed: a device that can't seal keeps nothing (D52,
ConversationNotKept). Deleting one blanks it and its turns first (ADR
0002, rule 2). A turn keeps every message a follow-up sends back (tool
calls and results, the providers' own blocks), but no image, only that
one was sent.
The instance's privacy page says conversations are kept, encrypted, and
what the instance sees of them.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 19:48:00 +01:00
|
|
|
|
On 26 Oct, how the third step is built (the assistant answering in Learn):
|
|
|
|
|
|
|
|
|
|
|
|
- **D47 A conversation shows in a sheet over the screen it was asked on** (recommended,
|
|
|
|
|
|
over a screen of its own and over the answer unfolding under the field): at half
|
|
|
|
|
|
height, dragged up to full, follow-up questions in the same sheet, so the card in a
|
|
|
|
|
|
session or the studyset asked about stays in view.
|
|
|
|
|
|
- **D48 Kept conversations are found from the field** (recommended, over a tile in
|
|
|
|
|
|
Settings › Assistants and over both): a history button in the field lists them, newest
|
|
|
|
|
|
first, each with its assistant and scope, those about where the person is first;
|
|
|
|
|
|
deleting one asks first.
|
|
|
|
|
|
- **D49 The scope is one chip with a menu** (recommended, over a segmented row of the
|
|
|
|
|
|
four): it leads the parts' chips ("Only what I tick"), and its menu holds This
|
|
|
|
|
|
studyset, Its tree, Library and D8's switch, so the field takes one more line at most.
|
|
|
|
|
|
- **D50 The field starts with only what is ticked** (recommended, over where the person
|
|
|
|
|
|
is and over the last scope used): nothing goes beyond the chips ticked and the model
|
|
|
|
|
|
gets no lookups until the person widens the scope, as the chips themselves start
|
|
|
|
|
|
unticked (decided 10 Oct).
|
|
|
|
|
|
- **D51 A conversation is a row and its turns, appended** (recommended, over one row
|
|
|
|
|
|
rewritten per conversation): `assistant_conversation` holds its assistant, scope and
|
|
|
|
|
|
title, `assistant_turn` one turn each, never changed once written (ADR 0001, rule 2), so
|
|
|
|
|
|
two devices continuing it offline lose nothing, and each turn is sealed alone (D13), so
|
|
|
|
|
|
a long conversation isn't sealed and synced anew with every question. Deleting one
|
|
|
|
|
|
blanks its turns, then deletes them (ADR 0002, rule 2).
|
|
|
|
|
|
- **D52 A device that can't seal answers but keeps nothing** (recommended, over offering
|
|
|
|
|
|
no assistant there): where the account's keys aren't open, the sheet says the
|
|
|
|
|
|
conversation isn't kept, and it is gone once the sheet closes; nothing unsealed is
|
|
|
|
|
|
stored or synced, as with own keys.
|
|
|
|
|
|
|
2026-10-23 14:47:04 +02:00
|
|
|
|
## Proposal
|
|
|
|
|
|
|
|
|
|
|
|
1. **Who signs up, per instance:** `SIGN_UP`: `open` (as today), `approval`, or
|
|
|
|
|
|
`closed`. On halkyon.li `approval`.
|
docs(adr): ADR 0021 accepted, the assistant's boundaries (D7–D30)
The developer's decisions of 25 Oct, reviewing ADR 0021 whole:
- What an assistant may see and do (D7–D12): the scope of each question
(the parts ticked, the studyset, its tree, the library), looked up
through read-only tools the app answers on the device; private
studysets out of a wider scope unless switched on, and a warning
whenever one's content would go to a remote model, Lumo included, as
no provider keeps a question confidential while its model answers;
changes only as drafts; progress never; text first, an image when
ticked or asked for.
- What it keeps, does and where it lives (D13–D18): conversations kept
sealed with the person's own key; four features (questions about what
is open, cards from text, explaining a miss, checking a written
answer); grants and limits in halkyon_base, the adapters in a package
of their own (halkyon_llm, BSD-3-Clause); the proposal's points 4–8
and 10 as written; the warning once per studyset and assistant; built
for v0.21.0.
- Sign-ups and operators (D19–D26): SIGN_UP open, approval or closed;
the first operator by SQL, others named in the app; suspending an
approved account; a wait screen with a matching code the operator
checks with the person; 14 days, 10 waiting.
- What people are told and what never goes (D27–D30): the app and a
privacy page of each instance's own; others' posts only with their
author's switch, a copy's licence being its agreement; an opaque ID
per person for the provider.
ADR 0022 and Learn's AGENTS.md now point to it as accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 13:36:56 +01:00
|
|
|
|
2. **The operator** is a role on the register. The first one by SQL (D20), the others
|
|
|
|
|
|
named in the app (D21); an operator approves, refuses and suspends accounts (D22),
|
|
|
|
|
|
grants assistants with their limits, and sees everyone's figures, never content.
|
2026-10-23 14:47:04 +02:00
|
|
|
|
3. **Waiting accounts** (D1): after signing up (SimpleLogin, handle, keys: ADR 0020), an
|
2026-10-25 15:04:21 +01:00
|
|
|
|
account waits. It gets no session, only a pass for its wait screen, which sees that it
|
|
|
|
|
|
waits or deletes the account (D31); nothing syncs and nothing uploads (D23). The operator sees who waits in the app (the
|
docs(adr): ADR 0021 accepted, the assistant's boundaries (D7–D30)
The developer's decisions of 25 Oct, reviewing ADR 0021 whole:
- What an assistant may see and do (D7–D12): the scope of each question
(the parts ticked, the studyset, its tree, the library), looked up
through read-only tools the app answers on the device; private
studysets out of a wider scope unless switched on, and a warning
whenever one's content would go to a remote model, Lumo included, as
no provider keeps a question confidential while its model answers;
changes only as drafts; progress never; text first, an image when
ticked or asked for.
- What it keeps, does and where it lives (D13–D18): conversations kept
sealed with the person's own key; four features (questions about what
is open, cards from text, explaining a miss, checking a written
answer); grants and limits in halkyon_base, the adapters in a package
of their own (halkyon_llm, BSD-3-Clause); the proposal's points 4–8
and 10 as written; the warning once per studyset and assistant; built
for v0.21.0.
- Sign-ups and operators (D19–D26): SIGN_UP open, approval or closed;
the first operator by SQL, others named in the app; suspending an
approved account; a wait screen with a matching code the operator
checks with the person; 14 days, 10 waiting.
- What people are told and what never goes (D27–D30): the app and a
privacy page of each instance's own; others' posts only with their
author's switch, a copy's licence being its agreement; an opaque ID
per person for the provider.
ADR 0022 and Learn's AGENTS.md now point to it as accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 13:36:56 +01:00
|
|
|
|
handle, when they signed up, which is all the instance knows, and the matching code of
|
|
|
|
|
|
D24) and approves or refuses; a refusal deletes the account. Unapproved after 14 days, it is deleted. At most 10
|
2026-10-23 14:47:04 +02:00
|
|
|
|
waiting at once, and sign-ups per network limited as today's, so strangers can't flood
|
|
|
|
|
|
the list. The operator's app shows a badge; there is no mail, as the instance keeps no
|
|
|
|
|
|
addresses.
|
2026-10-23 15:08:40 +02:00
|
|
|
|
4. **The assistants**, set by the operator (D4): one or more, each with an ID, the name
|
2026-10-25 17:38:53 +01:00
|
|
|
|
people see ("Claude Sonnet"), its protocol (`anthropic`, `openai` for every
|
|
|
|
|
|
OpenAI-compatible service, or `openai-responses`, D46), its base URL (the provider's own unless set), model and key
|
2026-10-25 16:52:21 +01:00
|
|
|
|
in `deploy/assistants.env` (D37: `ASSISTANTS=claude,gpt`, then `ASSISTANT_CLAUDE_NAME`,
|
|
|
|
|
|
`_PROTOCOL`, `_BASE_URL`, `_MODEL`, `_KEY`, `_IMAGES`, and the prices of D38). There
|
2026-10-23 15:08:40 +02:00
|
|
|
|
rather than in the app: the keys stay out of the database and its hourly backups, where
|
|
|
|
|
|
the operator keeps the instance's other secrets. None set: no assistant on the
|
|
|
|
|
|
instance, as today. Adding Lumo once its API is out, or switching a model, is a change
|
|
|
|
|
|
of these and a restart; no app changes.
|
2026-10-25 17:38:53 +01:00
|
|
|
|
5. **Adapters of our own, one per protocol (D46),** behind one interface, over plain HTTP, no SDKs, in a pure
|
2026-10-23 15:08:40 +02:00
|
|
|
|
Dart package of their own, which the server uses for the operator's assistants and the
|
|
|
|
|
|
app for personal keys (10). Features use only what both protocols share: a system prompt and messages,
|
2026-10-25 17:38:53 +01:00
|
|
|
|
streamed text, and tool calls where a feature needs them. Tested against documented
|
|
|
|
|
|
and recorded replies of each (D36). Not chosen: LiteLLM as a sidecar (a Python proxy for about 100
|
2026-10-23 14:47:04 +02:00
|
|
|
|
providers: one more container to run and update, for providers never used) and
|
|
|
|
|
|
langchain_dart (a large framework for a small job).
|
2026-10-23 15:08:40 +02:00
|
|
|
|
6. **Grants** (D2, D4): nobody has an assistant until the operator grants it to them, one
|
2026-10-25 16:52:21 +01:00
|
|
|
|
assistant at a time, each grant with its limits. The person agrees once to what goes
|
|
|
|
|
|
where: the provider's name, that the instance sees the text on its way, and that the
|
|
|
|
|
|
operator sees how much they used, never what; the grant keeps their agreement (D40).
|
2026-10-23 15:08:40 +02:00
|
|
|
|
7. **Asking:** the field offers the assistants granted beside the web search (the one last
|
|
|
|
|
|
used first), the app shows what it will send, the person sends it to the instance
|
2026-10-23 14:47:04 +02:00
|
|
|
|
(`assistant.ask`, the answer streamed), the instance checks the grant and what is left
|
|
|
|
|
|
of the limit, forwards the request, and counts what the provider's reply reports
|
|
|
|
|
|
(input and output tokens). Past the limit it refuses (`limitReached`), saying when it
|
|
|
|
|
|
resets. A private studyset (ADR 0019) goes only as far as the person sends it,
|
docs(adr): ADR 0021 accepted, the assistant's boundaries (D7–D30)
The developer's decisions of 25 Oct, reviewing ADR 0021 whole:
- What an assistant may see and do (D7–D12): the scope of each question
(the parts ticked, the studyset, its tree, the library), looked up
through read-only tools the app answers on the device; private
studysets out of a wider scope unless switched on, and a warning
whenever one's content would go to a remote model, Lumo included, as
no provider keeps a question confidential while its model answers;
changes only as drafts; progress never; text first, an image when
ticked or asked for.
- What it keeps, does and where it lives (D13–D18): conversations kept
sealed with the person's own key; four features (questions about what
is open, cards from text, explaining a miss, checking a written
answer); grants and limits in halkyon_base, the adapters in a package
of their own (halkyon_llm, BSD-3-Clause); the proposal's points 4–8
and 10 as written; the warning once per studyset and assistant; built
for v0.21.0.
- Sign-ups and operators (D19–D26): SIGN_UP open, approval or closed;
the first operator by SQL, others named in the app; suspending an
approved account; a wait screen with a matching code the operator
checks with the person; 14 days, 10 waiting.
- What people are told and what never goes (D27–D30): the app and a
privacy page of each instance's own; others' posts only with their
author's switch, a copy's licence being its agreement; an opaque ID
per person for the provider.
ADR 0022 and Learn's AGENTS.md now point to it as accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 13:36:56 +01:00
|
|
|
|
decrypted on the device for that request. The scope (D7) holds the conversation: the
|
|
|
|
|
|
app runs the tools' loop, answering each lookup from the person's local data within
|
|
|
|
|
|
it, so with the operator's assistant the lookups' answers pass through the instance as
|
|
|
|
|
|
the question does. A draft (D10) arrives as a tool call the app opens in the editor.
|
|
|
|
|
|
Whether an assistant reads images (D12) is its setting (`ASSISTANT_CLAUDE_IMAGES`; for
|
|
|
|
|
|
a personal key, a switch beside it).
|
2026-10-23 15:08:40 +02:00
|
|
|
|
8. **Limits and statistics** (D3): per grant, per day and per month (a day's limit stops a
|
|
|
|
|
|
runaway loop early). Counted per person, day and assistant: requests, input and output
|
2026-10-25 16:52:21 +01:00
|
|
|
|
tokens, and the cost at the prices the operator enters per model (per million tokens,
|
|
|
|
|
|
D38; without prices, tokens only, and limits in tokens), by UTC's days (D42), for
|
|
|
|
|
|
3 months (D41). Neither prompts nor answers are kept. The operator sees everyone's figures in the app, per person and month; each
|
2026-10-23 14:47:04 +02:00
|
|
|
|
person sees their own.
|
docs(adr): ADR 0021 accepted, the assistant's boundaries (D7–D30)
The developer's decisions of 25 Oct, reviewing ADR 0021 whole:
- What an assistant may see and do (D7–D12): the scope of each question
(the parts ticked, the studyset, its tree, the library), looked up
through read-only tools the app answers on the device; private
studysets out of a wider scope unless switched on, and a warning
whenever one's content would go to a remote model, Lumo included, as
no provider keeps a question confidential while its model answers;
changes only as drafts; progress never; text first, an image when
ticked or asked for.
- What it keeps, does and where it lives (D13–D18): conversations kept
sealed with the person's own key; four features (questions about what
is open, cards from text, explaining a miss, checking a written
answer); grants and limits in halkyon_base, the adapters in a package
of their own (halkyon_llm, BSD-3-Clause); the proposal's points 4–8
and 10 as written; the warning once per studyset and assistant; built
for v0.21.0.
- Sign-ups and operators (D19–D26): SIGN_UP open, approval or closed;
the first operator by SQL, others named in the app; suspending an
approved account; a wait screen with a matching code the operator
checks with the person; 14 days, 10 waiting.
- What people are told and what never goes (D27–D30): the app and a
privacy page of each instance's own; others' posts only with their
author's switch, a copy's licence being its agreement; an opaque ID
per person for the provider.
ADR 0022 and Learn's AGENTS.md now point to it as accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 13:36:56 +01:00
|
|
|
|
9. **What people are told** (D27): the provider and model, what is sent, that the instance
|
|
|
|
|
|
sees it in passing, that the operator sees each person's figures, that the instance
|
|
|
|
|
|
keeps no content, and that conversations are kept sealed on the person's devices
|
2026-10-25 16:52:21 +01:00
|
|
|
|
(D13): on the consent sheet, in Settings › Assistant, and on the instance's `/privacy`
|
|
|
|
|
|
(D39).
|
2026-10-23 15:08:40 +02:00
|
|
|
|
10. **Personal keys** (D5, D6), where the operator switches them on (`ASSISTANT_OWN_KEYS`,
|
|
|
|
|
|
off unless `on`; `instance.info()` says so, and the app offers them only then): a
|
|
|
|
|
|
person adds a provider in Settings (protocol, base URL, model, their key), and may add
|
|
|
|
|
|
several. The key goes into their settings, which are sealed with their personal key
|
|
|
|
|
|
(ADR 0019), so it reaches their other devices and the instance can't read it. The app
|
|
|
|
|
|
calls the provider directly with the same adapters (5); the instance sees neither key
|
|
|
|
|
|
nor text and counts nothing, and the person's limits are their provider's. The
|
|
|
|
|
|
instance can't stop a modified app from doing so, and needn't: nothing passes through
|
|
|
|
|
|
it. Personal assistants are offered in the field beside those granted.
|
docs(adr): ADR 0021 accepted, the assistant's boundaries (D7–D30)
The developer's decisions of 25 Oct, reviewing ADR 0021 whole:
- What an assistant may see and do (D7–D12): the scope of each question
(the parts ticked, the studyset, its tree, the library), looked up
through read-only tools the app answers on the device; private
studysets out of a wider scope unless switched on, and a warning
whenever one's content would go to a remote model, Lumo included, as
no provider keeps a question confidential while its model answers;
changes only as drafts; progress never; text first, an image when
ticked or asked for.
- What it keeps, does and where it lives (D13–D18): conversations kept
sealed with the person's own key; four features (questions about what
is open, cards from text, explaining a miss, checking a written
answer); grants and limits in halkyon_base, the adapters in a package
of their own (halkyon_llm, BSD-3-Clause); the proposal's points 4–8
and 10 as written; the warning once per studyset and assistant; built
for v0.21.0.
- Sign-ups and operators (D19–D26): SIGN_UP open, approval or closed;
the first operator by SQL, others named in the app; suspending an
approved account; a wait screen with a matching code the operator
checks with the person; 14 days, 10 waiting.
- What people are told and what never goes (D27–D30): the app and a
privacy page of each instance's own; others' posts only with their
author's switch, a copy's licence being its agreement; an opaque ID
per person for the provider.
ADR 0022 and Learn's AGENTS.md now point to it as accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 13:36:56 +01:00
|
|
|
|
11. **Never sent, in any scope:** the password, the account's keys, the recovery phrase,
|
|
|
|
|
|
codes, API keys, the Jellyfin token, other people's data (but posts whose author
|
|
|
|
|
|
agreed, D28), and progress (D11). Nothing is asked without the person: no assistant
|
|
|
|
|
|
runs in the background.
|
2026-10-23 14:47:04 +02:00
|
|
|
|
|
|
|
|
|
|
## Consequences
|
|
|
|
|
|
|
|
|
|
|
|
- The operator pays the provider, and sees who used how much, never what for.
|
docs(adr): ADR 0021 accepted, the assistant's boundaries (D7–D30)
The developer's decisions of 25 Oct, reviewing ADR 0021 whole:
- What an assistant may see and do (D7–D12): the scope of each question
(the parts ticked, the studyset, its tree, the library), looked up
through read-only tools the app answers on the device; private
studysets out of a wider scope unless switched on, and a warning
whenever one's content would go to a remote model, Lumo included, as
no provider keeps a question confidential while its model answers;
changes only as drafts; progress never; text first, an image when
ticked or asked for.
- What it keeps, does and where it lives (D13–D18): conversations kept
sealed with the person's own key; four features (questions about what
is open, cards from text, explaining a miss, checking a written
answer); grants and limits in halkyon_base, the adapters in a package
of their own (halkyon_llm, BSD-3-Clause); the proposal's points 4–8
and 10 as written; the warning once per studyset and assistant; built
for v0.21.0.
- Sign-ups and operators (D19–D26): SIGN_UP open, approval or closed;
the first operator by SQL, others named in the app; suspending an
approved account; a wait screen with a matching code the operator
checks with the person; 14 days, 10 waiting.
- What people are told and what never goes (D27–D30): the app and a
privacy page of each instance's own; others' posts only with their
author's switch, a copy's licence being its agreement; an opaque ID
per person for the provider.
ADR 0022 and Learn's AGENTS.md now point to it as accepted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-25 13:36:56 +01:00
|
|
|
|
- The instance sees what is asked on its way to the provider, and the lookups' answers;
|
|
|
|
|
|
the provider's own terms then apply to it. A private studyset leaves end-to-end
|
|
|
|
|
|
encryption wherever it goes to a remote model (D9).
|
2026-10-23 15:08:40 +02:00
|
|
|
|
- A provider that is down stops the assistants on it; the others granted, personal keys
|
|
|
|
|
|
and the web search go on.
|
2026-10-23 14:47:04 +02:00
|
|
|
|
- Strangers can sign up and wait, but can't use anything, and their accounts lapse.
|
2026-10-23 15:08:40 +02:00
|
|
|
|
- Public instances keep the rule of 10 Oct: their operators leave the assistants unset,
|
|
|
|
|
|
and may allow personal keys.
|