What this is — and how to read it
Three panes, one surface. The middle is the editor you write in; the left is your knowledge (docs in, related notes out); the right is chat over only your corpus. Everything AI-shaped is a preview you accept or reject — nothing edits your prose behind your back — and everything private is scoped to you by the server, so the browser can never even name another person's corpus.
This doc is a reference, grouped by surface, and it is honest about the seam between what is wired today and what is still a plan (section 5). Where a feature was previously mis-reported as done, it says so.
Docs in, notes out
Add text or .md/.txt, search it, and see related chunks pushed to you as you type.
A calm manuscript
Floating cream page, warm ink. Select text → ✨ op menu. Hover a block → "Edit this idea". Every change previews as a redline you accept or reject.
Ask your corpus
Grounded answers with citation chips that jump to the source chunk.
1 · The editor — the middle pane
1.1 · The ✨ selection-op menu
Select any run of text and a floating bubble offers nine visible ops in three groups. Each op sends the selection plus its instruction to the generation path and returns a preview. (A legacy clarify op still works but is hidden from the menu.)
| Group | Op | What it does |
|---|---|---|
| Edit | Improve writing | General polish — clarity, flow, word choice — keeping meaning and voice. |
| Rewrite… | Freeform: you type an instruction and it rewrites the selection to match. | |
| Fix grammar | Grammar, spelling and punctuation only; no stylistic drift. | |
| Change tone ▸ | Submenu: Formal · Casual · Friendly · Professional · Confident — re-voices the selection to the chosen register. | |
| (tone = 5 targets) | ||
| Length | Shorten | Tightens to fewer words without losing the point. |
| Expand | Develops the selection with more detail or explanation. | |
| Transform | Bullets | Reshapes prose into a bulleted list. |
| Simplify | Plainer language; lower reading level. | |
| TL;DR | Condenses to a one-line summary. |
1.2 · Two gestures
Selection-op
Select → pick an op → get a result. The precise, surgical gesture: you point at exactly the text you mean and act on it.
"Edit this idea" — the flagship
Hover any block → a ✨ gutter button appears → type a plain instruction like "tighten this" → the paragraph is rewritten and shown as an inline word-diff. The whole-thought gesture, keyed to a single paragraph, no selection needed.
1.3 · Preview · Accept · Reject · Retry
- Accept (Enter / ⌘↵) commits via real editor transforms — the diff becomes clean prose in the document model, not pasted HTML.
- Reject (Esc) restores the original untouched.
- Retry re-runs the same op for a fresh take.
- A
provider · modelmeta line tells you exactly which model produced the suggestion — "any model" made legible.
1.4 · The signature "Ink-In" animation
On Accept, the new text doesn't just pop in — it inks in via a CSS clip-path sweep, left to right, as if the page is absorbing the change. It is the one deliberately delightful moment in an otherwise calm surface, and it respects prefers-reduced-motion — the sweep is skipped entirely for anyone who has asked their system to reduce animation.
1.5 · Modes & chrome — the calm surface
Focus mode ⇧⌘F
Every block except the one under the caret dims. The sentence you're writing is the only lit thing on the page.
Manuscript ↔ Margin
Manuscript is the clean page. Margin mode works the AI marginalia in the right margin, joined to the text by leader lines — annotations beside the prose, not on top of it.
The top bar
The only chrome: wordmark, live word-count + read-time, model toggle, focus toggle. It idle-dims so the page is what you see.
Aesthetic: a floating cream page on a warm room, Source Serif 4 prose in warm ink, a quiet blue accent. The design language is documented separately; the point is that the tool disappears and the writing stays.
1.6 · Generation today — the two paths & the model toggle
/api/write proxyWRITE_DIRECT_MODEL=true runs the op straight on the oll-model gateway (Groq · llama-3.1-8b-instant) — the self-contained local demoThe provider toggle — "any model," wired
A persisted switch flips every op between Groq (Fast / free) and Claude (Quality / pro), threaded through the whole op pipeline — so the promise "any model" is literally in the request path, not marketing. Tier gating (who gets Claude) is framing-only until billing lands; the plumbing is done.
2 · The memory sidecar — left + right panes
2.1 · LEFT · "Your Knowledge" — three sections
1 · Add to knowledge
Paste text, or upload .md/.txt. Each ingested doc shows in a list with its chunk count, so the corpus is legible, not a black box.
2 · Search your knowledge
A manual semantic search box for when you do know what you're looking for — returns ranked ChunkCards.
3 · As you write
The proactive lane: cards pushed from the editor based on the paragraph under your cursor — retrieval you didn't ask for.
Every result is a ChunkCard: a snippet + its document_id + an optional heading or page + a similarity score. Provenance is on the card, always — you can see where a memory came from before you trust it.
2.2 · Proactive retrieval — retrieval as a background sense
An always-mounted layer watches the caret. When you settle in a paragraph it retrieves related knowledge and pushes it to the left pane — no query typed. The discipline is in the guardrails, so it helps without nagging:
| Guardrail | Behaviour |
|---|---|
| Debounce 600 ms | Waits until you pause before firing — never mid-keystroke. |
| Ignores < 20-char paragraphs | A half-written line isn't enough signal; it stays quiet. |
| Dedups | Won't re-push the same chunk you're already looking at. |
| Top-5 from your corpus | Precision over recall — a short, dead-on list beats a long fuzzy one. |
| Fails silently | If retrieval errors, nothing happens — it never disturbs the writing. |
2.3 · RIGHT · "Chat" — talk to your corpus
Chat grounded in only your documents. Each answer carries citation chips — [n] docId, hover to see the chunk text — plus a provider · model meta line, so every claim is one hover from its source and you always know which model answered.
MVP note: chat answers are not streamed — the full grounded answer arrives at once.
2.4 · Layout — editor-shell.tsx
On the desktop it's a 3-column grid; each side pane is independently collapsible, so you can write full-width when you want to. Below 1024px the side panes become drawers. Crucially, the middle editor is passed through untouched — the sidecar wraps the writing surface, it doesn't rebuild it.
3 · Identity, privacy & the data model — the trust boundary
3.1 · Core magic-link auth
Passwordless sign-in via Core magic-link. The identity is a 72h HS256 identity-only JWT in a readable oll_token cookie; the plan is read live from /api/auth/me (never baked into the token — mutable entitlement never rides in a token). The /editor route is gated by middleware; auth is on in production and off in local dev for a frictionless loop.
3.2 · Per-user scoped corpus — the one security rule
The browser can't name another user's corpus
On every memory call, the BFF derives collection = mem:user:{id} and acl = [u:{id}] server-side, from the authenticated Core id. The browser never supplies them and never holds the service token. So a user is architecturally incapable of naming someone else's corpus — the classic cross-user IDOR is closed by construction, not by a check that could be forgotten.
Local dev tokens map to a fixed dev corpus. The whole boundary is covered by a trust-boundary test suite, so a regression that re-opened it would fail CI.
3.3 · The BFF split
/api/memory/* only — never the memory service directlyX-Service-Token, pins the per-user collection + acl, then calls oll-memoryThe rule that keeps it safe: the service token's env var must never be prefixed NEXT_PUBLIC_ — that would ship it in the browser bundle and re-open the IDOR. The split only works because the secret stays server-side.
4 · The stack under the hood
| Concern | Runs on |
|---|---|
| Generation (ops + chat) | oll-model gateway /api/text/complete, privacy:"any" → Groq by default (llama-3.1-8b-instant); Claude on the quality toggle. |
| Embeddings / retrieval | oll-memory = LlamaIndex on pgvector, embeddings by Ollama nomic-embed-text — on-device / local, private. Hybrid dense + keyword fused with RRF. |
| BFF pattern | Thin route handlers → pure, testable handlers with an injectable fetch. Chat composes retrieve → ground → generate inside the BFF, so the browser only ever sees a same-origin call. |
nomic — the corpus never has to leave the machine to become searchable. That's the honest basis for both the privacy claim and the pay-once economics (on-device inference is ~$0/run). Details in the integration plan.5 · Wired today vs deferred
✓ Shipped — wired & running
- 3-pane sidecar (collapsible panes + <1024px drawers)
- Ingest: paste text +
.md/.txtupload, with chunk counts - Manual semantic search
- Proactive "as you write" cards + provenance (docId · heading/page · score)
- Chat over your corpus + citation chips (hover = chunk)
- Full ✨ op menu (9 ops) + "Edit this idea"
- Word-level redline diff + Accept / Reject / Retry
- Signature Ink-In animation (reduced-motion aware)
- Direct-to-oll-model demo path (
WRITE_DIRECT_MODEL) - Groq ↔ Claude provider toggle, threaded through every op
- Core magic-link auth + per-user corpus scoping
- Focus / Manuscript / Margin modes
- Live word-count + read-time
○ Deferred — not wired yet
- Drag-a-card-into-the-draft-as-citation is NOT wired — cards are read-only today (previously mis-reported as done)
- Inline Plate citation node
- PDF / binary ingest (UI takes text/markdown only — though the oll-memory backend already supports base64 PDF)
- Streaming (chat answers arrive whole)
- Draft-from-bullets
- Gap-chips (ungrounded-claim flags)
- Folder-sync / watch-sync
- The 70b quality dial on chat
- Production routing of chat generation through the write-service (chat is direct-to-oll-model in the demo)
The gap between the columns is the roadmap. The product thesis ranks which deferred items are the premium wedge (drag-to-cite, gap-chips, draft-from-bullets) versus retention plumbing (folder-sync, streaming).
6 · Headline capabilities
Calm manuscript editor
Redline-preview AI ops + "Edit this idea" — the words ink in on accept. Nothing edits your prose without a preview.
Any model, pay once
A Groq ↔ Claude toggle wired through every op, persisted. "Any model" is in the request path, not the copy.
Write from your own knowledge
Ingest + semantic search + proactive related-notes as you type (600ms, top-5, fails silent).
Chat with your corpus
Grounded, cited answers over only your documents — every claim a hover from its chunk.
Private by construction
A per-user corpus the browser can't name, local nomic embeddings, and the service token never in the bundle.
"Your writing, all right. Any model, pay once."
oll-write — Feature Documentation · code-grounded reference · 2026-07-05. Siblings: the product thesis (the empty market cell) · the integration plan (how memory welds into the editor). Design language: oll-write design. Feeds Backlog + Strategy.
Rendered faithfully from the code as it stands; the deferred column (§5) is the honest edge of what is not yet wired. Any model, pay once, private by construction.