Agent cockpit¶
/inbox is the new home screen for agents — a persistent, saved-view
filterable inbox with bulk actions, plus /note for internal-only
comments inside ticket topics, plus an auto-rendered customer history.
Feature flag
Gate on with FEATURE_AGENT_INBOX=true. Default is off so the
legacy /queue stays authoritative until teams are briefed.
/inbox¶
Opens the inbox as a single message with:
- Saved-view chips along the top: My open / Unassigned / Overdue / High / All open
- Ticket rows with a checkbox, priority icon, SLA-at-risk flag, unassigned flag, and a trimmed title
- Bulk-action footer (shown only when the selection is non-empty): Close, Assign me, Priority: High, Priority: Low, Clear selection
- Pagination when more than 10 tickets match
Everything is one in-place edit — switching views, toggling a ticket, paging back and forth never spawns a new message.
Saved views¶
| Key | What it shows |
|---|---|
my_open |
Tickets assigned to you, status=open (default) |
unassigned |
Status=open, no assignee |
overdue |
SLA warned or past breach deadline |
high_priority |
Priority=high |
all_open |
Everything still open |
by_tag:*, by_team:*, by_project:* filters are scaffolded in the
selection state — wiring them to user-editable saved views is a
follow-up.
Selection state¶
Your current selection persists in the user FSM, so switching views or paging preserves what you picked. Clicking Clear (or running a bulk action) empties it.
Bulk actions¶
Every bulk action goes through the shared
xtv_support.services.actions.ActionExecutor, so:
- One
ActionExecutedevent per ticket per action (audit-log friendly) BulkActionStarted/BulkActionCompletedwrap the run- Failures don't abort the batch — you get a count back
(
Bulk close: 4 ok, 1 failed)
Header controls¶
The ticket header card carries Assign · Tag · Priority · Close. Each acts
inside the header message itself — tapping Assign/Tag/Priority swaps the card's
buttons to the relevant picker (with a ◀ Back / ✅ Done button), and choosing an
option re-renders the header in place. Nothing is posted or deleted around it, so
the topic stays clean. Close shows a ✅ Confirm close / ◀ Back step before it
closes the ticket and its forum topic. The /tag, /assign topic commands still
work as power-user shortcuts.
/note <text>¶
Inside a ticket topic thread, appends an internal note to the ticket's
internal_notes field. Notes:
- Are never forwarded to the customer
- Live in a separate field from the public
historyso no future "history forwarder" can leak them - Fire the same
ActionExecuted(action="add_internal_note")event as the API + bulk path - Show up on the ticket header re-render as a collapsible section
Example:
/note customer escalated via email as well; see thread
Returns:
📝 Internal note added (3 total — hidden from the customer).
Two-way conversation¶
A ticket's forum topic mirrors the full conversation. When the user keeps writing — from the bot chat or the Mini-App / web console — each message is appended to the ticket history and posted into the topic, so agents see everything in one place. Closing from the web console also closes the topic and notifies the user, identical to closing from the bot. Agents reply from the topic side (their own messages in a private chat are not treated as ticket replies).
Customer history card¶
When a new topic is created for a user with a history
(FEATURE_CUSTOMER_HISTORY_PIN=true, default on), a short card gets
pinned at the top of the thread:
👤 Customer history — Ada
ID 42
💎 VIP
7 tickets total (6 closed) · ⭐ 4.8 CSAT avg · ⏱ 12m first response
Last tickets
• [closed] Refund issue
• [open] Password reset
The renderer is pure — you can reuse it from the API or plugins via
xtv_support.ui.templates.agent_inbox.render_customer_history.
Quick-reply menu (coming)¶
Plan 4.5 also sketches a button-driven macro picker with preview +
edit-before-send. The repo helper
services/macros/service.list_for_agent is in place; the inline-menu
wiring lands in a follow-up commit.
Audit story¶
Because the cockpit uses ActionExecutor with origin="bulk" (for
/inbox) or origin="bot" (for /note), every write is attributable.
Run:
/rules # ... or audit-log queries
and you see exactly who did what and from which surface.
Known gaps (scheduled)¶
- Custom user-defined saved views (
by_tag,by_team, etc.) - "Next unread ticket" queue walker
- Quick-reply menu in topics
- Typing indicators / read receipts forwarded