Every part of the interface, once.
What each user-facing part is called, where it lives on the screen, what it is for and what touching it does. Arranged the way a writer meets them: the frame around the page, writing, asking the agent, reading its answer, watching it work, talking to it, and the review of changes from outside.
None of the pictures are drawn here. Each one is the app's own component rendered with sample data, or the real editor with its own extensions put in that state, styled by the app's own CSS. Regenerate it with bun run features; when a component changes, so does its picture. The words come from scripts/features/catalog.tsx, and test/features.test.ts fails when a component exists that this page doesn't list.
The frame
What is always on the screen around a page: where you are, whether it is saved, and what is wrong with the connection.
Pages React component
WhereThe home screen, at /
The list of pages (the .md files in the docs folder), newest first.
Use it for
- Find a page to open, or start a new one.
When touched
- The gear: opens the settings dialog.
- New page: creates an empty page and opens it.
- A page's file name: opens it at /d/<id>. Its first line is beside it.
- The time is when the file last changed.
src/app/pages/Pages.tsxPages
No pages yet.
TopBar React component
WhereTop of a page, full width
Where you are and whether your words are safe: a way back, the page's title, and the save state.
Use it for
- Go back to all pages.
- Know at a glance whether the page is saved: nothing else in the app says it.
When touched
- ← : back to the list of pages.
- Copy page, beside the gear: copies the page for GitHub and Google Docs (see Copy page).
- The gear at the right end: opens the settings dialog.
- Save state changes by itself as you type: Unsaved changes → Saving… → Saved, or "Can't save, retrying…" in red when the server isn't answering.
src/app/pages/Frame.tsxA page from a newer Solipsist React component
WhereIn place of the page, when its file was saved by a newer build
A page whose format is newer than this build knows is shown read-only: nothing here can change it until Solipsist is updated.
Use it for
- Read a page a newer Solipsist saved, without risking it: no saving, no agents, no Sync.
When touched
- The banner names the page's format and the newest this build knows, and says to update. The top bar reads Read-only. The server refuses any write to the page (423) in case one is tried.
src/app/pages/NewerPage.tsxsrc/shared/docfile/file.tssrc/server/files.tsBanners React component
WhereUnder the top bar, one strip per problem
Strips that say what is wrong with the page's connection or file, with the one thing to do about it.
Use it for
- Another tab has the page open (only one may).
- The connection to the server is lost.
- The file changed elsewhere while you were typing.
When touched
- try again: reloads the page.
- Reload: takes the other version. Keep mine: keeps yours and writes it over theirs.
src/app/pages/Frame.tsxSupportNudge React component
WhereUnder the top bar, when a page opens
A quiet strip asking you to buy a licence, once you have written on support.after_days days (14 by default). Nothing is locked and nothing is sent anywhere: the count stays in support.json on this machine.
Use it for
- Buy a licence if Solipsist is useful to you.
- Say you already have one, or put it off.
When touched
- Buy a licence: opens the shop in a new tab.
- I've bought one: never asks again.
- Later: asks again after 7 more days of writing.
- It is checked only when a page opens, so it never appears while you write.
src/app/pages/Frame.tsxsrc/server/support.tsSettings gear React component
WhereRight end of the top bar, and in the header of the pages list
A gear that opens the settings dialog, from a page or from the list of pages.
Use it for
- Reach the prompts and the loaded settings without leaving the page you are writing.
When touched
- Click: opens the settings dialog over the page. Escape or the ✕ closes it.
src/app/pages/SettingsDialog.tsxsrc/app/pages/Frame.tsxsrc/app/pages/PagesView.tsxCopy page React component
WhereJust above the page, on its right
Copies the page as you see your own text (unsaved edits included), in two formats at once: markdown for GitHub and rich text for Google Docs. Markers, suggestions, margin comments and hand-written HTML comments are left out; a range's text stays.
Use it for
- Paste the page into a GitHub issue, PR or comment: the markdown keeps image paths as written (relative to the page's folder), which render when that folder is in the repo.
- Paste it into Google Docs: headings, lists, tables, code and links come across, and the images are embedded (SVG and other formats drawn as PNG), up to 8 MB of images in all; past that the rest are links to this server.
When touched
- Click: copies. Its label is always "Copy page as markdown".
- Copied (green check) for two seconds; its title says if any image was linked rather than embedded, and why.
- Couldn't copy (red) when the browser refused the clipboard; its title has the reason.
- No key: ⌥⌘C is the card's chat, and ⇧⌘C is the browser's inspector.
src/app/pages/CopyButton.tsxsrc/app/doc/copyPage.tssrc/app/pages/Sheet.tsxsrc/app/chrome.cssPrompts (settings dialog) React component
WhereThe settings dialog, first tab
Every instruction the agents are given, to read and change: the protocol, the prompt each run is sent, one prompt per kind of placeholder, and the chat prompts.
Use it for
- Change how the agents behave without editing the app: shorter answers, another voice, a house style for one kind of placeholder.
- See what the agents are actually told, with the slots the server fills in.
When touched
- A prompt in the list: opens it in the editor. "edited" marks a prompt whose file of yours is in use; "unsaved", one with a change not yet saved.
- Save: keeps the text as a file in your prompts folder (~/.config/solipsist/prompts). It is refused, with the reason, if it is empty or leaves out a required {slot}.
- Revert: drops the unsaved changes.
- Reset to default: deletes your file and brings the built-in text back.
- A change applies to the next run and the next agent started; one already running or waiting keeps what it began with.
- Closing with unsaved changes asks once.
src/app/pages/PromptsPane.tsxsrc/app/pages/SettingsDialog.tsxsrc/server/prompts.tssrc/app/settings.cssSettings
Protocol protocol
The system prompt of every agent: what a request is, the reply tools, and the rules. Read when an agent starts.
{guide}
A change applies to the next run and the next agent started; an agent already running or waiting keeps the instructions it began with.
Loaded /home/me/notes/solipsist.yaml
pages
- md_search_paths
- docs=/home/me/notes/docs default
server
- server.port
- 4000 file
- server.host
- localhost default
- server.allowed_hosts default
agent
- agent.gap_ms
- 1000 default
- agent.settle_ms
- 2000 default
- agent.single_agent
- false default
- agent.concurrency
- 2 AGENT_CONCURRENCY
- agent.max_runs
- 6 default
- agent.run_timeout_ms
- 600000 default
- agent.cost_limit_usd
- 5 file
- agent.cost_limit_day_usd
- 5 default
- agent.cost_limit_month_usd
- 50 default
- agent.max_unmetered_runs_day
- 40 default
- agent.wait_ms
- 300000 default
- agent.max_waiting
- 6 default
- agent.max_failures
- 3 default
- agent.preferred_models
- pi:openrouter/~deepseek/deepseek-flash-latest default
review
- review.on
- true default
- review.curator
- self default
- review.min_score
- 0 default
- review.min_kept
- 4 default
- review.kept_per_block
- 0.2 default
- review.max_per_review
- 3 default
- review.max_gloss_words
- 10 default
suggestions
- suggestions.max_chars
- 20000 default
- suggestions.max_edits
- 20 default
chat
- chat.max_message_chars
- 20000 default
pi
- pi.models
- openrouter/~deepseek/deepseek-flash-latestopenrouter/anthropic/claude-haiku-5.5openrouter/anthropic/claude-sonnet-5.5openrouter/~z-ai/glm-latestopenrouter/~moonshotai/kimi-latestopenrouter/google/gemini-3.5-flash default
- pi.tools
- readgrepfindlsbashwriteedit default
- pi.openrouter_key
- set SOLIPSIST_OPENROUTER_KEY
prompts
- prompts.dir
- /home/me/.config/solipsist/prompts default
comments
- comments.orphan_keep_ms
- 30000 default
support
- support.after_days
- 14 default
- support.dir
- /home/me/.config/solipsist default
log
- log.file
- /home/me/.solipsist/server.log default
- log.max_bytes
- 10485760 default
- log.tui
- true default
dev
- dev.mock_comments
- false default
- dev.mock_interval_ms
- 5000 default
Loaded settings (settings dialog) React component
WhereThe settings dialog, second tab
The settings the server is running with, by section, each with its value and where the value came from.
Use it for
- Check what is in effect: a value from the default, from solipsist.yaml, or from an environment variable (named).
- Find out why a setting isn't what you expected. A secret shows only as "set".
When touched
- Filter: narrows the list by key, environment name or description.
- Hover a key: what it does and its environment name.
- Read only: change settings in solipsist.yaml or the environment and restart.
src/app/pages/SettingsPane.tsxsrc/server/config.tssrc/app/settings.cssSettings
Protocol protocol
The system prompt of every agent: what a request is, the reply tools, and the rules. Read when an agent starts.
{guide}
A change applies to the next run and the next agent started; an agent already running or waiting keeps the instructions it began with.
Loaded /home/me/notes/solipsist.yaml
pages
- md_search_paths
- docs=/home/me/notes/docs default
server
- server.port
- 4000 file
- server.host
- localhost default
- server.allowed_hosts default
agent
- agent.gap_ms
- 1000 default
- agent.settle_ms
- 2000 default
- agent.single_agent
- false default
- agent.concurrency
- 2 AGENT_CONCURRENCY
- agent.max_runs
- 6 default
- agent.run_timeout_ms
- 600000 default
- agent.cost_limit_usd
- 5 file
- agent.cost_limit_day_usd
- 5 default
- agent.cost_limit_month_usd
- 50 default
- agent.max_unmetered_runs_day
- 40 default
- agent.wait_ms
- 300000 default
- agent.max_waiting
- 6 default
- agent.max_failures
- 3 default
- agent.preferred_models
- pi:openrouter/~deepseek/deepseek-flash-latest default
review
- review.on
- true default
- review.curator
- self default
- review.min_score
- 0 default
- review.min_kept
- 4 default
- review.kept_per_block
- 0.2 default
- review.max_per_review
- 3 default
- review.max_gloss_words
- 10 default
suggestions
- suggestions.max_chars
- 20000 default
- suggestions.max_edits
- 20 default
chat
- chat.max_message_chars
- 20000 default
pi
- pi.models
- openrouter/~deepseek/deepseek-flash-latestopenrouter/anthropic/claude-haiku-5.5openrouter/anthropic/claude-sonnet-5.5openrouter/~z-ai/glm-latestopenrouter/~moonshotai/kimi-latestopenrouter/google/gemini-3.5-flash default
- pi.tools
- readgrepfindlsbashwriteedit default
- pi.openrouter_key
- set SOLIPSIST_OPENROUTER_KEY
prompts
- prompts.dir
- /home/me/.config/solipsist/prompts default
comments
- comments.orphan_keep_ms
- 30000 default
support
- support.after_days
- 14 default
- support.dir
- /home/me/.config/solipsist default
log
- log.file
- /home/me/.solipsist/server.log default
- log.max_bytes
- 10485760 default
- log.tui
- true default
dev
- dev.mock_comments
- false default
- dev.mock_interval_ms
- 5000 default
Choose your files React component
WhereOver the home screen, on the first launch and from Add files
The markdown files md_search_paths found, to pick which ones Solipsist copies and syncs.
Use it for
- Say which of a project's files to work on. Nothing is created until you confirm.
When touched
- All: ticks or clears every file.
- Add N files: copies the ones ticked into .solipsist/.
- Cancel (Add files only): closes it.
src/app/pages/SetupDialog.tsxChoose your files
Found 3 markdown files, searching: *.md, docs
Files in subfolders? Add patterns like docs/**/*.md to md_search_paths in solipsist.yaml.
Sync and its dialog React component
WhereSync to file and Reload from file in the top bar; the dialog over the page
Sends the page to its original file, and asks first if the original changed since it was loaded.
Use it for
- Write your edits to the repo, or take in a newer original.
When touched
- Sync to file: writes the page over its original.
- Reload from file: merges the newer original with your edits.
- Overwrite the file: replaces the original.
- Discard my edits and load the file: when both changed the same text.
- Create it: when the original was deleted.
- Cancel: nothing is written.
src/app/pages/SyncDialog.tsxROADMAP.md changed since you loaded it. Syncing to the file now would replace those changes.
Connect a model React component
WhereOver the page, from the status bar or the ask key when no model can run
How to connect a model, instead of a request that can only fail.
Use it for
- Find out what the agent needs before it can answer.
When touched
- Close: closes it.
src/app/pages/ConnectModel.tsxConnect a model
The agent needs a model before it can answer. Any one of these will do, then restart Solipsist:
Set SOLIPSIST_OPENROUTER_KEY in your environment.
Run pi, then /login.
Writing
The page itself, and the small things that happen inside it while you type.
Sheet (the editor) Tiptap extension
WhereCentre of the screen: the page, in a serif at reading size
A Tiptap editor on one markdown file. What you type is saved to the .md file; nothing else is stored.
Use it for
- Write: headings, lists, tables, code, images, links; markdown shortcuts work as you type.
- Everything else in this file is something that happens in or beside this sheet.
When touched
- Typing saves after a short pause (see TopBar).
- Cmd/Ctrl-Z undoes your edits and your decisions on suggestions.
- The page is focused when it opens.
src/app/pages/Sheet.tsxsrc/app/editor/behaviour.tsPlan for Q3
The deadline is end of Q3, and the review is on the calendar.
Ship the editor
Write the docs
Team | Date |
|---|---|
Web | 3 Sep |
Vim mode Tiptap extension
WhereIn the sheet; switched from the status bar's left button
Optional Vim keys for the sheet: normal, insert, visual and visual-line modes, with a block cursor.
Use it for
- Move and edit without the mouse. Off by default (the status bar says Standard).
When touched
- Click the mode button in the status bar: Vim on or off.
- Esc (or Ctrl-[): back to normal. i, a, I, A, o, O: insert. v, V: visual. h j k l, w b e, 0 ^ $, gg G, { }, Ctrl-d / Ctrl-u (half a screen down / up, in visual mode extending the selection), counts, and the operators d, c, y with x, s, p.
- On a suggestion: ga accepts, gr rejects, gc opens its chat.
src/app/editor/vim.tsThe cursor is a block in normal mode.
New-block line ProseMirror decoration
WhereLeft of a block that just arrived from outside
A block added by another editor or by the loop gets a line down its left edge, so you can see what is new.
Use it for
- See at a glance what appeared while you were away.
- Throw a new block away: hover its line and click the cross.
When touched
- Hover the line: a cross appears. Click it: the block is deleted (an ordinary edit: Undo brings it back).
src/app/editor/newBlocks.tsAn ordinary paragraph.
This paragraph arrived from outside.
Another ordinary one.
Fresh text ProseMirror decoration
WhereInline in the sheet
Text that arrived from outside fades in, so the eye catches it.
Use it for
- Notice a change without a notification: the words glow for a moment, then settle.
src/app/editor/freshText.tsThe deadline is end of Q3, and this sentence just arrived.
HTML comment chip Tiptap extension
WhereIn the sheet, where a hand-written <!-- … --> comment is
A comment you wrote in the markdown (not one of ours) shows as a small chip with its first words; the file keeps it byte for byte.
Use it for
- Leave notes to yourself in the file without them showing as page text.
When touched
- Hover: the whole comment is the tooltip. The chip can't be typed into; delete it as a unit.
src/app/editor/htmlCommentChips.tsCheck the date ask finance before Friday before sending.
The next paragraph.
Margin comments React component
WhereLeft margin, level with the highlighted passage
Questions about a passage, as cards beside it (Google Docs style). Closed, a card is its gloss: the two-to-five-word note a reader pencils in the margin.
Use it for
- Read a question about a passage without leaving the page.
- Take one down (Dismiss) when you have considered it: the Reader never raises that passage again.
When touched
- Click a highlighted passage, or its card: the question opens in a window of its own, and the card counts as read, which keeps a better question from taking its place.
- A card whose question carries a picture shows a small square; the picture itself is in the window.
- Questions on nearby lines share the room around their passages and never cover each other. A click on a highlight inside a block a suggestion would change opens the question, not the suggestion's card.
src/app/pages/Margin.tsxsrc/server/review/index.tssrc/server/place.tsPage review React component
WhereStatus bar or agent panel (the button); the left margin and the sheet (the questions)
A reviewer reads the page and leaves questions beside the passages it can't follow. It writes nothing in the page: a question is a note, not a change.
Use it for
- Press Page review to have the page read like a reader would: what is unclear, unsupported or missing.
- See where each question is about: the passage is underlined, and its card sits in the left margin.
- Open a question to read it in full, take it down (Dismiss) or carry it into the chat (Ask).
When touched
- Page review blinks and reads “Reviewing…” while it runs; its steps are in the agent panel, and when it ends the panel says what became of every question.
- A highlighted passage or its card opens the question. With room, the popover hangs in the margin beside the passage; on a laptop it opens just under it. A thin line joins it to the passage and the rest of the page steps back.
- The status bar counts the questions, which matters when the window is too narrow for the margin.
- Escape, a click away or ✕ closes it. Questions are stored in the page's hidden block and never change the text.
src/app/pages/StatusBar.tsxsrc/app/pages/DebugPanel.tsxsrc/app/pages/Margin.tsxsrc/app/pages/CommentModal.tsxsrc/server/review/index.tsWhy small teams ship faster
Adding engineers to a late project makes it later, and yet we keep hiring.
The alternative is duller than it sounds. You cut scope until the thing fits in one head, and you let that head decide.
None of this is new. It is just rarely done.
A question, opened React component
WhereOver the page, from a margin card or a highlighted passage
One review question in full: the passage it is about, the point, the reviewer's reasoning, the picture it drew, and who asked.
Use it for
- Read the whole question, which never fits in the margin.
- See which reviewer and which model asked it — the same question from a small model and a large one is not the same question.
- Take it down (Dismiss), or carry it into the chat (Ask).
When touched
- Escape, the backdrop or ✕ closes it; the margin keeps its cards where they are.
- Dismiss: the question goes for good, and that passage is never raised again.
- There is no Accept or Reject: a question puts nothing in the page, so there is nothing to accept.
src/app/pages/CommentModal.tsxQuestion
Fiscal or calendar: which Q3 is this?
reviewer · deepseek-v4-flash
The deadline is the end of Q3 for all teams.
The date carries the plan and the page never says which.
Both teams read this, and they keep different calendars, so one of them will read it the wrong way. Which one did you mean?
Asking the agent
How a writer hands the agent a task from inside the text, and what the page shows while it is picked up and worked on.
Completion point (gen) Tiptap extension
WhereInline in the sheet, at the caret when you pressed ⌘.
A spot where the writer asked the agent to decide what belongs (text, a list, a table, an image).
Use it for
- Hand over a gap: put the caret where the answer should go and press ⌘. (Ctrl-. on other systems).
When touched
- ⌘.: inserts the point at the caret; the agent picks it up.
- It moves through four states: waiting, being worked on, a suggestion waiting, and done (nothing left to show). Its picture changes with each; when the answer is ready the picture goes and the suggestion shows in its place.
src/plugins/gen/index.tssrc/app/editor/pointView.tssrc/app/editor/markers/loader.tssrc/app/editor/markers/indicators.tssrc/app/editor/markers/registry.tsThe deadline is for all teams.
The deadline is for all teams.
The deadline is for all teams.
Request range (sel) Tiptap extension
WhereInline in the sheet, around the text that was selected when you pressed ⌘.
Text the writer asked the agent about or to change, with an optional instruction ("make it shorter").
Use it for
- Select text and press ⌘.: ask or tell the agent something about it. Type the instruction, Enter, and it is sent.
When touched
- ⌘. on a selection: opens the instruction input under it; Enter sends, Esc cancels.
- Click its loader (pending): reopens the instruction to read or change it.
- A selection that can't be marked says why under it: nothing selected, part of it already has a request, it holds a code block, or it starts or ends inside inline code.
src/plugins/sel/index.tssrc/app/editor/rangeLoaders.tssrc/app/editor/markerCommands.tsPlease check the end of Q3 date before we send it.
Please check the end of Q3 date before we send it.
Image request (img) Tiptap extension
WhereAround an image in the sheet, with a hint in the image's corner while it is selected
An image the writer asked the agent to draw again, with what to change ("make the bars horizontal"). The agent writes a new file and suggests it in the old one's place.
Use it for
- Change a picture without drawing it: select the image and press ⌘., then say what to change.
- In vim, `v` or `V` on the image's line selects it; otherwise click it or drag over it.
When touched
- While the selection holds one image: the image gets a dashed ring and "⌘. to change" in its corner. A selection of text that happens to hold an image is still a request about the text.
- ⌘. on it: opens the instruction input over the image. An instruction is required: Enter with nothing typed shakes the box.
- An image already being asked about says so instead of being asked about twice.
- The suggestion is the new image where the old one is: the old one dimmed and ringed, the new one beside it (Accept, Reject, Ask again, Chat as for any other).
src/plugins/img/index.tssrc/app/editor/imageTargets.tsSignups have risen every week.
Instruction input
WhereA popup under the selection (or under a request's loader)
One line that grows as it wraps: what the writer says to the agent about the selected text.
Use it for
- Tell the agent what you want done with the text, or ask a question about it.
- Also opens again from the suggestion card's Ask again, with the old instruction in it.
When touched
- Enter or Shift+Enter: sends (an instruction is one line).
- Esc, or a click away: closes without sending.
- Enter with nothing typed when one is required: the box shakes and nothing is sent.
- 500 characters at most.
src/app/editor/instructionInput.tssrc/app/editor/markers/popup.tsReading its answer
What the agent's result looks like in the page, and the ways to accept, reject or send it back.
Suggestion preview ProseMirror decoration
WhereIn the sheet, where the answer would go
The agent's result drawn where it would land, marked, while the page itself stays unchanged until you accept.
Use it for
- Read the answer in context: inline text, whole blocks, or a replacement shown against the old words.
When touched
- Hover: the card appears beside it. Click: the card is pinned until Esc or a click away.
- Nothing is written into the page until Accept.
src/app/editor/suggestions.tsThe deadline is for all teams.
Plan
After.
Please check the end of Q3 date today.
Check end of Q3 here.
Declined and answered chips ProseMirror decoration
WhereIn the sheet, in place of a preview
When the agent has nothing to put in the page, the marker says so: it declined (with its reason), or it answered a question about the text.
Use it for
- See why nothing was written, and read an answer that is not meant to go into the page.
When touched
- Declined: Dismiss takes the marker out; Ask again sends it back.
- Answered: Done takes the marker out; Ask again asks again.
src/app/editor/suggestions.tsA b.
Please check the end of Q3 date.
Suggestion card
WhereRight margin, beside the diff (a floating card)
What the agent says about its result, and the buttons to decide.
Use it for
- Decide: Accept puts the result in the page; Reject leaves the page as it is; Ask again turns it down and asks for another.
- On a request about selected text, ▾ beside Accept offers Accept as a Button: the result goes in, with a button above it to run the request again.
- Talk to the agent that made it (Chat).
When touched
- Accept ⌥⌘Y · Reject ⌥⌘N · Chat ⌥⌘C (vim: gc) · next ⌥⌘] · previous ⌥⌘[ .
- ▾ (on a request that can have a button) opens a menu under it. A result that is one piece of text in place: Accept as a Button (see Accept as a Button). One that isn't (it changes other parts of the page, deletes the text, holds new requests, or starts or ends with a code block): Ask again as a button, saying which, and the agent is asked for one that can be. Asked for as a button, the card leads with Accept as a Button and ▾ holds Accept without a button. ▾ again, Esc or a click away closes the menu.
- Ask again on a request with an instruction opens the instruction input first.
- Esc closes the dropdown, then a pinned card; a click away closes it too.
- A decision is your own edit: saved with the next save, undone with Undo.
src/app/editor/suggestions.tssrc/app/editor/sideCard.tsUsed the plan's own date.
- Changes a paragraph
Nothing says what goes here.
Yes: the plan says 30 September.
Accept as a Button
WhereA popup under the diff, from ▾ beside a suggestion's Accept
Says what a button does before the result becomes one: a press runs the request again and its result goes straight into the page.
Use it for
- Keep a result you will want redone (today's figures, the current time, a summary of a section that grows), with a button to redo it.
When touched
- Accept as a Button: the result goes in, and a button appears above it (see Request button).
- Cancel, Esc or a click away: nothing changes; the suggestion still waits.
src/app/editor/suggestions.tsRequest button ProseMirror decoration
WhereIn the sheet, on its own line above the text a request's button holds
A result the writer kept as a button. The text is ordinary text; the button runs its request again, and the new result replaces it without a diff.
Use it for
- Redo the request on the text as it is now.
- Change what it asks for.
- Have it redo itself on a schedule, page open or not (today's figures, the time).
- Take the button off and keep the text.
When touched
- Press: runs the request again at once, with its own instruction (no input). While it runs the text shows as a waiting request.
- The new result goes straight in, with no fade or new-block line, and the button comes back; its margin note says when it last ran (Last run 20:59; hover for the next scheduled run). A decline, an answer, or a result for text you changed during the run waits on its card instead; deciding it brings the button back.
- Hover: the text it holds is highlighted, and ✎, ⏱ and × show.
- ✎: the instruction input, filled in; Enter keeps the new instruction (it doesn't run).
- ⏱: a menu, Only when pressed or every minute, 5 or 15 minutes, hour or day. The server runs a schedule, page open or not, as if you pressed it (on any engine; the page's agent switch and the cost limits still hold), and the button says how often (⏱ every 5 minutes; hover it for the next run). A run that ends on a card waits for you, and the schedule with it.
- ×: removes the button, keeps the text (Undo brings it back).
- Sync writes only the text: the button stays in the working copy.
src/app/editor/taskButtons.tssrc/app/page.cssThe time is now half past three.
The next paragraph.
The time is now half past three.
Risks:
late data
a missed step
Suggestion count React component
WhereStatus bar, right side (only while suggestions wait)
How many suggestions wait in the page, and a menu to go through them.
Use it for
- Know there is something to read; step through them; accept or reject them all at once.
When touched
- Click: opens the menu: Next, Accept all, Reject all.
- ⌥⌘] / ⌥⌘[ : next / previous from anywhere in the page.
src/app/pages/SuggestionCount.tsxWatching the agent
Quiet signs of what the agents are doing, and the panels that show everything.
Agent pill (margin note) React component
WhereRight margin, level with each placeholder's marker
One line beside a placeholder that says where its agent is: waiting to be picked up, working (with its latest step), done, declined (with the agent's reason), asleep, or in a chat. After you accept its result it stays beside where the result landed, saying Accepted (Kept as a button beside a button), for as long as the page is open.
Use it for
- See, without opening anything, that the agent is on it, what it is doing, and when it is done.
When touched
- Click (or Enter): opens the chat with that agent, wherever there is one to talk to (done, asleep, in chat, accepted, or a run a Pi agent is working).
- Hover: the whole step (a tool call's arguments, a result) in a panel under the pill.
- Each state has its own icon and motion (see Primitives).
src/app/pages/AgentFeed.tsxsrc/app/pages/NoteIcon.tsx{"file_path": "/docs/plan.md"}The agent asked for permission (Write …), which can't be answered here
Engine marks React component
WherePills, the debug panel's header, the page-chat button
The mark of the engine that runs an agent: Pi's pixel mark.
Use it for
- Tell at a glance that an agent is at work, and which engine it runs on.
src/app/pages/EngineIcon.tsxsrc/app/pages/PiIcon.tsxsrc/app/editor/logo.tsStatus bar React component
WhereBottom of the screen, full width
Like an IDE's: editing mode, the model answering, single-agent mode, what the page has cost, the agent panel, and where the caret is.
Use it for
- Switch between Standard and Vim editing.
- See which model is answering on this page, whether one lasting agent handles every request, and what the page's agents have cost since you opened it.
- Open the agent panel; see suggestions waiting; the caret's line and column; the word count; which version of Solipsist is serving the page.
When touched
- Mode button: Vim on/off.
- Version (last, e.g. v0.1.0; v0.1.0-dev from source): its title is the whole `solipsist --version` line, to give in a bug report.
- Model: opens the agent panel, where the model is chosen and the agents are turned off and on.
- Page review: one review, which leaves questions in the margin and writes nothing in the page. It blinks and reads “Reviewing…” while the run is in flight, and its title says so when a review raised nothing.
- Debug: opens the same panel (its dot shows the agents' state).
- In Vim, typed counts and operators show beside the mode (e.g. 2d).
src/app/pages/StatusBar.tsxDebug panel React component
WhereRight edge of the screen, opened from the status bar
Everything the page's agents say, as it happens: the state, the runs, every step.
Use it for
- See why nothing is happening, or what a run did, step by step.
- Choose this page's engine and model (the picker); turn the page's agents off and on; clear the log.
When touched
- Model picker: changes this page's model (saved in its file); a run in flight finishes on the old one.
- Agent on/off: stops or starts this page's agents (kept in the page's file, so a reload and every other tab agree; a run in flight stops).
- Page review: one review, which leaves questions in the margin and writes nothing in the page. When it ends, the panel says what became of every question it raised.
- Run tabs: show one run's messages; ‹ › cycle through them.
- Clear: empties the log. ✕: closes the panel.
src/app/pages/DebugPanel.tsxModel picker React component
WhereDebug panel header, and the page chat's header
The model this page's agents run on: a shortlist at a glance — your preferred models first, then each engine's — and a search over every model your engines can run, which for Pi is every model your own Pi has credentials for.
Use it for
- Choose which engine and model this page's agents use; the page-wide chat uses the same one.
- Type to search the whole catalog by name, vendor or id, beyond the few the shortlist shows.
- Read what a model holds and what a million tokens cost before picking it.
When touched
- Choosing saves the page's setting. A run in flight finishes on the old model; old agents keep their own engine.
- ↑ ↓ move, Enter picks, Escape closes, and so does a click outside.
- A model whose engine isn't set up is listed but can't be chosen, and says why on hover.
- `agent.preferred_models` in solipsist.yaml pins models to the top under Preferred; the first that can run is a new page's default.
src/app/pages/ModelPicker.tsxTalking to it
The chat window: the page-wide chat, and the chat behind a suggestion.
Page chat button React component
WhereTop-right corner of the sheet
Opens a chat about the whole page with the engine this page is on, and shows how that chat's agent is.
Use it for
- Ask a question about the page, or ask for changes (they come back as suggestions on the page). The conversation is kept: opening it again goes on where it was.
- See at a glance whether the page chat is working while its window is closed: quiet (no agent), a little brighter (snoozed, conversation kept), a breathing glow (agent up, or the chat open), a light running round the edge (replying), a dot (a reply came while it was closed).
When touched
- Click: opens the chat window. Its mark is the page's engine.
- Its state comes from the page's agent stream (`pichat` events, `pageChat` in the hello). Under reduced motion it holds still and shows the state by colour.
src/app/pages/ChatLaunch.tsxsrc/app/pages/Sheet.tsxsrc/app/pages/EngineIcon.tsxsrc/server/agent/pageChatStatus.tsChat window React component
WhereA window over the page
A conversation with an agent: what you say, what it does (folded), and what it answers.
Use it for
- Talk to the agent behind a suggestion (from its card or its pill), or about the whole page.
- Look in on a run that is still going.
When touched
- A call to one of Solipsist's own tools (suggest, answer, decline) is shown apart from the agent's own work, as the result it gave; the agent's calls fold away into one line of work.
- Enter sends · Shift+Enter new line · Esc closes (also the ✕ and a click outside).
- Stop (while it replies): stops the reply, keeps the conversation.
- Send while it replies (an engine that takes it, Pi): the message is queued and the agent reads it after its current step; the same reply answers it. Closing the chat (Esc, a click outside) leaves the reply going.
- The page chat's header has the model picker (changing it starts a new chat on that model) and New chat (forgets the conversation and starts over).
- Closing the page chat leaves a reply going (its suggestion still lands on the page); opening it again shows the conversation where it is. Left alone, it snoozes and is taken up again on the next open.
- While it looks in on a run, the box is disabled until the run ends.
src/app/pages/ChatModal.tsxSuggestion · plan.md
Task from Solipsist (18 tokens)
You are working on the page /docs/plan.md. Your placeholder is gen:abc …
Thought · 1 tool
Thinking The writer wants a date; the plan names one in the first section.
The writer wants a date; the plan names one in the first section.
Read/docs/plan.md40 ms
{
"file_path": "/docs/plan.md"
}# Plan The deadline is end of Q3 …
Done.
Could it say the weekday too?
Worked for 2s · 2 tools · 1 failed
Bashdate -j -f %Y-%m-%d 2026-09-30 +%A120 ms
{
"file_path": "date -j -f %Y-%m-%d 2026-09-30 +%A"
}date: illegal option
WebSearchweekday of 30 September 20261.4 s
{
"file_path": "weekday of 30 September 2026"
}Wednesday
Running Read…
Read/docs/notes.md
{}Chat with Pi
Could it say the weekday too?
The deadline is on 30 September.
Suggestion · plan.md
Could it be shorter?
Shorter, then.
Suggestion · plan.md
No conversation yet.
Suggestion · plan.md
Task from Solipsist (18 tokens)
You are working on the page /docs/plan.md. Your placeholder is gen:abc …
Running Read…
Read/docs/notes.md
{}Suggestion · plan.md
Task from Solipsist (18 tokens)
You are working on the page /docs/plan.md. Your placeholder is gen:abc …
Thought · 1 tool
Thinking The writer wants a date; the plan names one in the first section.
The writer wants a date; the plan names one in the first section.
Read/docs/plan.md40 ms
{
"file_path": "/docs/plan.md"
}# Plan The deadline is end of Q3 …
Done.
Could it say the weekday too?
Worked for 2s · 2 tools · 1 failed
Bashdate -j -f %Y-%m-%d 2026-09-30 +%A120 ms
{
"file_path": "date -j -f %Y-%m-%d 2026-09-30 +%A"
}date: illegal option
WebSearchweekday of 30 September 20261.4 s
{
"file_path": "weekday of 30 September 2026"
}Wednesday
Running Read…
Read/docs/notes.md
{}Sent mid-reply: “keep it short”. It reads this after its current step.
Suggestion · plan.md
No agent was kept for this suggestion: its engine can't keep a conversation, or it isn't set up now.
Chat log parts React component
WhereInside the chat window's log
The kinds of thing in a conversation, each shown its own way.
Use it for
- Read the answer first; look at the work only if you want to.
When touched
- Task from Solipsist: folded; opens to the prompt the agent was sent.
- Worked for 5s · 2 tools: folded work; open while it streams, and when a tool failed.
- A tool: its arguments and result open under it.
- Envelopes (suggestion, edit, answer, note, declined) are set apart from prose.
src/app/pages/ChatModal.tsxRead/docs/plan.md
{}Read/docs/plan.md40 ms
{}# Plan …
Bashdate -j …1.2 s
{}date: illegal option
Here you go.
Your suggestion was updated on the page.
Another run started on this placeholder.
Primitives
The small parts everything above is made of: buttons, key chips, dots, spinners and the motion they use.
Buttons CSS pattern
WhereEverywhere
Three variants: primary (rare, one per surface), the default, and ghost. An icon button is square.
Use it for
- Primary: the one thing to do next (Accept, Send, New page). Ghost: a quiet alternative (Reject, Clear, Close).
src/app/chrome.csssrc/app/margin.cssKey chip CSS pattern
WhereNext to the action a key performs
A small raised chip for a key: shortcuts are shown, not shouted.
Use it for
- Show the key for an action beside it, in the chat's footer and on buttons.
src/app/chrome.csssrc/app/tokens.cssStatus dots and tags CSS pattern
WhereStatus bar, chat header, debug panel, run tabs
A 6-pixel dot says live, fine or wrong; the live one breathes. Tags are tinted, never filled.
Use it for
- Say a state in a glance: live (breathing), ok, error, idle.
src/app/chrome.cssSpinners and motion
WhereWherever work is waiting or in progress
Every indicator that moves, and what moves it. SVG ones animate themselves; the rest are CSS.
Use it for
- Placeholder pending: a slow-fading dot. Placeholder working: a turning arc. A pill's icons: a turning clock hand, a breathing mark, a check that draws itself, a floating z, rising dots. Chat: a caret while the agent thinks; a ring while a tool runs.
When touched
- All motion stops for people who prefer reduced motion.
src/app/editor/markers/indicators.tssrc/app/margin.csssrc/app/chat.csssrc/app/pages/NoteIcon.tsxRead/docs/plan.md
Keyboard
Every shortcut, and where it works. On Linux and Windows ⌘ is Ctrl and ⌥ is Alt; the app's own hints name your keyboard's keys.
| ⌘ . | Anywhere in the page | Ask the agent: at the caret it adds a completion point; on a selection it opens the request box; on a selected image, the box to change the image (src/plugins/*/index.ts, markerCommands.ts) |
| ⌥⌘ Y | Caret on a suggestion | Accept it |
| ⌥⌘ N | Caret on a suggestion | Reject it |
| ⌥⌘ C | Caret on a suggestion | Chat with the agent that made it |
| ⌥⌘ ] · ⌥⌘ [ | Anywhere in the page | Go to the next · previous suggestion |
| esc | A pinned card, an input, the chat | Close it (the request box: cancel) |
| ↵ · ⇧↵ | The request box | Send (an instruction is one line) |
| ↵ · ⇧↵ | The chat's box | Send · new line |
| ⌘ Z | The page | Undo, including a decision on a suggestion |
| ga · gr · gc | Vim normal mode, caret on a suggestion | Accept · reject · chat |
| esc · ctrl-[ | Vim insert or visual mode | Back to normal mode |
Generated from the code. Fonts load from node_modules when this file is opened from the repository.
Question
Brooks's law, stated as a fact
reviewer · deepseek-v4-flash
This is Brooks's law, written as if it were always true. Readers will want to know it is an observation.
The next clause carries the real argument, about why managers hire anyway. Naming Brooks, or softening to “tends to”, keeps it from resting on an overstated rule.