aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--docs/superpowers/specs/2026-10-16-assistant-canvas-design.md108
1 files changed, 108 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-10-16-assistant-canvas-design.md b/docs/superpowers/specs/2026-10-16-assistant-canvas-design.md
new file mode 100644
index 0000000..4df5562
--- /dev/null
+++ b/docs/superpowers/specs/2026-10-16-assistant-canvas-design.md
@@ -0,0 +1,108 @@
+# Assistant canvas: design
+
+Date: 2026-10-16. Status: approved in brainstorming, not implemented.
+
+## Goal
+
+A Luma-style conversation canvas for the local text assistant, after the
+model of Modesty's Luma (read for ideas only, never copied: Modesty is
+GPLv3). SUPER+Home opens a centred card over DP-1 with the conversation,
+an input and the history. It takes llamachat's place on that bind while it
+is tested.
+
+The canvas is only a view. desktop-assistant is the daemon that owns the
+model, the tools and the history; its protocol and storage are specified in
+that repo, `docs/superpowers/specs/2026-10-16-text-daemon-design.md`.
+
+## Out of scope for v1
+
+Voice, a model picker, attachments, launcher or file search, desktop
+actions with review. Each can come later without reshaping the canvas.
+
+## Where it lives
+
+`desktop/assistant/`, inside the `desktop` process like `island/`. The
+canvas does not need the drawer or the island, but living in the integrated
+process means one keepalive window and one restart path.
+
+- A `PanelWindow` on DP-1, layer overlay, `ExclusionMode.Ignore`,
+ `WlrLayershell.keyboardFocus: Exclusive` while shown, namespace
+ `quickshell-assistant`. Frosting comes from a `blur-assistant` layer rule
+ in hypr-theme's `sections/decorations.lua`.
+- `IpcHandler { target: "assistant" }` with `toggle()`. The bind is
+ `qs -p <repo>/desktop ipc call assistant toggle`.
+- Key events reach a focused item, not the window (AGENTS.md), so Escape
+ and Enter are handled on the input.
+
+## Connection
+
+A `Socket` on `$XDG_RUNTIME_DIR/desktop-assistant.sock` with a
+`SplitParser`, inside a `LazyLoader` that is toggled off and on to retry,
+because a `Socket` whose connect failed never retries in Quickshell 0.3.1.
+The retry runs every 2s while disconnected, as the old overlay did.
+
+While disconnected the card shows one line, "assistant not running", and
+the input is disabled. `hello` on connect redraws the current conversation,
+so a daemon restart or a canvas reopened mid-reply catches up.
+
+## Layout
+
+A centred card, about 760px wide and 70% of the screen high, with the
+theme's surface colour and translucency.
+
+- **Header:** the model name, the context meter (`ctx` used of max, amber
+ at 75%, red at 90%, as llamachat does), a History button, a New button.
+- **Body:** a `ListView` of turns, following the bottom while a reply
+ streams unless the user has scrolled up.
+- **Footer:** a multi-line input. Enter sends, Shift+Enter inserts a
+ newline, Escape closes the card. While a reply streams, a Stop button
+ replaces Send.
+- **History:** a panel that slides over the body. A search field on top,
+ the conversation list below; each row is a title, a date and a delete
+ button. Clicking a row sends `open` and closes the panel. With text in
+ the field the list shows `results` with their snippets; clearing the
+ field shows `conversations` again. Escape closes the panel before it
+ closes the card.
+
+## Messages
+
+- `desktop/assistant/Md.js` splits a message into segments: prose, and
+ fenced code `{lang, text}`. An unclosed fence, which is normal while a
+ reply streams, yields a code segment marked open.
+- Prose renders in a read-only `TextEdit` with `textFormat:
+ TextEdit.MarkdownText`: selectable, unlike `Text`.
+- A code segment renders monospace on a tinted block with a copy button
+ that runs `wl-copy`. An open segment has no copy button yet.
+- User messages go through the same renderer.
+- Thinking (`think` deltas) shows as one collapsed `▸ thinking` line above
+ the reply, expanded on click, labelled live while it streams. A resumed
+ conversation has no thinking: the daemon does not store it.
+- A tool call shows as a chip with the tool's name, dimmed when `done`.
+- `error` shows as a line in `Theme.red`.
+
+Glyphs come from `Theme.iconFamily` and must exist in Inconsolata Nerd
+Font.
+
+## Switch-over
+
+- `git rm -r assistant/`, the voice overlay. AGENTS.md's tree line and the
+ `Socket` retry note's file reference move to `desktop/assistant/`.
+- `desktop/modules/ai/README.md`: the desktop-assistant row stays; the line
+ about status failing when the overlay is down goes.
+- hypr-theme (the live config, linked from `~/.config/hypr`):
+ `sections/autostart.lua` starts the daemon and drops the commented
+ overlay line, `llamachat --daemon` stays; `sections/keybindings.lua`
+ rebinds SUPER+Home to the IPC toggle; `sections/decorations.lua` gains
+ `blur-assistant`. Then `hyprctl reload`.
+- A new directory under `desktop/` is a new import, so the running desktop
+ shell needs a restart from the user's terminal (`./reload.sh desktop`).
+
+Order: the daemon first (testable alone with `socat`), then the canvas,
+then the switch-over. Work goes on master in all three repos.
+
+## Testing
+
+`node desktop/assistant/test_md.js`: plain prose, one fence, two fences,
+a fence with a language, an unclosed fence, inline backticks that are not a
+fence, a fence inside a list item. Visual checks are the user's: the card,
+streaming, the thinking line, copy, the history panel and search.