# Conversations

> How the web UI is organized and used day to day: conversations, models, directories, the composer, recordings, subagents, diffs, terminals, and context.

Shelley's UI is a list of conversations on the left and the current one on
the right: transcript, a status line, and the composer. The header has
buttons for the diff viewer, the git graph, the terminal, a new conversation,
and an overflow menu. Most things are also in the command menu
(<kbd>Ctrl</kbd>+<kbd>K</kbd>, or <kbd>⌘</kbd>+<kbd>K</kbd> on a Mac).

## One conversation, one agent

Each conversation is its own agent loop with its own model, reasoning level,
tool settings, and working directory. Several can work at once; they don't
share context. A conversation lives at `/c/<slug>`, where the slug is
generated from your first message. Rename it from its row menu or with
`/rename <new-slug>`.

- **New**: the **+** button, or `/new [first message]`.
- **Drafts**: a new conversation's unsent text is saved on the server and
  shows up in the list as *draft*, so it follows you to another device.
  Unsent text in an existing conversation is kept in the browser's local
  storage.
- **Fork**: `/fork`, or *Fork conversation from here* on any message, copies
  the conversation up to that point into a new one.
- **Archive**: the row menu, `/archive`, or <kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>X</kbd>.
  *View Archived* at the bottom of the list restores or permanently deletes.
- **Search**: the magnifier above the list searches message text and slugs
  across active and archived conversations. Type `tag:` to filter by tag;
  tags are set from the row menu. The list can also be grouped by directory,
  git repository, or tag.
- **Export**: <kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>E</kbd> opens the
  conversation as editable Markdown you can download.

Conversations, messages, and settings are stored in the SQLite database you
pass with `--db`. It runs in WAL mode, so expect `shelley.db-wal` and
`shelley.db-shm` next to it.

## Model, reasoning, tools, and profiles

Click the model name in the status line (or the picker above the composer,
before the first message). The picker sets:

- **Model**: any model Shelley has configured. See [Models and API keys](/docs/models).
- **Reasoning effort**: one of `off`, `minimal`, `low`, `medium`, `high`,
  `xhigh`, `max`, limited to the levels the model supports, with the
  model's default preselected (*auto* appears when Shelley can't tell what
  the default is). The model's thinking shows in the transcript as a
  collapsed 💭 block.
- **Tools**: each tool on, off, or at its default. See [Tools](/docs/tools).
- **Profile**: a named bundle of model, reasoning, tool settings, and system
  prompt. One profile is the default for new conversations. Editing a profile
  later does not change conversations that already used it.

You can switch models mid-conversation. The picker is disabled while a turn
is running; stop it or wait. You can also type `/model` to see the current
settings, or `/model <model> [level]` to change them. Names match leniently:
a unique prefix or fragment of a model ID works, and an ambiguous one gets a
list of candidates. Each change leaves a marker in the transcript.

## Working directory

A new conversation's directory is set in the **Dir:** field above the
composer. It defaults to the last directory you picked in this browser, then
the most recent conversation's, then the directory `shelley serve` was
started in. After that, click the directory in the status line to change it
(when the agent is idle), or let the agent move with its `change_dir` tool.
The command menu can also start a conversation in a new git worktree.

## The composer

<kbd>Enter</kbd> sends, <kbd>Shift</kbd>+<kbd>Enter</kbd> adds a newline (on
touch screens <kbd>Enter</kbd> adds a newline and you tap Send). Type `@` to
complete file and folder names from the working directory; this inserts a
path, not the file's contents. Type `/` for commands:

| Command | What it does |
|---|---|
| `/btw <question>` | Ask a side question without disturbing the main thread (below) |
| `/tour [hash]` | Build a [commit tour](/docs/commit-tours) |
| `/fork`, `/new`, `/archive`, `/rename` | As above |
| `/diff` | Open the diff viewer |
| `!<command>`, `/shell` | Run a command in the terminal panel; `!` alone opens a shell |
| `/compact [instructions]` | Compact the context (below) |
| `/clear` | Start fresh context in the same conversation |
| `/transcription <path>` | Transcribe an uploaded recording |

You can add your own slash commands with [hooks](/docs/hooks).

**Files and images.** Paste, drag, or attach files (up to 1 GiB). They are
uploaded to `/tmp/shelley-uploads` on the server and their paths are added
to your message in brackets; the agent opens them with its tools
(`read_image` for pictures). Click any image in the transcript, drag a box,
and type a comment: Shelley inserts a quote naming the image and the region
as ImageMagick geometry, so the agent can crop exactly what you meant.

