2026-10-23 15:08:40 +02:00
|
|
|
|
# ADR 0022: No hand-off and no connector
|
|
|
|
|
|
|
|
|
|
|
|
- **Status:** decided 23 Oct 2026, by the developer (D1–D3 below); built for v0.19.0
|
|
|
|
|
|
(build 22).
|
|
|
|
|
|
- **Supersedes:** ADR 0006 (Claude reads studysets through a connector on the instance),
|
|
|
|
|
|
and the hand-off to an AI assistant outside the app (decided 10 and 14 Oct 2026, Learn's
|
|
|
|
|
|
`AGENTS.md`).
|
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
|
|
|
|
- **Followed by:** ADR 0021 (an assistant on the instance, on its operator's keys),
|
|
|
|
|
|
accepted 25 Oct 2026.
|
2026-10-23 15:08:40 +02:00
|
|
|
|
|
|
|
|
|
|
## Context
|
|
|
|
|
|
|
|
|
|
|
|
Since 10 Oct a question asked from the app could leave it in two ways, both through the
|
|
|
|
|
|
person's own subscription, as Halkyon called no language model with an API key: the
|
|
|
|
|
|
hand-off opened the chosen assistant's new conversation (Lumo by default, ChatGPT,
|
|
|
|
|
|
Claude, …) with the question and the chosen parts written in, for the person to send; and
|
|
|
|
|
|
Claude's apps read the person's studysets through the instance's connector (ADR 0006: MCP
|
|
|
|
|
|
at `/mcp` with its own OAuth, connected with a code from Settings › Assistant › Connect
|
|
|
|
|
|
Claude). Beside them, the same field searched the web.
|
|
|
|
|
|
|
|
|
|
|
|
ADR 0021 proposes an assistant inside the app on an instance whose operator pays for it:
|
|
|
|
|
|
several providers on the operator's keys, granted per person, with limits and statistics,
|
|
|
|
|
|
and personal keys where the operator allows them. The developer asked on 23 Oct to "drop
|
|
|
|
|
|
the Assistant part that just opens the assistant outside of the app, but let's keep the
|
|
|
|
|
|
web open part", or else decide how the instance's own assistant and opening one's own
|
|
|
|
|
|
outside the app go together.
|
|
|
|
|
|
|
|
|
|
|
|
## Decisions (23 Oct 2026, the developer's)
|
|
|
|
|
|
|
|
|
|
|
|
- **D1 The hand-off goes now** (over keeping it until the instance's assistant comes,
|
|
|
|
|
|
which was recommended): until then the field searches the web only.
|
|
|
|
|
|
- **D2 The connector goes too** (over keeping it, which was recommended): an instance has
|
|
|
|
|
|
one way to an assistant, its operator's (ADR 0021), and nothing else on it reads
|
|
|
|
|
|
people's content for a language model.
|
|
|
|
|
|
- **D3 In v0.19.0, the app and the server together** (over releasing v0.19.0 first and
|
|
|
|
|
|
taking the server's part out with the next raise of `minimumAppBuild`, which was
|
|
|
|
|
|
recommended): build 22 raises `minimumAppBuild` to 22 anyway, so no app that calls the
|
|
|
|
|
|
connector's endpoints can use the instance after it, and nothing needs to stay for
|
|
|
|
|
|
older apps.
|
|
|
|
|
|
|
|
|
|
|
|
## What goes, and what stays
|
|
|
|
|
|
|
|
|
|
|
|
1. **In the app:** the assistants a question opened in (`AiAssistant`, `AssistantHandOff`),
|
|
|
|
|
|
the switch at the field's start between them and the web (`assistantTarget`), Settings'
|
|
|
|
|
|
choice of assistant, Connect Claude with its route, cubit, repository and gateway, and
|
|
|
|
|
|
their texts. A device's settings file from before keeps the old keys (`aiAssistant`,
|
|
|
|
|
|
`customAssistantUrl`, `assistantTarget`) until the next change of a setting writes it
|
|
|
|
|
|
anew without them; nothing reads them.
|
|
|
|
|
|
2. **On the server:** `lib/src/assistant/` (the MCP endpoint, its OAuth pages and metadata,
|
|
|
|
|
|
the five tools, connect codes, tokens), `AssistantEndpoint`, the daily forgetting of
|
|
|
|
|
|
the connector's codes and tokens, their lines in Learn's deletion hook,
|
|
|
|
|
|
`instance.info().assistantConnectorUrl` (nullable, so an older app reads it as none),
|
|
|
|
|
|
and Caddy's forwarding of `/mcp`, `/oauth/*` and `/.well-known/oauth-*`. A migration
|
feat(assistant)!: no hand-off and no connector; the field searches the web (ADR 0022)
The developer decided on 23 Oct to drop the hand-off to an AI assistant
outside the app, and Claude's connector with it, in v0.19.0, the app and
the server together: build 22 raises minimumAppBuild anyway, so no app
calling the connector's endpoints uses the instance after it. An instance
is to have one way to an assistant, its operator's (ADR 0021, proposed).
The app: the field at the foot of Home, and the button in the Library, on
a studyset and while studying, search the web alone, through the engine
chosen in Settings or Android's own search, with the parts of a card the
person picks; a studyset's name and description are never offered. Gone:
the assistants a question opened in (AiAssistant, AssistantHandOff), the
switch between them and the web, Settings' choice of assistant, Connect
Claude with its route, cubit, repository and gateway, and their texts. A
settings file from before keeps the old keys until the next change of a
setting writes it anew; nothing reads them.
The server: lib/src/assistant/ (MCP, its OAuth, the five tools, connect
codes and tokens), AssistantEndpoint, the daily forgetting of the
connector's secrets (its scheduled call cancelled at start), its lines in
the deletion hook, instance.info().assistantConnectorUrl (nullable, so an
older app reads it as none), and Caddy's forwarding of /mcp, /oauth/* and
/.well-known/oauth-*. The migration drops the connector's five tables,
children first:
DROP TABLE "assistant_token" CASCADE; -- tokens of a connection
DROP TABLE "assistant_grant" CASCADE; -- OAuth codes of a connection
DROP TABLE "assistant_connection" CASCADE; -- a person's connected client
DROP TABLE "assistant_connect_code" CASCADE;
DROP TABLE "assistant_client" CASCADE; -- OAuth clients registered
No other table references them, so CASCADE drops only their own foreign
keys. For the minute between the maintenance run and the switch, the old
server answers the connector with errors and fails to delete an account
(its hook still deletes from these tables); ADR 0022 says so.
BREAKING CHANGE: a connected Claude gets no answer from the deploy on, and
the app no longer opens a question in an AI assistant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-23 15:33:53 +02:00
|
|
|
|
drops the five tables (`assistant_client`, `assistant_connect_code`,
|
2026-10-23 15:08:40 +02:00
|
|
|
|
`assistant_connection`, `assistant_grant`, `assistant_token`) with every connection,
|
|
|
|
|
|
code and token in them: from the deploy on, a connected Claude gets no answer, and
|
|
|
|
|
|
people remove the connector in Claude's settings.
|
|
|
|
|
|
3. **Stays:** the field (`AssistantBar` on Home, `AssistantButton` in the Library, on a
|
|
|
|
|
|
studyset and while studying), off unless the person turns it on in Settings, its chips
|
|
|
|
|
|
of what the question is about (those a web search takes: a card's front, back, hints
|
|
|
|
|
|
and explanation, never a studyset's name or description), and the web search through
|
|
|
|
|
|
the engine chosen in Settings, or Android's own search.
|
|
|
|
|
|
|
|
|
|
|
|
## Consequences
|
|
|
|
|
|
|
|
|
|
|
|
- Until an instance offers ADR 0021's assistant, its people ask no language model from the
|
|
|
|
|
|
app. learn.halkyon.eu, a public instance, offers none (ADR 0021: public instances leave
|
|
|
|
|
|
the assistant unset).
|
|
|
|
|
|
- The instance reads payloads in one place fewer (ADR 0019's context named four).
|
feat(assistant)!: no hand-off and no connector; the field searches the web (ADR 0022)
The developer decided on 23 Oct to drop the hand-off to an AI assistant
outside the app, and Claude's connector with it, in v0.19.0, the app and
the server together: build 22 raises minimumAppBuild anyway, so no app
calling the connector's endpoints uses the instance after it. An instance
is to have one way to an assistant, its operator's (ADR 0021, proposed).
The app: the field at the foot of Home, and the button in the Library, on
a studyset and while studying, search the web alone, through the engine
chosen in Settings or Android's own search, with the parts of a card the
person picks; a studyset's name and description are never offered. Gone:
the assistants a question opened in (AiAssistant, AssistantHandOff), the
switch between them and the web, Settings' choice of assistant, Connect
Claude with its route, cubit, repository and gateway, and their texts. A
settings file from before keeps the old keys until the next change of a
setting writes it anew; nothing reads them.
The server: lib/src/assistant/ (MCP, its OAuth, the five tools, connect
codes and tokens), AssistantEndpoint, the daily forgetting of the
connector's secrets (its scheduled call cancelled at start), its lines in
the deletion hook, instance.info().assistantConnectorUrl (nullable, so an
older app reads it as none), and Caddy's forwarding of /mcp, /oauth/* and
/.well-known/oauth-*. The migration drops the connector's five tables,
children first:
DROP TABLE "assistant_token" CASCADE; -- tokens of a connection
DROP TABLE "assistant_grant" CASCADE; -- OAuth codes of a connection
DROP TABLE "assistant_connection" CASCADE; -- a person's connected client
DROP TABLE "assistant_connect_code" CASCADE;
DROP TABLE "assistant_client" CASCADE; -- OAuth clients registered
No other table references them, so CASCADE drops only their own foreign
keys. For the minute between the maintenance run and the switch, the old
server answers the connector with errors and fails to delete an account
(its hook still deletes from these tables); ADR 0022 says so.
BREAKING CHANGE: a connected Claude gets no answer from the deploy on, and
the app no longer opens a question in an AI assistant.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-10-23 15:33:53 +02:00
|
|
|
|
- **The deploy breaks the rule that migrations keep the old server working until the
|
|
|
|
|
|
switch**, for the minute between the maintenance run and the new server: the old one
|
|
|
|
|
|
then answers the connector's calls with errors, and an account deleted meanwhile (by
|
|
|
|
|
|
its owner, or the pruning) fails and is deleted when asked again, as the old server's
|
|
|
|
|
|
deletion hook still deletes from the connector's tables. Keeping the tables a release
|
|
|
|
|
|
longer would keep the rule, for codes and tokens nothing reads; since build 22 raises
|
|
|
|
|
|
`minimumAppBuild` (D3), no released app syncs with that server by then.
|
2026-10-23 15:08:40 +02:00
|
|
|
|
- The privacy page (website repository) drops the connector and the hand-off to Lumo.
|