aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/specs/2026-10-16-assistant-canvas-design.md
blob: 4df55628adf2585d15d09c665cc591d2591bdac1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
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.