Action verbs¶
Action verbs are the agent's entire interface to the board. An agent does not call functions or return JSON — it writes plain text, and the engine scans that text for slash-command lines it recognises. Each recognised line becomes an action the engine applies (change a status, create an issue, request an approval, write a file). Everything the engine does not recognise stays in the visible comment.
This page is the complete, exact catalogue. It is generated by reading
the parser (internal/engine/actions.go, ParseAgentActions) and the
applier (internal/engine/adapter.go). If a verb is here, the engine
parses it. If it isn't here, the engine treats it as prose.
For the conceptual background — when the engine parses a reply, and what context the agent sees — read the-agents-pov.md.
Format rules¶
These apply to every verb:
- A verb must be the first non-whitespace token on its line. Leading
whitespace is fine;
Hello /status doneis not a verb (the/isn't at the start of the line). - Verbs are case-insensitive.
/STATUS DONEparses the same as/status done. (Argument values may be case-sensitive — see each verb.) - Both
kebab-caseandsnake_casespellings are accepted./blocked-byand/blocked_byare identical;/create-issueand/create_issueare identical. The catalogue below lists the canonical hyphenated form first. - Arguments may be wrapped in
",', or backticks; matching outer quotes are stripped. - Each verb line is independent. Emit as many as you need in one
reply. They apply in the order they appear (with one ordering caveat
for
/create-issuedependency hints, noted below). - Some verbs take continuation lines — either
key: valuehint lines or a triple-backtick fenced body. Those are documented per verb.
Hints and fenced bodies¶
Several verbs read structured continuation lines after the verb line:
- Hint lines are
key: valuepairs (e.g.assignee: Go Developer). The parser accepts them at any indentation. Each verb has an allowlist of hint keys it understands; a key outside that allowlist ends the hint block and the line is treated as prose. (WhenTRIMUS_DEBUG=parseris set, every dropped hint is logged with the reason.) - A fenced body is the next triple-backtick block after the verb
(and its hints). The opening fence may carry a language hint
(
```markdown) which is discarded — only the lines between the fences are captured. The closing fence must be exactly three backticks on a line by themselves. An unterminated fence is treated as no body (the rest of the reply is not swallowed).
When a verb requires a fenced body and none is found, the verb is dropped and its line is preserved in the visible comment so the malformed attempt stays auditable.
Issue state¶
/status <state>¶
Set the current issue's status. Valid states (anything else is rejected and logged at WARN):
| State | Meaning |
|---|---|
backlog |
Not yet ready to work. |
todo |
Ready, not started. |
in_progress |
Actively being worked. |
in_review |
Done from the agent's perspective; awaiting human check. |
done |
Closed, positive. |
blocked |
Stalled on something — explain in prose. |
cancelled |
Closed, negative; won't do. |
/status reads two optional hint keys:
reason:— captured when transitioning intoblocked. It is stamped onto the issue (blocked_reason) so the UI and activity log can render why the issue is blocked.unblock-reason:(orunblock_reason:) — required when transitioning away fromblocked. If the issue is currentlyblockedand the agent emits/statuswith any other state but nounblock-reason:, the verb is dropped so the agent has to acknowledge it is unblocking the issue on purpose.
/priority <level>¶
Set the current issue's priority. Valid levels: critical, high,
medium, low. Any other value is rejected and logged at WARN.
Assignment and ownership¶
/assign <name>¶
Reassign the current issue to another agent. The argument is everything
after the verb (so multi-word names like Senior Backend Engineer
survive), with an optional leading @ and matching outer quotes
stripped.
The name is resolved to an agent on the same company. If no agent matches, the action is dropped and the current assignee is unchanged.
/checkout¶
Take the soft cooperative lock on the current issue under your agent. The engine already auto-checks-out the issue at the start of a heartbeat, so most agents never emit this. It exists for agents that want explicit ownership semantics. No arguments, no body.
/release¶
Release the issue you checked out (or were assigned). Heartbeats
normally auto-release at the end of the turn; emit /release to give the
issue up without doing more work — useful for a reviewer handing an issue
back to its original assignee. No arguments, no body.
Approvals¶
/request-approval <title>¶
Pause for a human decision. Creates a Pending approval (type
agent_request), links it to the current issue, and posts an
approval_created event so the Approvals page and Inbox refresh. The
title is everything after the verb on the same line — be specific.
An optional fenced body is captured as the approval's body_markdown —
this is where the agent should put the rich context a human reviewer
needs (what it plans to do, why sign-off is needed, what happens on
approve vs reject, how to roll back):
/request-approval Apply cross-child dependency edges for the AC-42 breakdown
```text
I created six children but three of the dependency edges are between
siblings I can't wire from this parent ticket. On approve, a human
applies them via the UI. On reject, leave a note and I'll re-plan.
Empty / whitespace-only titles are silently dropped (no useless
"Untitled" approval). The agent's run continues for the rest of its turn;
on the next heartbeat the agent should see the unresolved approval and
not redo the same work. **Agents cannot resolve approvals** — only board
users can. See [approvals.md](approvals.md).
---
## Issue creation and dependencies
### `/create-issue <title>`
Create a **child** issue under the current one. The new issue starts in
`backlog`, unassigned, so triage can route it. There is a **per-run cap**
(`max_issues_per_run` on the agent); attempts past the cap are dropped
with a notice.
```text
/create-issue Design — wireframe + visual treatment for /docs/how-we-use-ai
/create-issue reads these hint keys:
| Hint key | Effect |
|---|---|
assignee: (also assign-to: / assign_to:) |
Route the child directly to a named teammate (resolved like /assign). Without it the child starts unassigned and triage routes it. An unresolvable name leaves the child unassigned and logs a warning. |
blocks: |
The child blocks the named target issue. |
blocked-by: (also blocked_by:) |
The child is blocked by the named target issue. |
relates: (also relates-to: / relates_to:) |
Non-blocking link between the child and the named target. |
title: |
The issue title, when it isn't on the verb line (#371). Lets an agent emit /create-issue with title: on the next line. |
description: |
The issue body, used when no fenced ``` block follows the verb (#371). |
priority: |
critical / high / medium / low (case-insensitive); defaults to medium (#371). |
/create-issue Design — wireframe + visual treatment
assignee: Frontend Designer
/create-issue Backend — JSON endpoint at GET /api/public/models
assignee: Go Developer
/create-issue Frontend — implement the page
assignee: Frontend Developer
blocked-by: Design
blocked-by: Backend
Dependency targets (for the blocks / blocked-by / relates hints
and the relation verbs below) can be the issue's short identifier
(ACME-42), the 8-character id prefix shown in the UI, or the exact
issue title. Resolution waits until every sibling in the same reply has
been created, so the order you list the /create-issue lines does not
matter.
After the verb line and hints, you may add a fenced body — it becomes the
new issue's body_markdown:
/create-issue Login hangs for 5 seconds on first click
assignee: Frontend Developer
```markdown
## Steps to reproduce
1. Open `/login` in a fresh browser session.
2. Click **Sign in**.
3. The spinner runs ~5 s before the redirect.
## Expected
Click → redirect in under 1 s.
The fenced body is **opportunistic**: omit it and the child is created
with title + hints only (`body_markdown` NULL).
### `/blocks <id-or-title>`
Record that **this** issue blocks the target (the target can't proceed
until this one is done). Argument is an id-prefix, short identifier, or
title.
```text
/blocks ACME-42
/blocks "Migrate billing to Stripe"
/blocked-by <id-or-title>¶
Record that this issue is blocked by the target. Mirror of /blocks.
/relates <id-or-title>¶
Record a non-blocking relationship to the target. Also accepts
/relates-to and /relates_to.
For all three relation verbs, an empty argument drops the verb; unresolvable targets and self-references are dropped with a warning.
Reading the board¶
These verbs let an agent pull board state mid-reply. They are primarily used by the chat substrate (where a conversational agent answers questions about issues and notes); a heartbeat agent already receives its issue context in the prompt.
/get-issue <ref>¶
Fetch a single issue by reference (e.g. ACME-126). No hints, no body.
Empty ref drops the verb.
For a paired, authenticated, vetted user on a 1:1 surface (a DM, or the
web chat, which is already role-gated), /get-issue returns the issue's full
content: the title/status/priority/description plus the discussion —
comments, agent work product, and the resolution/answer (#374). The answer to a
completed issue lives in its comments — the engine posts an agent run's whole
output as a comment — so this is how the Concierge tells a user the outcome of
work it helped file, not just that the issue exists. The discussion is rendered
newest-first (the answer leads) so it survives the chat re-prompt's
head-truncation; the most recent comments are kept under a size budget and, if a
long thread is trimmed, the reply says how many earlier comments were omitted
and points to the issue in Trimus.
The full discussion is DM/web only. In a shared channel or group (a
Slack channel, or a Telegram group/supergroup) the reply is visible to every
member — including unvetted bystanders and external guests who are not the
requester — so /get-issue there returns metadata + description only, even
for a vetted mentioner; the Concierge offers to continue in a DM. Likewise,
unvetted or unpaired chat users get metadata only. No comment content is exposed
to a reader who could not already see it — the same principle as the #265
vetting gate that governs the drive verbs.
/list-issues¶
List issues. Takes no required argument. Reads these hint keys:
| Hint key | Effect |
|---|---|
status: |
Comma-separated status filter (e.g. status: done), or all for every status. With no status: hint the default is the active set (backlog/todo/in_progress/in_review), falling back to all statuses when the active set is empty so a done-heavy company isn't listed as empty (#371). |
assignee: |
Filter by assignee. |
limit: |
Cap the result count. |
/get-note <id>¶
Fetch a single note by id. No hints, no body. Empty id drops the verb.
/list-notes¶
List notes. Reads these hint keys: labels:, q: (search query),
archived:, scope:, limit:.
Notes (CRUD)¶
Notes are a lightweight company scratchpad. See the operator notes guide for the data model.
/create-note <title>¶
Create a note. Reads hint keys labels: and as:. An optional fenced
body becomes the note body.
/create-note Q3 vendor shortlist
labels: procurement
```markdown
Three vendors cleared the security review: ...
### `/edit-note <id-or-title>`
Edit an existing note. Reads hint keys `title:` and `labels:`. An
optional fenced body replaces the note content.
### `/archive-note <id>`
Archive a note. Single line; id is the rest of the line. No hints, no
body.
### `/unarchive-note <id>`
Un-archive a note. Single line, same shape as `/archive-note`.
### `/install-note <title>`
Install a **company-wide** note in one shot. The title is on the verb
line; a fenced body is **required** (title-only or empty-body invocations
are dropped). Lightweight by design — no approval, no capability, no
activity-log row. Agent-authored notes are visible to every operator with
viewer access to the company.
1. SSH to the cache host.
2. Run `trimus-cache flush --confirm`.
3. Verify hit-rate recovers within 2 minutes.
### `/record-finding <one-line title>`
Record an **agent-authored finding** into the Notes index. The title is
on the verb line; a fenced markdown body is **required**. Use this
mid-heartbeat when you land on a "this is worth remembering" observation
— distinct from `/install-note` (an operator-facing scratchpad) and
`/create-issue` (actionable work).
The body may carry inline hashtags, which become the note's tags. The
recognised tags are `#decision`, `#finding`, `#attempted`, `#failed`,
`#escalation`, `#working`, `#blocked`. A body with no recognised tag
gets a default `#finding` tag.
The `invoice.paid` handler double-credits on retry. #finding #failed
Root cause: no dedup on the event id.
---
## Skills, routines, memories, agents, federations
These are the **install verbs**. They let an agent grow the company's
capabilities. The highest-risk ones (skills, agents, federations) install
in a **disabled** state and raise a paired approval — they only become
active after a human approves on the Approvals page. See
[approvals.md](approvals.md) and
[../agents/hiring-and-firing.md](../agents/hiring-and-firing.md).
### `/install-memory <topic>`
Register a **memory** capability — a durable fact the company wants
remembered. The topic (one line of natural language describing the kind
of question this fact answers, e.g. `the budget for project openfang`) is
on the verb line. An optional fenced body carries the fact content. No
approval. Empty topic drops the verb.
### `/install-routine <title>`
Register a **routine** capability — a reusable multi-step procedure. The
title is on the verb line (and is the natural-language trigger future
asks match against). A fenced body is **required** — it becomes the
routine's step list / description that the eventual assignee agent reads
when running it. The routine installs with **no assignee**: an operator
picks the runner and wires any cron/webhook trigger from the UI. No
approval. Title-only or empty-body invocations are dropped.
1. Generate a new key in the provider console.
2. Update the Trimus secret.
3. Confirm the old key is revoked after 24h.
### `/install-skill <name>`
Register a **skill** capability — a reusable markdown prompt snippet that
agents pull into context. The name is on the verb line; a fenced body
(the SKILL.md content) is **required**. **Skills install DISABLED and
raise a paired approval** — they inject text directly into agent prompts,
so an operator audits before activation. Name-only or empty-body
invocations are dropped.
# Draft Incident Postmortem
Use this when asked to write a postmortem. Structure: timeline,
impact, root cause, remediation, action items.
### `/install-agent <Name>`
Provision a **new agent** that will receive heartbeats. The name is on
the verb line; a fenced body (the new agent's `system_prompt`) is
**required**. This is the **highest-risk install verb** — a system prompt
is an ongoing identity, not a one-off action. Defense in depth: the new
agent installs with `status=paused`, `heartbeat_enabled=false`, a
disabled capability, and a paired approval. Approval flips all of those
on. The new agent inherits the installer's adapter / provider / model as
defaults.
Optional hint keys:
| Hint key | Effect |
|----------------|----------------------------------------------------------------|
| `role:` | Role for the new agent (defaults to `general`). |
| `title:` | Short title. |
| `description:` | One-line summary; used as the capability's trigger description. |
| `reports-to:` (also `reports_to:`) | Escalation target, looked up by name; ignored if not found. |
You are the Release Manager. You cut releases, verify CI is green,
and post release notes. You never deploy without an approval.
### `/install-federation <Name>`
Register a pointer to an **external system** the company wants to
delegate certain question types to. The name is on the verb line. A
fenced body is **required** — the federation **contract**: a markdown
description of what the external system handles, its input/output shape,
latency expectations. The contract is rendered into agent prompts when
the capability matches. Installs disabled + raises a paired approval.
Optional hint key: `description:` (overrides the bare name as the trigger
description).
> **Critical:** never put credentials, endpoint URLs, or API keys in the
> contract. The agent never collects auth — an operator wires the
> endpoint and credentials via the UI after approval. This keeps the
> agent-emitted action stateless with respect to secrets.
Handles billing questions. Input: a customer email. Output: current
plan, MRR, and last-invoice status. Typical latency under 2s.
### `/use-skill <name>`
An **audit-trail marker** — "I applied skill X to this response". The
skill body is already in the agent's `## Available Skills` prompt section;
this verb injects nothing new. Its only purpose is the audit trail
(which skills got used, by which agents, on which issues). Drops with a
notice if the name doesn't resolve to a skill in this company. No body.
```text
/use-skill draft-incident-postmortem
/fire-routine <title>¶
Run an installed routine on demand. Looks up the routine by title in the
company, creates a routine_runs row, and spawns a child issue assigned
to the routine's runner with the routine's step list as the body. Drops
with a visible comment if the routine has no assignee yet (operator must
wire the runner) or the title doesn't match. Scheduling (cron/webhook) is
not part of this verb — that stays operator-wired. No body.
/promote-routine [<new-title>]¶
Promote this issue into a recurring routine capability. The issue's
body_markdown becomes the routine description; the optional argument
overrides the title (defaults to the issue title). The new routine
installs with no triggers — agents don't pick crons; that's an
operator decision. No body.
Subagents¶
Subagents let an agent fan work out to short-lived child agents it
spawns. Fan-out is rate-limited (TRIMUS_MAX_SUBAGENT_RUNS_PER_MINUTE).
/spawn-subagent <Name>¶
Mint a child agent. The name is on the verb line; a fenced body (the
child's system_prompt) is required, and a reason: hint is
required (it's persisted to spawn_reason for audit). An optional
role: hint sets the child's role (defaults to general). Missing name,
body, or reason drops the verb.
/spawn-subagent Citation Checker
role: researcher
reason: verify every source in the draft before publication
```markdown
You are a citation checker. For each source in the parent issue,
confirm the URL resolves and the claim matches.
### `/await-subagents`
Dispatch one heartbeat run for each of the parent's **direct** active
children. Emit this in a follow-up turn after `/spawn-subagent` calls.
The handler posts a system marker with the count dispatched so the parent
can see what happened next turn. No arguments, no body.
### `/await-subagents-recursive`
Same as `/await-subagents`, but BFS-walks the parent's **entire** subtree
(children, grandchildren, …) and dispatches a run for every active
descendant. Use when the parent wants every descendant to make one tick
of progress without waiting for each depth-1 child to itself await its
own children. Shares the same fan-out rate-limit budget. No arguments, no
body.
---
## Routing and input
### `/needs-routing [<summary>]`
Flag this issue for (re-)routing. Sets `needs_routing = TRUE`; on the next
routing scan, the matcher runs against the pool of local + remote (A2A)
agents and either assigns a local agent (clearing the flag) or dispatches
via the A2A cascade. Cascade exhaustion flips `needs_human_attention`.
The optional trailing summary becomes a comment; an optional fenced body
adds longer context (the matcher uses both as input). Use when you can't
make progress and the issue needs a different assignee.
```text
/needs-routing This needs a security specialist, not a generalist.
/await-input [<question>]¶
Pause work on this issue until a non-agent comment lands. Sets
awaiting_input = TRUE. The optional trailing text is posted as a comment
(before the flag flips) so the human sees what's being asked. No fenced
body; empty questions are allowed (the agent may have already explained
the situation in its prose). Use when you can't proceed without operator
clarification.
User modeling¶
/update-user-model¶
Update a user's opt-in profile (profile_markdown). The agent emits this
mid-chat to record durable facts about a user. A user: hint is
required (an email or UUID identifying the profile owner); a fenced
body is required (the whole new profile, not a diff). Missing
user: or body drops the verb. The verb has no trailing-text value — the
user: hint is the identifier.
/update-user-model
user: jordan@example.com
```markdown
Prefers terse status updates. Works in the payments domain. Reviews
PRs on Tuesdays.
> **Privacy:** the handler checks `user_models.enabled` before writing.
> If the user has not opted in, the write is a no-op — an agent cannot
> populate a profile the user hasn't agreed to.
---
## Filesystem
### `/write-file <path>`
Persist a file. The workspace-relative path is on the verb line; the file
body is the next fenced block (**required** — a missing fence drops the
action and preserves the verb line as prose).
Rules:
- Path must be **relative**. Absolute paths and `..` traversal are
rejected; so are null bytes and empty path segments.
- Subdirectories are auto-created.
- Per-file cap: **4 MiB** (`content exceeds 4194304 byte limit`).
- The opening fence's language hint is informational and discarded; the
body is captured verbatim. The closing fence must be exactly three
backticks on its own line.
- Multiple `/write-file` actions in one reply all apply; one failure
doesn't abort the others.
Unlike older versions of Trimus, `/write-file` **does not silently drop
when the issue has no project**. The engine resolves a destination
through a four-tier cascade — project workspace → company files dir →
instance files dir → (last resort) inline the body as an issue comment so
the content is never lost. The full semantics, including the cascade and
how to handle them gracefully in a skill, are in
[../agents/the-write-file-action.md](../agents/the-write-file-action.md).
---
## Reports
### `/report <title>`
Persist a **report** work-product on the current issue. A one-line title is
on the verb line; a triple-backtick fenced markdown body is **required**.
The engine stores a work-product of **type `report`** and posts a
confirmation comment on the issue.
## Signups
Up 12% week-over-week, driven by the docs launch.
## Churn
Flat at 2.1%. No action needed this week.
- An **empty title**, or a **missing / empty fenced body**, drops the
action and keeps the line as prose (so the malformed attempt stays
auditable).
- `/report` is **heartbeat-only** — it is emitted by a persona agent working
a report routine, grounded by the pre-injected metrics snapshot (#267). It
is not available in chat.
- Aliases `/write-report` and `/write_report` are accepted.
---
## What is NOT a verb
Several things look like verbs but are not. Lines starting with these are
treated as prose and left in the visible comment:
- `/comment`, `/note`, `/say` — a comment is just prose. Anything not
consumed as a verb becomes the comment.
- `/done`, `/close`, `/finish` — use `/status done`.
- `/block`, `/blocked` (without `-by`) — use `/status blocked` for the
current issue, or `/blocks <ref>` for a relation.
- `/approve`, `/reject` — agents request approvals (`/request-approval`)
but cannot resolve them.
- `/hire`, `/fire`, `/terminate` — hiring and firing happen via the REST
API, usually wrapped in a skill. See
[../agents/hiring-and-firing.md](../agents/hiring-and-firing.md). (The
closest verb is `/install-agent`, which provisions a *paused* agent
pending approval.)
- `/run`, `/exec`, `/bash` — there is no shell verb. Real filesystem and
command execution require a CLI-backed adapter (`claude_local`,
`codex_local`, or their sandboxed variants).
Unknown verbs are logged at DEBUG (`unknown verb`) and kept as prose, so
the human reading the timeline still sees what the agent tried to do.
## How to verify a verb landed
Three places to look:
- The issue's **Timeline** shows a discrete activity entry for each
applied action (status change, relation added, file written, approval
requested, child issue created).
- The agent's **Runs** tab → open the run → the parsed-actions list and
the full transcript.
- For `/write-file`, also check the project's **Workspace Files** panel.
If a verb you expected is missing everywhere, the engine probably didn't
parse it. Check the format rules at the top of this page (verb at start of
line? recognised spelling? required body present?), enable
`TRIMUS_DEBUG=parser` to see drop reasons in the logs, and read
[../agents/debugging-agents.md](../agents/debugging-agents.md).
## Chat verbs (#265)
Chat is a first-class verb surface. A **vetted, paired** user (admin-managed
on the company Pairings page) can drive Trimus from web chat, Slack, or
Telegram; unvetted users keep the read verbs (`/get-issue`, `/list-issues`,
`/get-note`, `/list-notes`). A vetted user on a 1:1 surface (DM or web)
additionally sees an issue's full discussion/resolution via `/get-issue`
(#374); unvetted readers — and everyone in a shared channel — get metadata only.
Because a chat has no bound issue, the issue-scoped verbs take an
`issue: <ref>` continuation line (identifier like `ACME-42`, a UUID/prefix,
or an issue title):
```text
/status in_progress
issue: ACME-42
Available in chat: /status, /priority, /assign, /blocks,
/blocked-by, /relates (each with the issue: hint), /fire-routine
<title>, plus the create/note verbs listed above. /checkout, /release,
/write-file, and the install-* verbs stay heartbeat-only.
Chat ↔ Issues parity (broad reads + issue conversation)¶
The chat surface can read broadly across Trimus and converse on issues, for a
paired + vetted user, with authority never exceeding the web (the required
company role for each action mirrors the equivalent web route). Sensitivity is
tiered by audience: never-in-chat (secrets/keys — never rendered),
DM/web-only (work-products, budgets, agent config), and channel-safe
(titles/status/counts).
Generic reads:
/show <entity> <ref>— read oneagent,project,goal,routine,budget, orapprovalby name or id. Channel-safe metadata renders anywhere; config fields (agent model/adapter/system prompt, project working-dir/repo) and the wholebudgetentity are DM/web-only — in a shared channel they're redacted with a "DM me" pointer.budgetadditionally requires the admin role./list <entity>— list them, with optionalstatus:/limit:/level:filter continuation lines.
Issue conversation writes (each takes an issue: <ref> hint):
/comment— post a reply on an issue (authored by you, so a linked account is required). By default it dispatches the assigned agent to work your reply (creating a heartbeat run, exactly like the web "Comment & Resume"); addresume: falseto comment without dispatching. A stalled issue (blocked / in-review) is moved to in-progress first; a done or cancelled issue is not reopened (use/statusfor that), and a paused or unassigned issue is not dispatched — the confirmation says which happened. The reply text is a fenced block or abody:line./edit-issue— change the issue's title (title:hint) and/or body (fenced block)./cancel-issue— cancel the issue.
Approvals & routines writes:
/resolve-approval(withapproval: <id or title>+decision: approve|reject+ optionalreason:) — approve or reject a pending approval, running the same downstream effects as the web (comments the linked issues, unblocks + wakes the assigned agent on approval). Human-only./set-routine-status active|paused(withroutine: <id or title>) — enable or disable a routine.
Delivery-back: when you drive an agent on an issue from chat (a /comment
that resumes it, or an issue you created from chat), the agent's reply is
delivered back into your chat once it finishes — you don't have to poll. This
happens only in a 1:1 DM (never a shared channel/group), and exactly once (a
later heartbeat run won't re-push).
Discovery:
/capabilities— asks the agent to list what you can read and do here, filtered to your role, vetting, and surface.
All writes are drive verbs behind the vetting gate; unknown entities, role denials, and missing input return a visible marker (never a silent no-op).
Multi-agent threads: address any chat-capable agent with @Agent-Name
(hyphens match spaces: @lead-researcher finds "Lead Researcher"). The
mention routes that turn only — the chat's current agent stays the default
responder. Mention several agents and they reply in order, each seeing the
previous replies; every reply is labeled with its author.