Sessions are where you interact with agents. This guide covers the full workflow from creation to conversation.
Make sure you have a project selected and at least one agent running
Click New Session in the left sidebar. The New Session button is a split button — clicking the main body creates a default worktree session; clicking the chevron to the right opens a menu with two other modes:
If the project root is not a git repository, the split button adapts: the primary action becomes New Session in Project Root, the caret-menu hides the now-redundant project-root entry, and a banner beneath the button offers an Initialise Git Repository action so worktree mode can be enabled with one click. See Projects Without a Git Repository for the full behaviour.
Select a persona or agent from the dropdown in the prompt toolbar:
A new row appears in the sidebar immediately — showing a rotating dashed spinner and a "Setting up…" subtitle while the server provisions the worktree and completes the agent handshake. The row transitions to ready once setup finishes and you can send your first prompt. If anything fails on the way — worktree creation error, agent not reachable, handshake timeout — the row flips to failed with the error as its subtitle and stays in the list until you delete or archive it. Non-worktree sessions additionally display a coloured mode pill (ROOT or SCRATCH) once ready, so you can tell them apart at a glance. See Session Status Indicators and Failed Session Setup for the full lifecycle.
You can click New Session several times in quick succession to queue up multiple setups — each click creates its own session row and they provision in parallel.

Many agents expose capability options — things like model selection, thinking mode, or permission bypass — in the config options bar that sits above the prompt input. The value you pick for each option is remembered so you don't have to reconfigure the agent every time you create a session.
Where choices are stored depends on whether the project uses personas.
| Setup | Source of truth | Scope |
|---|---|---|
| Personas configured | The selected persona's Agent Config Options (see Personas > Agent Config Options) | Per persona, per agent. Each persona carries its own set of overrides, so switching personas picks up that persona's configuration. |
| No personas | Project preferences, keyed by agent id | Per project, per agent. Each agent remembers its own last-used values independently. |
How the no-persona flow works:
Why the split? Personas already give you multiple named configurations per agent, so a separate project-level store would duplicate that behavior and could silently mask the persona's overrides. The direct-agent flow has no equivalent "named configuration" concept, so project preferences fill that gap — but only when no personas are defined, avoiding any conflict with the persona model.
When a new worktree session is created, the prompt toolbar includes a branch selector that lets you pick the branch the worktree will be created from. The chosen ref is passed to git worktree add -b acp-session/<session-id> <path> <branch> as the start point, so the session begins at exactly that commit. Once the first prompt is sent the selector locks to indicate the base branch is fixed; changing it afterwards from the session view recreates the worktree against the new ref.
The selector is only meaningful when the session has a git worktree, so Braide hides it entirely in the modes where a base branch would have no effect:
| Situation | Branch selector |
|---|---|
| Worktree session in a git project | Shown — branches load asynchronously from git branch -a, filtered to skip the session's own acp-session/* refs and any acp-session-deleted/* / acp-session-archived/* tombstones. |
| Worktree session in a project whose root is not a git repo | Hidden — the session is auto-promoted to project-root mode, and there is no branch list to pick from. |
| Project Root session (explicitly created) | Hidden — project-root sessions don't track a base branch and don't own a session branch, so the selector would be inert. |
| Scratch session | Hidden — scratch sessions run in an empty directory with no git repository at all. |
The same gating applies to both the new-session view and the existing-session view. In the existing-session view the selector is additionally hidden if the branch list is empty for any reason (e.g. the GET /api/projects/<id>/branches endpoint returned an error).
Type your message in the prompt input at the bottom of the screen and press Enter (or click the send button).
/ to open a command autocomplete menu. As you continue typing, the list is filtered using fuzzy matching. Use the arrow keys to navigate and Enter or Tab to select a command. Press Escape to dismiss.@ to open a file autocomplete menu. The menu loads file paths from the session's worktree asynchronously and filters them as you type. Select a file to attach it as context for the agent. Use arrow keys to navigate and Enter or Tab to confirm.Both the / and @ menus can also be opened via buttons next to the prompt input, which is useful on touch devices or if you prefer clicking.

