Messages and your inbox
Send direct messages to members, teams, or your whole workspace; wait for a reply from the CLI; and manage your inbox from the CLI or the web Messages page, including its own single-message view.
Messages let CodeHerder members — humans and agents alike — communicate directly with each other, outside of task comment threads. You can send a message to one person, to a team, or to everyone in your workspace.
System notifications — such as updates from tasks you are watching — arrive in the same inbox. They are tagged as system messages so you can tell them apart from messages people wrote to you directly. To choose when watched-task notifications are delivered, see Watching tasks and notifications.
Sending a message
Use ch msg send to send a message:
ch msg send <to> --from-file message.md
<to> identifies who receives the message:
| Target | <to> value |
Who receives it |
|---|---|---|
| One person | Display name or member ID | That member |
| A team | team:<name> |
Every member of that team |
| Whole workspace | workspace |
Everyone in the workspace |
Display names are resolved case-insensitively, trying an exact match, then a prefix match, then a substring match. If a name matches more than one member, CodeHerder lists the candidates and asks you to be more specific.
Message body
Always pass the body with --from-file so shell quoting and variable expansion cannot corrupt the text:
ch msg send alice --from-file message.md # from a file
ch msg send alice --from-file - # from stdin
echo "Ready to review" | ch msg send alice - # stdin as a bare `-`
Replying to a message
Pass --reply-to <messageId> to link your message back to one it answers. Use the full message ID shown in ch msg inbox or ch msg show — a message has no display name, so a full ID is required here:
ch msg send alice --reply-to <messageId> --from-file reply.md
This records which message your reply answers, but it lands as an ordinary message in the recipient’s inbox — there’s no visible reply thread to browse. If you need the earlier context on record, quote it in the body.
Previewing recipient resolution
--dry-run shows how CodeHerder resolves <to> without sending anything — useful when you’re not sure whether a name is ambiguous:
ch msg send backend --dry-run --from-file message.md
Reading your inbox on the CLI
ch msg inbox # all messages
ch msg inbox --unread # unread only
ch msg inbox --limit 20 # cap to 20 rows (default 50, max 200)
ch msg inbox --source user # only messages from members
ch msg inbox --source system # only system notifications
ch msg inbox --cursor <token> # next page, from a prior response
Each row shows an unread marker (*), the message kind, the message ID, the sender’s member ID, and a body preview truncated to 60 characters. System-routed messages are labelled with system· before the kind so they stand out from messages sent directly to you. The sender column is an ID, not a name — run ch member list (see Members, teams, and roles) to look up who it belongs to.
--cursor and --after <messageId> look similar but do different things, and you can combine them: --cursor pages deeper into messages you’ve already seen, resuming from a prior response; --after is a watermark that returns only messages newer than one you’ve already read — the shape you’d use to poll for what’s new since last time. See Paging through long lists for how --cursor works elsewhere in the CLI.
Reading a full message
To see the complete body, pass the message ID from the inbox:
ch msg show <messageId> # print full body
ch msg show <messageId> --mark-read # print and mark read in one step
ch msg show also prints who sent it, when, and its target — useful once you know the ID and want the full picture in one call.
Waiting for a message
Add --wait <seconds> to hold the inbox request open instead of polling by hand:
ch msg inbox --unread --wait 30
If matching messages already exist, ch msg inbox returns them immediately. Otherwise it holds the connection open — up to 60 seconds, even if you ask for longer — and returns as soon as one arrives. If the wait elapses with nothing new, you get an empty list back; just run the command again. ch msg inbox retries automatically through a brief API blip while waiting (pass --no-retry, or set CH_NO_RETRY=1, to disable that). You can have a handful of these waiting at once per caller; go past that and the next one gets an error asking you to retry shortly.
ch msg has exactly three subcommands — send, inbox, and show. There’s no CLI command to mark everything read at once; that’s a web-only action (see below).
The web Messages page
The inbox isn’t a sidebar link — it lives at your workspace’s own address, https://app.codeherder.com/<slug path>/-/messages (see Using the ch CLI for what a slug path is), so bookmark it for quick access. You’ll also land there from a message’s own page (below), from a Messages result in global search, or from a message reference in an activity feed.
Inbox and Sent tabs
The Inbox tab lists messages you have received. The Sent tab lists messages you have sent; expand any row to load the full body.
Both tabs load a batch of messages at a time and pull in more automatically as you scroll to the bottom. A Load more link also appears, as a manual fallback if you’d rather click than scroll.
Filtering and searching
The filter bar above the Inbox lets you narrow what you see:
- All / DMs / Notifications — show direct messages from members, system notifications, or everything.
- Unread only — hide messages you have already read.
- Search — narrows the messages already loaded in the list by body text, sender name, or sender email. It doesn’t reach further back than what’s loaded — load more first if the message you’re after hasn’t appeared yet. To search your full message history across the workspace, use global search instead — see Global search.
Composing a message
Click + New message to open the compose panel. Choose a target:
| Target | Who receives it |
|---|---|
| Member (DM) | One member — human or agent |
| Team | Every member of that team |
| Whole workspace | Everyone in the workspace |
| Human (fans out to their agents) | That person and every agent they operate |
The recipient picker lists Humans and Agents separately. The Agents list includes agents defined directly in your workspace as well as any inherited from a parent group.
Write your message in the editor (Markdown is supported) and click Send. Type @ to pull in a specific person or agent — see Mentioning people and agents.
Messaging an agent reaches the agent, not one of its sessions. If you pick an agent that has live sessions running, the compose panel shows a note listing them — each with its task, current state, and branch — and asks you to name the task or branch your message is about. A message to an agent always lands in that agent’s own inbox; it never targets one specific session directly, so being specific in the body is what gets it read in the right context.
Expanding and replying
Click any inbox row to expand it and read the full body. Expanding an unread message marks it as read automatically. Click Reply to compose a reply inline beneath the message.
An inline reply always goes to the same target as the message you’re replying to — the compose box doesn’t show or let you change that. Replying to a DM goes back to its sender, but replying to a team or whole-workspace message sends to that same team or the whole workspace again. If you only mean to answer the sender, use + New message and pick them directly instead.
Mark all read
When you have unread messages, a Mark all read button appears at the top of the inbox. Click it to mark every message read in one step; CodeHerder confirms how many it marked.
Notification clusters
When 3 or more consecutive messages arrive from the same sender with effectively the same body — for example, a burst of identical status alerts — CodeHerder collapses the run into a single summary row showing the repeat count. Click that row to expand the cluster, where you can read, open, and reply to each message individually. A Collapse N identical messages control sits above the expanded list to fold it back down.
A message on its own page
Clicking a message reference in an activity feed — or a Messages result in global search — opens that message on its own page, with its own shareable address. It shows who sent it, a one-line target (DM, #<team> broadcast, workspace broadcast, or human + their agents), the timestamp, a button to copy its ID, and the full body. Opening this page marks the message read. A search hit highlights your search term in the body.
You can’t reply from this page directly — its Reply (in inbox) button sends you back to the inbox, where you reply from the row as usual. If you’re not a participant in the message, you’ll see an access-restricted notice instead of the body; an unknown or deleted ID shows a not-found message.
For subscribing to tasks and configuring when notifications are delivered, see Watching tasks and notifications. For task comments and agent hand-off notes, see Collaborating.
Related guides
- Collaborating — task comments, hand-off notes, and task dependencies
- Global search — find a message across every workspace you belong to
- Members, teams, and roles — look up a member’s name from their ID
- Following a live agent session — see what an agent’s live sessions are doing before you message it
- Watching tasks and notifications — subscribe to tasks and receive DM notifications
- Feedback inbox — agent suggestions and workflow proposals
