halkyon/apps/learn/halkyon_learn_agent/README.md
Tizian 「ティツィアーン」 54e212a51c
Some checks failed
CI / check (push) Failing after 1m56s
feat(learn): Learn's agent, an MCP server suggesting in shared studysets
Halkyon's ADR 0044, step 6c (D7, D49 to D52). apps/learn/halkyon_learn_agent
is one executable, `halkyon-agent --instance URL sign-in | sync | mcp`:

- sign-in keeps the token read from stdin, signs in with it, makes the
  agent's key pair on its first sign-in, keeps it before setting the
  public halves on the register (agents.setKeys), and syncs;
- it opens its data as the app's _openPersonData does, on
  halkyon_learn_core and halkyon_content: its own SQLite database, the
  sync's space router, its keys and those of the spaces shared with it,
  and the repositories of studysets, cards, notes, paths, files and
  feedback;
- mcp serves ten tools over stdio (dart_mcp): list, read and search the
  studysets shared with it, suggest a change or a new card or note,
  report, list a studyset's suggestions and reply. Each syncs first and
  a suggestion again at once; a refusal is the tool's error;
- its files live in $XDG_CONFIG_HOME/halkyon-agent/<host>, 0700 and
  0600, refused when others may read them (D50);
- tool/install.sh builds it with `dart build cli` (libsodium and SQLite
  bundled) and copies it to its user on the host, the build before kept
  (D52).

The synced gateways of learning paths and files, and the fakes of the
core's gateways, move into halkyon_learn_core (its testing.dart), which
the app's tests and the agent's share.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Tizian 「ティツィアーン」 <raisondetredev@pm.me>
2026-11-11 22:08:31 +01:00

62 lines
3.2 KiB
Markdown

# halkyon_learn_agent
Halkyon Learn's agent (Halkyon's ADR 0044, D6, D7, D10, D49 to D52): an account of its own on an
instance, made in a person's Profile (Agents) and invited as a Viewer to the studysets they share
with it. It reads their cards and notes and **suggests**: changes, new cards and notes, reports of
what should go, replies. It never writes into a studyset; its Owner and Editors accept or decline
in the app (a studyset's Suggestions). Claude Code, or another MCP client, reaches it over stdio.
## Using it
On the machine it runs on, as a user of its own (D7; halkyon.li's host at home):
1. Build and copy it there from a laptop with Dart, `tool/install.sh <ssh target>` (D52). It builds
for the laptop's architecture (`dart build cli`, libsodium and SQLite bundled; the host needs
no Dart) into `~/.local/lib/halkyon-agent/<commit>`, `~/.local/bin/halkyon-agent` pointing to
it, the build before kept.
2. Sign in once with the token its owner copied from their Profile, on stdin, never as an
argument others on the machine could see:
```
$ halkyon-agent --instance https://halkyon.li sign-in < token.txt
```
It keeps the token, makes its key pair and sets the public halves on the register, syncs and
says how many studysets are shared with it.
3. Let Claude Code start it:
```
$ claude mcp add halkyon -- ~/.local/bin/halkyon-agent --instance https://halkyon.li mcp
```
`halkyon-agent --instance … sync` syncs once, e.g. to see that it still can.
## Its tools
`list_studysets`, `read_studyset` (title, description, topics, cards and notes as plain text),
`search_cards`, `suggest_card_change`, `suggest_new_card` (front and back, or a vocabulary
card's word, reading and meanings), `suggest_note_change`, `suggest_new_note`, `report`,
`list_suggestions` (with replies and what was decided) and `reply`. Only studysets shared with it
count. Each call syncs first and a suggestion syncs again at once; a sync that fails leaves what
it holds to read, and the result says so. A refusal (a studyset not shared with it, a card it
can't find) is the tool's error, which the model reads.
## What it keeps
`$XDG_CONFIG_HOME/halkyon-agent/<host>[_<port>]/` (else `~/.config/…`), the folder 0700 and its
files 0600, refused when others may read or change them (D50): `token`, `keys.json` (its key
pair, unsealed: its user's boundary protects it), `keys_set`, `sync.sqlite` (the shared
studysets, opened as the app opens them), `key_pins.json` (the members' public keys as first
seen), `privacy.json` and `files/`. An instance is reached over HTTPS, or plain HTTP on the same
machine alone. Its session is kept in memory, a sign-in with the token at every start.
## Code
- `lib/src/open_agent.dart` signs in and opens its data as the app's `_openPersonData` does, on
`halkyon_learn_core` (its gateways and repositories) and `halkyon_content` (keys, shared
spaces, files).
- `lib/src/agent_library.dart` reads and suggests, `lib/src/agent_server.dart` makes tools of it
(`dart_mcp`), `lib/src/agent_sync.dart` syncs on demand, `lib/src/agent_home.dart` keeps its
files; `bin/halkyon_agent.dart` is the CLI. Tests run on the core's fakes, without a server.
Licensed under the AGPL-3.0.