When you paste multi-line content into the prompt input, the app tries to identify the language of the pasted text and, if it recognises one, wraps the paste in a triple-backtick fenced code block tagged with that language:
```typescript
import { useState } from "react"
export function Counter() {
const [n, setN] = useState(0)
return <button onClick={() => setN((c) => c + 1)}>{n}</button>
}
```
The agent receives the prompt with the fence tag intact, so it knows the attached material is typescript and not prose — useful when you're asking it to review, refactor, or diff pasted snippets. When the paste is later rendered back in the message stream, the same fence tag drives syntax highlighting.
What triggers auto-fencing:
```, the paste is inserted as-is so manually constructed blocks aren't double-wrapped.Under the hood the prompt input POSTs the clipboard text to an internal /api/detect-language endpoint, which runs a small machine-learning model (the same one VS Code uses for its language-detection feature). Because the ACP backend is local to the app, detection adds only a millisecond or two of latency before the text appears in the input. If the request fails for any reason, the paste falls back to plain text — you never lose content.
Recognised languages include all of the common ones listed under Code Syntax Highlighting. Short snippets (a handful of lines) are more likely to fall through as plain text than longer, structurally distinctive code; if you want a specific language tag, type the opening fence (e.g. ```sql) before pasting. JSON is a special case: any paste that parses as valid JSON is tagged as json regardless of length, so small objects and arrays get fenced reliably.
If you have configured actions in the project settings, additional buttons appear in the prompt input toolbar. The Run, Build, Test, and Browse actions are shown as icon buttons between the terminal toggle and the config options bar. Each button has a distinctive icon and a tooltip showing the action name. When multiple actions are defined for a type, a split button is shown — click the primary button to run the default action, or click the chevron to choose from alternatives.
Clicking an action button executes its configured command:
Action buttons are only visible when they have been configured with a non-empty prompt in project settings. See Settings & Preferences for how to configure them.
Click the paperclip icon in the prompt toolbar (next to the command menu button) to attach local image or video files to the next prompt. The button is available as soon as a session is being created — attachments added during setup are persisted once the session is ready.
The picker opens a filesystem browser titled Attach Media, showing both image files (png, jpg, jpeg, gif, webp, svg, bmp, heic, heif) and video files (mp4, webm, mov, avi, mkv, m4v). Directories appear first, then media files with thumbnails (images) or a play icon (videos) and sizes. Click a directory to navigate into it, or use the up-arrow button to go to the parent.
Default location. The picker opens at the last directory you attached from, remembered per project. If that directory was inside your session's worktree, it is stored as worktree-relative and re-resolved against the current session's worktree on next open — so it "follows" you across worktrees. The first time you open the picker in a project it defaults to the current worktree directory.
Selecting files. Both image and video files are selectable using the same controls:
| Action | Behaviour |
|---|---|
| Click | Select just that file |
| Cmd/Ctrl-click | Toggle an individual file in the selection |
| Shift-click | Select a contiguous range from the previously clicked file |
| Cmd/Ctrl+Shift-click | Add a range to the existing selection |
| Double-click | Select that file and attach immediately |
| Enter | Attach the current selection |
| Escape | Cancel without attaching |
Click Attach (N) to attach the selected files and remember the current directory for next time.
Selection restrictions. You cannot mix video and image files in the same selection — doing so disables the Attach button and displays a warning: "Cannot mix video and image files in one selection". You also cannot select more than one video file at a time; selecting multiple videos shows: "Only one video file can be selected at a time". These restrictions exist because video files are routed to the Video Keyframe Modal for frame extraction, which processes one video at a time.
Video files. When a single video is selected and you click Attach (or double-click it), the picker closes and the Video Keyframe Modal opens so you can select specific frames to extract.
The entire session view — prompt input, message stream, session header — acts as a drop target for image and video files. You can drag media from any external source that provides file data:
Visual feedback. While you're dragging files over the session view, a dashed cyan overlay labelled "Drop images or videos to attach" appears above the content. If multiple files are involved, the overlay stays until the last one is released. Non-media files are silently skipped at drop time, so mixed drags (media + text files, for example) only process the media portion.
Mixed drops. You can drop images and videos in one gesture. Image files become individual attachment pills (as before). If a video file is included, the first video opens the Video Keyframe Modal so you can extract frames from it. Image files in the same drop are attached immediately.
Supported formats. Images: png, jpg, jpeg, gif, webp, svg, bmp, heic, heif. Videos: mp4, webm, mov, avi, mkv, m4v. Files with other extensions are silently ignored, and drops that contain no media files are no-ops.
What happens on drop depends on the runtime:
| Runtime | Behaviour |
|---|---|
| Electron desktop app | Each dropped file's absolute filesystem path is read via the Electron webUtils bridge. Image attachments reference the file in place — nothing is copied or uploaded. Video files open the keyframe modal using the local path. The file must remain at that path when the prompt is sent; if it has been moved or deleted by then, that one image is skipped with a warning and other images go through. |
| Plain browser | Absolute paths aren't exposed by the OS, so each file is uploaded via POST /api/projects/{projectId}/sessions/{sessionId}/uploads (multipart form, file field). The server writes the file to <sessionDir>/uploads/<uuid>.<ext> and returns its absolute path. The overlay swaps to "Uploading…" for the duration of the transfer. Uploads are capped at 100 MB per file (to accommodate video). Because the uploads live inside the session directory, they are removed automatically when the session is deleted. |
New-session caveat (browser only). In the browser, drag-and-drop requires the session to already exist on the server, because the upload endpoint is session-scoped. If you drop media in the new-session view before sending your first prompt, the drops are silently skipped. Either use the paperclip picker (which doesn't need a session) or send a prompt first to create the session. The Electron desktop app does not have this limitation — its drops don't go through the upload endpoint.
After drop. Dropped images become regular attached image pills — same color coding, same detach behaviour, same preview popover, same "only unsent images are re-sent" rule on prompt submit. Video frames extracted via the keyframe modal also become image pills after extraction.
When you select or drop a video file, a Video Keyframe Modal opens where you can scrub through the video and capture specific frames to send to the agent as image attachments. See the Video Keyframe Editor guide for full details on video loading, the filmstrip timeline, play/pause controls, keyframe capture, and keyboard shortcuts.
Each attached image appears as a pill in the session header alongside any attached GitHub issues. Image pills are color-coded differently from issue pills (cyan) and carry a small image icon. Hover to reveal the × button to detach. Attachments are references only — the underlying file is never copied, so detaching leaves the file on disk untouched. Frames extracted from video keyframes appear as regular image pills indistinguishable from directly attached images.
Click an image pill to open a preview popover anchored underneath that pill (similar to the attached-issue popover). Inside the popover:
Historical image thumbnails also appear in the past prompt cards in the event stream — click any thumbnail to open the same preview popover.
When you submit a prompt, any attached images that haven't been sent in a previous prompt for this session are read from disk, base64-encoded, and delivered to the agent as native ACP image content blocks alongside your text. Images already sent in a prior prompt are not re-transmitted. This keeps token usage predictable when images accumulate across multiple prompts.
Text is required. An image-only prompt cannot be submitted — images describe what, but the agent still needs text telling it what to do with them. The send button stays disabled until you type a prompt (or an unsent issue provides the instructions). When keyframes are extracted from a video, the auto-inserted caption text satisfies this requirement.
If an attached image has been moved or deleted on disk by the time you send the prompt, it is silently skipped for that request and a warning is logged. Other images go through as normal.
You don't have to wait for the agent to finish before sending your next prompt. While the agent is running, you can continue typing and pressing Enter to queue additional prompts.
Queued prompts appear as small chips labelled Queued above the prompt input. You can remove any queued prompt by clicking its × button, or click a chip to edit its text. Drag and drop chips to reorder them — prompts are sent in the order they appear from left to right.
When the agent completes its current task, all queued prompts are automatically flushed as a single submission. Each queued prompt is sent as a separate content block so the agent treats them as individual instructions.
While the agent is running, the send button changes to a + icon with a "Queue prompt" tooltip to signal that submissions will be queued rather than sent immediately. Both the stop button and the queue button are visible at the same time, so you can cancel the current run or queue follow-up work as needed.
You can also queue prompts for a future time using scheduled tasks. Click the clock icon in the prompt toolbar to set a schedule — all prompts submitted while a schedule is active are queued and sent automatically at the scheduled time.
Agent responses stream in real time as a series of events.
The agent's text responses are rendered as markdown with support for headings, code blocks, lists, tables, and links. Fenced code blocks with an explicit language tag are tokenised and colour-coded — see Code Syntax Highlighting for the supported languages and palette. Fenced blocks tagged mermaid, likec4, or c4 render as interactive diagrams instead.
When the agent uses tools (reading files, running commands, searching), the tool calls are collapsed into the agent message or thinking block that preceded them. Each such block dedicates its right-hand column to a Tool Calls area containing:
completed/total count.description input (e.g. Bash, Task/Agent), that description is used as the tooltip instead of the raw status.Click anywhere in the Tool Calls area to reveal the individual tool call cards inside the same block, below the message text and separated by a thin divider. Each card shows the tool name, arguments, result, and status. Click again to collapse. If a permission request arrives while the agent is running, the area auto-expands so the request is visible.
When a tool call card is collapsed and its input includes a description, a small info icon appears in the card header (right-aligned, before the status badge). Hovering the icon reveals a popover containing the full description, so you can scan the purpose of each call without expanding it. The icon is omitted for tools that don't supply a description.
Tool calls that arrive with no preceding agent message or thinking block — for example, right after a user prompt — still render as a standalone Tool Calls panel below the prompt, with the same dot grid and expansion behaviour.
Some tool calls require your approval. When a permission block appears inside the tool call list:
The Tool Calls area that contains the pending permission expands automatically so you don't have to hunt for it.
When the agent modifies files, a diff report card appears showing a summary of all changes — files added, modified, deleted, or renamed — along with addition/deletion counts. Click a file row to expand the inline diff viewer.
Files that have been staged (added to the git index) are marked with a green STAGED badge next to the filename, making it easy to distinguish staged changes from unstaged ones at a glance.

The expanded diff viewer provides three view modes, selectable via tabs in the toolbar:
| Mode | Description |
|---|---|
| Unified | Standard unified diff with old and new line number gutters. Changed lines are highlighted with word-level precision — individual tokens that differ within a line are emphasised so you can see exactly what changed. |
| Split | Side-by-side comparison with the old file on the left and the new file on the right. Word-level highlights are applied on each side independently. |
| Raw | The unformatted patch text. A copy button appears in the toolbar to copy the raw diff to the clipboard. |
Your selected view mode is persisted across sessions. It is saved to settings.json in your ACP home directory and restored automatically the next time you view any diff.
Click the Expand button in the diff toolbar (visible in Unified and Split modes) to open the diff in a full-screen modal. The modal provides:
Click Collapse or press Escape to return to the inline view.
If you have configured commit actions in project settings, a commit button appears in the diff report header:
For terminal mode commit actions, the command runs in the session terminal and output appears in the terminal pane. For agent mode commit actions, the prompt is sent to the agent and the response appears in the session's message stream.
A status bar between the event stream and the prompt input shows the session's running cost and context window consumption. When the agent is working, these figures appear right-aligned alongside the "Working..." indicator. When the agent is idle, the cost and context usage remain visible so you can review them at any time. See Cost and Context Usage in the Sessions concept page for details.
The same status bar also surfaces two optional pill buttons — Sub-agents N and Skills N — that appear to the left of the cost figures once the agent has made its first corresponding tool call. They roll up the delegation activity for the session at a glance:
Agent and Skill tool-call events, so they update live and survive session reload.See Sub-agent and Skill Usage in the Sessions concept page for full details of the data model behind the pills.
To the right of the sub-agent and skill pills, a Files N pill shows where the agent's Read / Write / Edit / MultiEdit / NotebookEdit calls have landed. N is the number of distinct files touched so far (only completed calls count). The pill stays hidden until the first file operation completes and then updates live as the agent works.
Clicking the pill opens an anchored popover above the pill with a condensed view of the worktree:
3 reads, 2 writes).+N untouched files line counts the sibling files in that directory the agent has not touched — a quick way to gauge coverage.A maximise icon in the popover header opens a larger modal with a filename search input and clickable +N untouched files rows that reveal the skipped files inline. Use the modal when you want to investigate coverage or find a specific file quickly; the compact popover is intended for at-a-glance scanning.
When rows are expanded or collapsed, the popover resizes upwards from its bottom edge so the pill stays in place — no jumping. Press Escape or click outside to dismiss either the popover or the modal.
See File Activity in the Sessions concept page for the data model and classification rules.
While an agent is running, a cancel button appears next to the prompt input. Click it to stop the agent mid-response. The session stays open — you can continue sending new prompts.
If an agent is upgraded or restarted while you have existing sessions, Braide automatically recovers them. When you send your next prompt, the system detects that the agent no longer knows the session and transparently creates a new one, compressing the previous conversation history into a summary that is sent alongside your prompt. A context compressed indicator appears in the event stream to mark the boundary.
No manual action is required — just keep prompting as usual. For details on how the history is compressed, see Session Recovery.
Sessions are automatically labeled based on the first prompt. To rename:
Click the delete icon next to a session in the sidebar to remove it. This is permanent.
Click any session in the sidebar to switch to it. Each session maintains its own conversation history.