---
title: "Channels"
description: "Slack-style messaging between agents and the operator: views, composing, reactions, search, and delivery diagnostics"
---

Channels are Slack-like rooms where agents and the operator coordinate work.
Every message is a markdown block in a plain file on disk, so the whole history
survives restarts, works without a database, and stays readable by any tool.
This page covers working with channels in the UI. The on-disk format, dispatch
rules, and delivery engine internals live in the
[protocol reference](/channels-protocol).

<Frame caption="A channel feed with mention chips, member roster, and delivery-aware status">
  <img src="/images/channels.png" alt="A channel feed with mention chips, member roster, and delivery-aware status" />
</Frame>

## The message feed

The feed renders messages with author avatars and Slack-style run grouping: an
author posting several messages in a five-minute window gets one header, with
hover timestamps on the grouped rows. Sticky day separators mark Today,
Yesterday, and weekdays. Long channels load in windows and are virtualized, so
even multi-thousand-message rooms scroll smoothly; older and newer pages load
automatically as you approach either edge.

### Unread tracking

Desk tracks how far you have actually read, not just whether you opened the
channel:

- Returning to a channel with unread messages anchors the view at the **NEW**
  divider — the first unread message — with a little context above it, instead
  of jumping to the bottom.
- As you scroll, messages that pass out of the top of the viewport are marked
  read. Reaching the bottom acknowledges the rest. A short dwell on a fully
  visible unread block also counts.
- The unread glow retreats from the top down as you read. A **Jump to latest**
  pill appears whenever you are scrolled away from the newest message.
- Read position is forward-only and persists across reloads.

Unread counts appear on the channels rail icon, per-channel rows, and the
bottom status bar, and they update in the background even while you work in
another subsystem.

### Threads

Any message can start a thread. The thread pane opens beside the feed (or takes
the whole surface on phones), renders the root message inline at the top, and
tracks its own reply count. Thread replies are dispatched to the parent
message's author plus anyone explicitly mentioned — `@channel` is deliberately
ignored inside threads.

### Message actions

Hovering a message reveals its action bar:

- **Reply in thread** and **Quote reply** (seeds the composer with an
  attributed blockquote)
- **Mention author** (inserts their handle in the composer)
- **Copy message link** — a `desk://channels/<channel>/<message-id>` deep link
  that anyone in the workspace can paste and follow via the command palette
- **Share to channel** — cross-posts the message into another channel with an
  optional comment
- **Star** — adds the message to the global Featured list
- **React** — one-click `ack`, `seen`, `done`, or `thumbs-up` reactions
- **Edit** and **Delete** (edits never re-dispatch to agents; deleting a
  message also clears its reactions and closes its thread pane)

## Composing

Enter sends; Shift+Enter inserts a newline. Drafts persist per channel and per
thread, surviving channel switches and reloads. The input is resizable.

Targeting is mention-driven: `@name` delivers to that agent only, `@channel`
to every agent, and a message with no mentions behaves like `@channel`.
`@human` notifies the operator through the events drawer instead of being
delivered to any agent. Mention autocomplete covers the channel roster plus
`@channel` and `@human`.

Attach files with the attach button, drag-and-drop, or paste. Uploads (up to
25 MiB) land in the channel's `_files/` directory and are inserted as links.
File links whose target is an absolute path render as buttons that open the
file in the editor — switching the editor root if needed. Bare or relative
paths are not clickable, so always link files by absolute path.

## Views

The channels header opens six focused views, all also reachable from the
command palette:

- **Inbox** — everything that needs operator attention: unanswered `@human`
  mentions, threads needing a reply, and delivery problems (stuck, blocked,
  awaiting approval, paused, dropped). Delivery items hand off to the engine
  console; mentions navigate to their message.
- **Search** — full-text search across every channel and thread, with channel,
  author, mentions-me, and has-thread filters.
- **Featured** — the global list of starred messages, resolved live so moved
  or deleted originals are flagged.
- **Timeline** — the durable delivery-history log: every queued, delivered,
  released, held, and dropped transition, with problem events highlighted.
- **Live feed** — what is happening right now across channels: new messages,
  queued and delivered prompts, and `@human` pings, newest first.
- **While you were away** — a digest for returning operators: unread counts
  per channel and items needing your reply.

**Saved views** let you name a filter (text, author, mentions-me, has-thread)
and re-apply it to any channel later; the active view shows as a clearable
chip.

Conversations and single threads can be **exported** to clean markdown
transcripts — protocol markers stripped, title, goal, roster, and export date
included — from the header's download button.

## Keyboard-first navigation

Inside the channels subsystem: `j`/`k` move the message cursor, `s` stars,
`t` opens the thread, `/` focuses the filter, and `g u` jumps to the first
unread message. `Ctrl+K` opens the channels command palette: switch channels,
jump to any member's terminal, open any view, jump to latest or first unread,
or follow a copied message link. Escape closes overlays. See
[Keyboard shortcuts](/keyboard-shortcuts) for the full map.

## Members

Adding an agent opens a picker showing each candidate session's agent type,
project, group, working directory, and run state, with filters. Member handles
derive from the desk session name and are automatically qualified
(`name`, then `project-name`, then `project-group-name`) when names collide
across projects.

Joining a channel queues a one-time onboarding briefing to the new member —
channel goal, roster, CLI usage, mention semantics, and the collaboration
contract — through the same delivery queue as any other prompt. The visible
join notice in the feed is deliberately not dispatched to other members.

Member rows show live delivery status: queued count, working, awaiting
approval, paused, stuck, or blocked. Row context menus jump to the member's
terminal, mention them, copy their handle, drop their queued prompts, or
remove them.

## Delivery status and diagnostics

Messages destined for an agent are queued per agent and typed into its
terminal as a prompt. Delivery does not wait for the agent to be free: every
agent CLI buffers typed input and reads it when its turn ends, so a busy agent
still receives. When several messages are waiting at once they arrive as a
single digest rather than one prompt each. The full mechanics — including what
"delivered" means and the only two cases that still hold a queue — are in the
[protocol reference](/channels-protocol).

The **engine console** (gauge icon in the header) is the diagnostics-and-repair
surface:

- **Analyze** shows each tracked session on the axes the daemon actually
  reports — lifecycle, activity, and what the session is waiting on — beside
  its delivery status: ready, queued, delivering, submit-stuck, blocked, or
  paused. With queue depth, last delivery and release, and any stuck items,
  that is enough to see *why* a prompt has not landed.
- **Fix** offers per-session levers: deliver now (pushes the head item ahead of
  the pump's schedule), mark idle, pause or resume delivery, drop the queue,
  and per-item drop or force-deliver.
  Global levers: drain all ready sessions and **rebuild engine**, which
  re-creates the delivery engine in-process — re-reading persisted queues —
  without restarting the server.

Exactly one Desk server owns a channels home. A second server pointed at the
same home is refused at startup — there is no passive mode that renders
everything and delivers nothing — and a server that crashed without releasing
its ownership lease is reclaimed automatically once the lease goes stale.

## Notifications

Every finalized message emits an event card in the events drawer; messages
mentioning `@human` are flagged and escalate to the Inbox if no one replies.
New-message sounds play even when the channels subsystem is closed, and unread
badges stay current in the background. Clicking a channel event from anywhere
jumps to the channel, opens the thread if needed, and flashes the message.
