aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanilo M. <danix@danix.xyz>2026-10-16 14:56:56 +0200
committerDanilo M. <danix@danix.xyz>2026-10-16 14:56:56 +0200
commitab05d5bbb89745f1e7cb1615a6da305577aff864 (patch)
tree74a2d34ee3962c0154fd0c1f2296a3ea6b982ea5
parent94f12dc0e14b5e671965bee8fd664fed95c69d0b (diff)
downloadquickshell-ab05d5bbb89745f1e7cb1615a6da305577aff864.tar.gz
quickshell-ab05d5bbb89745f1e7cb1615a6da305577aff864.zip
docs: spec the entry line and file drop on the island
Three card states: an entry line, a file state offering what to do with dropped files, and the chat. A drop always starts a new task, and asking about a file is one of the choices rather than the only one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
-rw-r--r--docs/superpowers/specs/2026-10-16-file-drop-design.md92
1 files changed, 92 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-10-16-file-drop-design.md b/docs/superpowers/specs/2026-10-16-file-drop-design.md
new file mode 100644
index 0000000..d3c8a9d
--- /dev/null
+++ b/docs/superpowers/specs/2026-10-16-file-drop-design.md
@@ -0,0 +1,92 @@
+# File drop and the entry line: design
+
+Date: 2026-10-16. Status: approved in brainstorming, not implemented.
+
+## Goal
+
+SUPER+Home opens a single line, "How can I help you?", which grows into the
+chat once a question is asked. A file dragged onto the island opens a middle
+state offering what can be done with it, and asking about it is one of
+those choices, not the only one. This follows Modesty's island drop (read
+for ideas only; Modesty is GPLv3).
+
+The daemon side (files in `ask`, extraction, history) is desktop-assistant's
+`docs/superpowers/specs/2026-10-16-attachments-design.md`.
+
+This is piece 1 of three. Piece 2 fills the file state's **Ask** row with
+per-type model prompts, piece 3 its **Do** row with local file operations
+(PDF to markdown, merge, video to audio, format or GIF, trackcrop). Each
+gets its own spec.
+
+## Three states
+
+| state | when | the card shows |
+| --- | --- | --- |
+| entry | no turns, nothing staged | one line: "How can I help you?" |
+| file | files staged, no turns | the file chips, the action rows, the input ("Ask about report.pdf…"), **Chat about it** |
+| chat | the conversation has turns | the chat as today |
+
+The card stays centred, with the dim backdrop in every state. Its height
+animates (about 180 ms) between states, growing from the centre.
+
+- **Opening.** SUPER+Home shows the chat if the current conversation was
+ active (a `user` or `done` event) in the last 10 minutes. Otherwise the
+ canvas sends `new`, and the empty conversation is the entry state. The
+ old conversation stays in History. The 10 minutes are a constant, not a
+ preference.
+- **Entry to chat.** Enter on a typed question sends `ask`; its `user`
+ event adds a turn, which is the chat state.
+- **A drop** always starts a new task: the canvas sends `new`, stages the
+ files and shows the file state, even over a recent conversation.
+- **File state.** Each chip has a ×; removing the last returns to entry.
+ Enter on a typed question sends `ask {text, files}` and clears the chips.
+ **Chat about it** moves to the chat layout with the files still staged
+ and focus in the input, sending nothing. In piece 1 the action rows hold
+ only Chat about it. A file of a kind chat does not take (video, archive)
+ shows "chat supports text, images and PDF" on its chip; while any such
+ chip is staged, Chat about it and the input are disabled (removing it
+ enables them).
+- **Results of a local operation** (piece 3) report in the file state and
+ never turn it into a chat.
+- Escape closes the card in every state, after the history panel.
+
+Sent files show as chips under the question in the transcript, with the
+`truncated` mark from the daemon's `files` list.
+
+## File kinds
+
+`desktop/assistant/Files.js` maps a path to `text`, `image`, `pdf`,
+`video`, `archive` or `other` by extension, with the same text, code and
+image lists as the daemon. It also turns a dropped URL into a path:
+`file://` URLs are decoded, anything else is ignored.
+
+## The island receptacle
+
+In `desktop/island/Island.qml`:
+
+- one `DropArea` spans the sliver and the space for a bubble below it;
+- a drag entering with URLs and a copy action sets `dropHold`, which shows
+ a bubble, "Drop for the assistant", and adds the bubble to the input
+ mask so the drop can land on it;
+- leaving clears `dropHold`;
+- a drop converts the URLs, calls `asst.attach(paths)` and accepts the
+ copy. With no file URLs it is refused.
+
+`shell.qml` passes the canvas as `asst: assistant`, never under the
+canvas's own id name (AGENTS.md: a property named like the enclosing id
+binds to itself).
+
+Wayland reports a drag only once it enters one of the island's input
+regions, which is why the drop begins on the sliver.
+
+## Testing
+
+- `node desktop/assistant/test_files.js`: kinds per extension, case
+ folding, files with no extension, URL decoding with spaces and non-ASCII
+ names, non-file URLs dropped.
+- The scratch harness load check, as for the canvas.
+- By hand: drag a file over the sliver and see the bubble; drop it and get
+ the file state; remove the chip and get entry; drop again and use Chat
+ about it; ask about a PDF and an image; see chips in the transcript;
+ drop a video and see the refusal; SUPER+Home after more than 10 minutes
+ gives entry, within 10 minutes the chat.