Skip to the content.

πŸ’¬ Chat & UX design

← Home

NanoResearch’s UI is one chat, one sidebar. There are no buttons for β€œstart”, β€œsave profile”, or β€œsubmit feedback” β€” every action is a natural-language message in the chat.

Layout

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  NanoResearch                       demo Β· ready β”‚  Profile       β”‚
β”‚                                                  β”‚  ─────────     β”‚
β”‚  πŸ’¬ Chat thread (assistant + user bubbles)       β”‚  archetype     β”‚
β”‚                                                  β”‚  domain        β”‚
β”‚  β–Έ user msg                                      β”‚                β”‚
β”‚      β—‚ assistant narration                       β”‚  Pipeline      β”‚
β”‚      β—‚ another narration                         β”‚  ●○○○○○        β”‚
β”‚      β—‚ paper-ready link                          β”‚                β”‚
β”‚                                                  β”‚  What I've     β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”‚  learned       β”‚
β”‚  β”‚ tell me a topic, or refine your profile…   β”‚  β”‚  3 skills      β”‚
β”‚  β”‚                                        SENDβ”‚  β”‚  5 memories    β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β”‚                β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Conversational flow

flowchart TD
  Start([User opens UI]) --> Hello[Assistant greets +<br/>asks for name + field]
  Hello --> User1[User describes themselves]
  User1 --> Intent[/POST /api/intent/]
  Intent -->|create_user| Saved[Profile saved + selected]
  Saved --> Ask[Assistant: ready for a topic]
  Ask --> User2[User: 'start a run on X']
  User2 --> Intent2[/POST /api/intent/]
  Intent2 -->|start_run| Run[/POST /api/runs/]
  Run --> SSE{SSE stream open}
  SSE -->|narration| Bubble1[Assistant bubble appears]
  SSE -->|narration| Bubble2[Assistant bubble appears]
  SSE -->|awaiting_feedback| Pause[Pause for feedback]
  Pause --> User3[User types feedback]
  User3 --> Intent3[/POST /api/intent/]
  Intent3 -->|submit_feedback| FB[/POST /feedback/]
  FB --> SSE
  SSE -->|paper_ready| Link[Assistant: πŸ“„ download link]
  Link --> Done([User downloads paper.tex / paper.pdf])

Why no slash commands?

We support /help, /start, etc. as a fast path, but they’re documented only via /help and never required. Every slash command is also expressible in natural English; the backend’s intent classifier (POST /api/intent) hands either form off to the same action enum.

This means:

Narrations vs. raw events

Each pipeline event the backend pushes onto the SSE queue is fanned out as two separate events:

  1. The technical trajectory_event β€” keys like label, detail, metadata. Available to UIs that want the granular view.
  2. A narration event β€” a single human-readable text field that the chat renders directly as an assistant bubble.

The Narrator is a pure function in api/narrator.py β€” no LLM, no extra latency, just an event-label β†’ English string table. Easy to localise later (swap the table per locale).

State persistence

Browser-side, we persist via localStorage:

Key Purpose
nano.userId Active profile id
nano.runId Active run id (auto-cleared when run terminates)
nano.chat.thread The visible chat history (last 200 turns)

This lets a user refresh the page mid-run and pick up where they left off in both the chat thread and the sidebar status.

Markdown subset rendered in chat

The chat renders a tiny, fast, dependency-free markdown subset:

No tables, no headings, no code-fences. Keeps the chat dense and on-brand.

Card Refresh policy
Profile Updates on selectUser / upsertUser
Pipeline Polled every 8 s while run is non-terminal; stops on completed/failed
What I’ve learned about you Polled every 15 s while run is live; static otherwise

The pipeline card shows six dots (ideation β†’ planning β†’ coding β†’ analysis β†’ writing β†’ review) β€” done = green, active = amber pulse, awaiting feedback = sky-blue pulse with a β€œneeds feedback” badge.