Architecture
Mycelium2 is a Rust workspace of ten crates over an axum HTTPS
server. Everything is self-contained: SQLite metadata, encrypted files
on disk, no external services (the LLM backend is optional).
┌──────────────────────────────────────────── mycelium2 (bin) ───┐ │ │ │ mycelium-web ── axum HTTPS + SSR pages + REST /api/v1 │ │ │ merges the MCP router at /mcp │ │ │ │ │ ├── mycelium-auth ── login, sessions, TOTP/WebAuthn, │ │ │ OIDC, API keys, RBAC │ │ │ │ │ ├── mycelium-librarian ── book ingest worker (LLM + │ │ │ heuristic fallback) │ │ │ │ │ ├── mycelium-mcp ── stateless MCP 2026-07-28 server │ │ │ (rmcp, Streamable HTTP) │ │ │ │ │ └── mycelium-store ── SQLite + encrypted file repo + │ │ │ encrypted search index │ │ │ │ │ ├── mycelium-crypto ── Argon2id, HKDF, │ │ │ AES-256-GCM, key newtypes │ │ │ │ │ └── mycelium-core ── OKF parsing, links, │ │ graph, book anchors, search│ └───────────────────────────────────────────────────────────────┘
Encryption model
- **Per-user data**: password → Argon2id → KEK → unseals the master
key → HKDF-SHA256 derives path-bound DEKs → AES-256-GCM per file.
The search index uses the same pattern (HMAC tokens + AEAD doc
payloads) so plaintext never touches the database.
- **Global data** (bookshelves, library stacks, global skills): the
service key (0600 file, env override) with the same envelope
format.
- **Key newtypes** (`MasterKey`/`Kek`/`Dek`/`ServiceKey`/...) make
key-mixing a compile error.
Scopes and namespaces
| Scope id | Key | Contents |
|---|---|---|
| `user:<uuid>` | user master key | private bundle: concepts, notes, private skills |
| `global:skills` | service key | global skills shelf (admin-write, all-read) |
| `global:library` | service key | book catalog concepts (hub + chapters) |
Book **stack texts** (the full book bodies, up to the configured upload limit) are raw
encrypted FileRepo payloads — deliberately outside the registry and
search index; they are read via `book://<slug>#<anchor>` passage
extraction, never listed or searched.
OKF format
Concepts are markdown files with YAML frontmatter (`type` required).
Graph edges are absolute leading-slash `.md` links; links inside code
spans/fenced blocks are skipped (a deliberate divergence from the
original Mycelium — it fixes false-edge bugs). `index.md`, `log.md`,
and `info.md` are reserved. Skills are concepts with `type: Skill`.
Book ingest flow
1. Admin uploads a markdown book (multipart, ≤ the configured limit, CSRF-checked).
2. The librarian worker stages the text, creates book + job rows
(one job per user at a time; atomic claim prevents double-runs).
3. The LLM (optional) enriches a catalog; the heuristic outline is the
total fallback.
4. Full text → `/library/<slug>.md` (raw payload); catalog →
`/<slug>/book.md` hub + `/<slug>/ch-<n>-<slug>.md` chapters in
`global:library`.
5. Passages are read via `GET /api/v1/passages?resource=book://<slug>#<anchor>`
with shelf-visibility enforcement (global-read or admin).
MCP server
Stateless MCP 2026-07-28 over Streamable HTTP at `/mcp`. Per-request
identity comes from the bearer API key (rmcp injects the request parts
into each call). Tools: `mycelium2_memory_query/add/update/status/
maintain`, `mycelium2_skill_get/list`. MCP queries stay private to the
caller's bundle by default (web search spans user + global scopes).
Frontend (mycelium-ui)
`mycelium-ui` is the Leptos-based frontend crate that `mycelium-web`
depends on for rendering. It is feature-split: `ssr` (the default)
server-renders components and the app shell to HTML strings that the
axum handlers interpolate into their pages, and `hydrate` builds the
wasm island bundle that re-attaches behavior client-side. Components
take primitive-only props (strings, options, tuples — no axum or
state types), so the crate stays free of server concerns and compiles
cleanly to `wasm32-unknown-unknown`; the hydrate bundle's artifacts
(`mycelium_ui.js` + `mycelium_ui_bg.wasm`) are checked in under
`crates/mycelium-web/assets/` and delivered by the asset scaffold (see
Deployment). `ASSETS_VERSION` is mirrored in the
crate's shell and must bump in lockstep with mycelium-web's.
Determinism
Graph edges, broken links, orphans, and search ranking are all
deterministic (sorted/stable) — the same inputs always produce the
same outputs, which the test suite relies on.