**Sending while the agent works.** A message sent mid-turn reaches the model
at its next request; the turn isn't interrupted. To hold it until the turn
ends instead, use the arrow next to Send and choose *Queue after agent
finishes*. Queued messages wait at the bottom of the transcript with *Send
now* (interrupts the turn) and *Cancel*. **Stop** cancels the turn, kills a
running foreground command, and stops the conversation's working subagents.

If Shelley restarts mid-turn, the status line says *Conversation
Interrupted* with a **Continue** button. An unfinished tool call may run again.
After a restart to install an upgrade, Shelley continues the turn on its own
and leaves a warning in the transcript saying so.

## Voice and screen recording

The record button next to the composer records your voice, or your voice
and screen (<kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>M</kbd> for voice; add
<kbd>Alt/⌥</kbd> for screen). When you stop, the recording is uploaded and
transcribed, and the transcript is sent as your message, after anything you
had already typed. A screen recording also gets a 12-frame contact sheet, and
the message includes the paths to the video, the sheet, and word timestamps,
so the agent can line up what you said with what you pointed at.

It needs a few things:

- **A transcription route**: `OPENAI_API_KEY`, or an exe.dev LLM integration,
  set before Shelley starts (other routes are in
  [Models and API keys](/docs/models#recordings-need-transcription)).
  Without one, the button explains that instead of recording.
- **`ffmpeg` and `ffprobe`** on the server's `PATH`. Every recording is
  probed with `ffprobe`.
- **A browser that allows it**: microphone access needs HTTPS or
  `localhost`, and *Voice & Screen* only appears where the browser supports
  screen capture.

The diff viewer has its own record button for narrated reviews: talk through
a diff, and Shelley sends the transcript along with a log of what was on
screen and selected as you spoke.

## Subagents and side questions

When the agent delegates with its `subagent` tool, each subagent is a full
conversation. It appears nested under its parent in the list (the number
badge expands or collapses them), and the tool card in the parent shows what
it's doing live. Open it like any other conversation. Its reports arrive in
the parent's transcript, attributed to it. Only top-level conversations can
have subagents.

`/btw <question>` asks a side question. A read-only helper answers from a
frozen copy of the conversation's context, inline, without adding to the main
thread. You can ask it to summarize the exchange into your composer.

## Diffs, git graph, and terminal

**Diffs** (<kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>D</kbd>) shows working
changes, a single commit, or a range, side by side, with a file tree. In
comment mode, line comments go into your composer, and <kbd>.</kbd>/<kbd>,</kbd>
step through changes and <kbd>&lt;</kbd>/<kbd>&gt;</kbd> through files; edit
mode saves your edits to disk; there's a Vim toggle. Edits made
with the `patch` tool also render as diffs in the transcript; changes made
through shell commands only appear in the viewer. When a turn moves `HEAD`, a
"now at `<hash>`" line appears with links to the diff and its tour.

**Git graph** (<kbd>Ctrl/⌘</kbd>+<kbd>Shift</kbd>+<kbd>G</kbd>) shows
branches and history for the conversation's repository, with commit details,
*Open diff*, and tour badges.

**Terminal** (<kbd>Ctrl</kbd>+<kbd>&#96;</kbd>) opens a real shell in the
conversation's directory. Terminal sessions are persistent: they survive page
reloads and Shelley restarts, and are kept in a `terminals` directory next to
the database. A terminal can belong to one conversation or show in all of
them. Buttons on the panel copy its output or insert it into the composer.

## Context and compaction

Every request sends the conversation's context to the model again, so long
conversations get slower, worse, and
[quadratically more expensive](https://blog.exe.dev/expensively-quadratic).
The token count in the status line is the current context size. Click it for
token and cost graphs. It changes color at 100k, 200k, and 300k tokens (or
70, 80, and 90% of a known context window). Nothing is compacted unless you
ask:

- `/compact [instructions]` summarizes older messages, keeps roughly the
  last 20k tokens verbatim, and carries on in the same conversation. This
  starts a new *generation*: from then on, only the current generation (the
  summary plus what follows) is sent to the model. Earlier messages stay
  visible in the transcript. <kbd>Ctrl/⌘</kbd>+<kbd>Enter</kbd> (or *Compact and
  send* under the Send arrow) compacts and then sends.
- `/clear` starts fresh context in the same conversation, with no summary.
- **Auto compaction**, a switch in the Tools dialog, gives the agent the
  `compact_in_place` tool and nudges it once context passes a threshold
  you pick there (250k by default), and again every 50k tokens after that.
  It collapses old ranges into short notes and trims old tool output; the
  originals stay in the database.

## Notifications and phones

The overflow menu turns on browser notifications for when a tab is hidden.
The command menu's *Notification Settings* adds server-side channels: a
Discord webhook, ntfy, or email (on exe.dev). The layout works on a phone:
the list becomes a drawer, and voice recording works if the page is served
over HTTPS.
