HITL — UI Patterns
How approvals are surfaced, displayed, and actioned across every interface — DM Portal, Dashboard, Mobile, and CLI.
See also: Approval Flow — full lifecycle | HITL Index — all touchpoints Screen specs: DM Portal Screens | Dashboard Screens | Mobile | CLI Commands
Where Approvals Surface
| Interface | Primary surface | Secondary surface |
|---|---|---|
| DM Portal | Approval Queue (P2) — cross-tenant list | Activity Detail (P3) — inline review |
| Dashboard | Approvals Queue (D5) — tenant’s own | Campaign Detail (D4) — per-activity |
| Mobile | Approvals tab — push-notification entry point | — |
CLI (lm) | /queue — terminal table | /stream + /approve — inline |
DM Portal — The Primary Review Interface
The DM Portal is where the bulk of HITL decisions are made. Reviewers see work across all their assigned tenants in one place.
P2 — Approval Queue
┌─────────────────────────────────────────────────────────────────────┐
│ Approvals [Bulk select ▾] [Filter]│
├─────────────────────────────────────────────────────────────────────┤
│ │
│ 🔴 HIGH RISK (2) │
│ ─────────────────────────────────────────────────────────────── │
│ ☐ Q2 Newsletter — April 2026 Globex Corp email 2h │
│ Content review · Email campaign · Expires in 22h │
│ ✅ Sarah K. approved · ⏳ Tenant admin pending │
│ [Review]│
│ │
│ ☐ Live Ad Push — Google Ads Campaign Acme Corp ads 45m │
│ Channel action · Google Ads · Expires in 23h │
│ [Review]│
│ │
│ 🟡 MEDIUM RISK (4) │
│ ─────────────────────────────────────────────────────────────── │
│ ☐ LinkedIn — Week 14 Acme Corp social 3h │
│ Content review · Social post │
│ [Review]│
│ ☐ Facebook — Week 14 Acme Corp social 3h │
│ Content review · Social post │
│ [Review]│
│ │
│ 🟢 LOW RISK (8) │
│ ─────────────────────────────────────────────────────────────── │
│ ☐ "Why Local SEO Matters" Acme Corp blog 18h │
│ ☐ "Top 5 Plumbing Tips" Acme Corp blog 18h │
│ ☐ "GBP Profile Optimisation" Acme Corp blog 17h │
│ ☐ + 5 more [Show all]│
│ │
│ ────────────────────────────────────────────────────────────────── │
│ Selected: 0 items [Approve all low]│
└─────────────────────────────────────────────────────────────────────┘Visual conventions:
- 🔴 / 🟡 / 🟢 risk badges are always shown — reviewers learn to scan by colour
- High-risk items always appear at the top, regardless of age
- Items approaching expiry show a countdown:
Expires in 4h ⚠with amber text - Expired items appear in a separate
🚨 EXPIREDsection at the very top - Dual-approval items show which sign-offs are pending inline on the queue row
- Bulk select + “Approve all low” is available for fast processing of large low-risk queues
Filtering options:
- By tenant, risk level, type, agent role, age
- “Assigned to me” vs “All reviewers”
P3 — Activity Detail (HITL review pane)
Opening a content_review approval for a blog post:
┌──────────────────────────┬──────────────────────────────────────────┐
│ ← Approvals │ Content Review │
│ │ "Why Local SEO Matters" │
│ Acme Corp │ blog_post · low risk · 18h ago │
│ "Why Local SEO ├──────────────────────────────────────────┤
│ Matters" │ Agent: blog-writer │
│ │ Model: claude-sonnet-4-6 │
│ ───────────────────── │ Tokens: 4,812 in / 1,204 out │
│ Validator results │ Cost: $0.018 │
│ │ Duration: 3m 40s │
│ ✅ Word count: 1,240 ├──────────────────────────────────────────┤
│ (min 800) │ ▸ Retrieved context (3 RAG queries) │
│ ✅ Sections: 5/5 │ client_docs · website_content │
│ ✅ Brand voice: 82/100 ├──────────────────────────────────────────┤
│ ✅ No banned words │ │
│ │ # Why Local SEO Matters for │
│ ───────────────────── │ Brisbane Plumbers │
│ Skills used │ │
│ client-context-file │ Local SEO is no longer optional for │
│ seo-brief │ businesses that rely on customers in │
│ │ a specific area. For a plumbing │
│ ───────────────────── │ business in Brisbane, ranking on page │
│ Approval expiry │ one for "plumber near me" can be the │
│ In 54 hours │ difference between… │
│ │ │
│ │ [full content scrollable] │
│ │ │
│ ├──────────────────────────────────────────┤
│ │ Reviewer notes (optional for approve, │
│ │ required for reject) │
│ │ ┌──────────────────────────────────┐ │
│ │ │ │ │
│ │ └──────────────────────────────────┘ │
│ │ │
│ │ [Edit content] │
│ │ [Reject ↩] [Approve ✓] │
└──────────────────────────┴──────────────────────────────────────────┘“Edit content” flow:
- Opens the content in an inline rich-text editor
- Reviewer makes changes (typos, tone, factual fixes)
- Clicks “Approve edited version” → edited content saved as final, no retry
For content_direction / brand_direction approvals with options:
Direction needed:
"Should this blog target informational or commercial intent?"
○ Informational — "How to find a reliable plumber in Brisbane"
Target: top-of-funnel, build authority
○ Commercial — "Best emergency plumber in Brisbane"
Target: high-intent, conversion-focused
[Reject ↩] [Approve selected option ✓]For channel_action approvals (write-tool gate):
Channel Action Pending
Action: Publish post to WordPress
Site: acmecorp.com.au
Post: "Why Local SEO Matters"
Status: Will publish immediately on approval
⚠ This action cannot be undone once executed.
[Cancel action ✗] [Approve & publish ✓]Dashboard — Tenant Self-Approval
Tenants see their own approvals in the Dashboard. They cannot see approvals for other tenants.
D5 — Approvals Queue
Same layout as DM Portal P2 but scoped to the tenant’s content only. Tenants see:
content_reviewapprovals for their deliverablesstrategy_changeandbudget_authorizationapprovals that require their sign-off- The second sign-off prompt when a DM reviewer has already approved
┌──────────────────────────────────────────────────────┐
│ Approvals [Filter] │
├──────────────────────────────────────────────────────┤
│ │
│ ACTION REQUIRED FROM YOU (1) │
│ ───────────────────────────────────────────────── │
│ Q2 Newsletter — April 2026 email high │
│ Sarah K. (DM team) has approved this. │
│ Your sign-off is also required before sending. │
│ [Review] │
│ │
│ PENDING DM REVIEW (3) │
│ ───────────────────────────────────────────────── │
│ "Why Local SEO Matters" blog low │
│ "Top 5 Plumbing Tips" blog low │
│ LinkedIn — Week 14 social medium │
│ │
└──────────────────────────────────────────────────────┘Tenants see “Pending DM Review” items as read-only — they can see what is in the queue but cannot action items that are pending the DM reviewer’s turn.
D4 — Campaign Detail → Activity tab
Each activity card in the activity list shows its approval status inline:
┌──────────────────────────────────────────────────────────────┐
│ 🤖 Blog Writer — "Why Local SEO Matters" │
│ Status: ⏳ Awaiting approval · risk: low · 18h │
│ Cost: $0.018 · Duration: 3m 40s │
│ │
│ [View content] [Approve ✓] [Reject ↩] │
└──────────────────────────────────────────────────────────────┘Clicking “View content” expands the card inline with the full output + validator results — no page navigation required for simple approvals.
Mobile — Push-First Approval Flow
Mobile is designed for the approval use case specifically. The primary entry point is a push notification, not the app.
Push notification → deep link
📝 Blog post ready to review — Acme Corp
"Why Local SEO Matters" · low riskTapping the notification deep-links directly to the review screen for that specific approval — not to the approvals list.
Mobile approval review screen
┌──────────────────────────────────────┐
│ ← Approvals ≡ │
│ │
│ Why Local SEO Matters │
│ blog post · low risk · 18h ago │
│ ──────────────────────────────── │
│ Acme Corp · blog-writer │
│ 1,240 words · $0.018 · 3m 40s │
│ │
│ ──────────────────────────────── │
│ Local SEO is no longer optional │
│ for businesses that rely on │
│ customers in a specific area. │
│ For a plumbing business in │
│ Brisbane, ranking on page one │
│ for "plumber near me" can be… │
│ │
│ [Read full post ↓] │
│ │
│ ──────────────────────────────── │
│ Notes (required to reject) │
│ ┌──────────────────────────────┐ │
│ │ │ │
│ └──────────────────────────────┘ │
│ │
│ ┌────────────┐ ┌────────────────┐ │
│ │ Reject ↩ │ │ Approve ✓ │ │
│ └────────────┘ └────────────────┘ │
│ │
│ Approving triggers haptic feedback │
└──────────────────────────────────────┘Mobile-specific UX notes:
- Action bar is pinned to the bottom — always visible without scrolling
- Approve triggers haptic feedback (success pattern) + green flash
- Rejection note entry uses a keyboard-aware bottom sheet so the input is never hidden
- Swipe right on an approval card in the list = quick approve (with haptic + undo toast)
- Swipe left = flag for later (snooze 2h)
- Offline: decision is queued locally and submitted when connectivity returns. A banner shows: “Your approval will be submitted when you’re back online.”
Approvals tab (bottom bar)
The Approvals tab shows a badge with the count of pending items. The tab itself has two sub-sections:
[Needs your action] [Pending DM review]“Needs your action” = approvals where the tenant admin is the blocker (strategy_change, budget_authorization, dual sign-off). These are sorted to the top and badged on the tab icon.
CLI — Terminal Approval Patterns
See CLI Commands — /approve, /reject, /bulk-approve for full command docs.
/queue output
lm [Acme Corp] › /queue
🔴 High Risk (1)
─────────────────────────────────────────────────────────────────
A-1250 channel_action "Publish Q2 Newsletter to Mailchimp" 45m
🟡 Medium Risk (2)
─────────────────────────────────────────────────────────────────
A-1253 social_post "LinkedIn — Week 14" 3h
A-1254 social_post "Facebook — Week 14" 3h
🟢 Low Risk (3)
─────────────────────────────────────────────────────────────────
A-1234 blog_post "Why Local SEO Matters" 18h
A-1235 blog_post "Top 5 Plumbing Tips" 18h
A-1236 blog_post "GBP Profile Optimisation" 17hInline review with /stream + /approve
lm [Acme Corp] › /stream A-1234
Content Review — "Why Local SEO Matters"
blog_post · low risk · 18h ago · $0.018
Validator: ✅ word_count ✅ brand_voice:82 ✅ no_banned_words
──────────────────────────────────────────────────────────────────
# Why Local SEO Matters for Brisbane Plumbers
Local SEO is no longer optional for businesses…
[full content]
[/approve A-1234] [/reject A-1234 --reason "..."]
lm [Acme Corp] › /approve A-1234
✅ Approved. "Publish to WordPress" queued.Bulk approve
lm [Acme Corp] › /bulk-approve --filter "risk=low"
Preview — 3 blog posts will be approved:
A-1234 "Why Local SEO Matters"
A-1235 "Top 5 Plumbing Tips"
A-1236 "GBP Profile Optimisation"
Confirm? [y/N] › y
✅ 3 approved. Publish activities queued for all 3.In-App Notifications (Web Bell)
The bell icon in the top navigation shows a badge count of unread notifications. Clicking it opens a dropdown:
┌──────────────────────────────────────────────┐
│ Notifications Mark all ✓ │
├──────────────────────────────────────────────┤
│ 🔴 Q2 Newsletter needs your sign-off │
│ Globex Corp · email · 45 min ago │
│ [Review →] │
│ │
│ 📝 3 blog posts ready to review │
│ Acme Corp · low risk · 18h ago │
│ [Queue →] │
│ │
│ ✅ "LinkedIn Week 14" was approved │
│ by Sarah K. · 2h ago │
│ │
│ ⏱ Approval expiring in 4h │
│ "Live Ad Push" — Acme Corp │
│ [Review →] │
└──────────────────────────────────────────────┘Notification types in the bell:
- New approval requiring action (links to review screen)
- Approval approved / rejected by someone else (informational)
- Approval expiry warning (4h before expiry)
- Budget cap alert
- Channel disconnected (token expired)
- Agent error / escalation
The bell updates in real time via SSE — no page refresh needed.
Notification Preferences
Users can configure which events trigger which channels in Settings → Notifications:
| Event | Web (always) | SMS | Push | |
|---|---|---|---|---|
| New high-risk approval | ✅ on | ✅ on | configurable | ✅ on |
| New medium-risk approval | ✅ on | ✅ on | off | ✅ on |
| New low-risk approval | ✅ on | digest | off | configurable |
| Approval expiry warning | ✅ on | ✅ on | off | ✅ on |
| Approval resolved by colleague | ✅ on | off | off | off |
| Budget alert | ✅ on | ✅ on | configurable | ✅ on |
| Agent error | ✅ on | ✅ on | off | ✅ on |
Defaults shown above. Users can turn off any channel except web (in-app) for any event.