h.work — Client × AI Specialist Interaction Product Documentation
Corrected: 2026-08-05 | Scope: WebChat · Slack Channel · Expert Dashboard
The conversation/runtime contract in ADR-046 is authoritative. Known implementation deviations are listed in its remediation ledger; a legacy code path is not an allowed product alternative.
I. Overall Architecture
Client (org_admin / org_member)
├── WebChat (/client/chat)
└── Slack Channel (DM or Channel @mention)
↓
API (NestJS) — Unified message entry point
↓
Managed Hermes session — canonical Specialist reply
↓
Reply delivered once through the original channel
└── Optional after-delivery Expert observation/correction
Core Principles
- Messages from all channels remain conversation-scoped and channel-separated
- Every successful Hermes reply is delivered once; confidence, risk, review, clarification, and approval state never withhold it
- Humanwork sends only the exact user message and native attachment blocks; Hermes owns history, retrieval, tools, and response behavior
- Message deduplication and idempotent writes prevent duplicate processing
II. WebChat Module
2.1 Feature Description
After signing in, the Client enters /client/chat and can:
- View all Specialists assigned to the current org (profile area on the left)
- Start a new Thread (conversation) with each Specialist
- Maintain multiple independent Threads for the same Specialist
- Send text, images, files, and other attachments
- Receive AI Specialist replies through scoped Socket.io mutation events; reconnect performs one bounded catch-up read and idle time performs no polling
2.2 Current Implementation Status
| Feature | Status |
|---|---|
| Specialist selection + profile display | ✅ Implemented |
| New Thread / Thread list (left sidebar) | ✅ Implemented |
| Send messages (text) | ✅ Implemented |
| Message attachments (images/files) | ✅ Implemented |
| Receive replies in real time via Socket.io | ✅ Implemented |
| Rename Thread / Resolve / Reopen | ✅ Implemented |
| Unread message badge | ✅ Implemented |
| Threads sorted by latest message time, descending | ✅ Implemented |
| Thread status display (in_progress / awaiting_client / resolved) | ✅ Implemented |
| Channel source indicator (Slack/Email/WhatsApp icon) | ✅ Implemented |
2.3 Message Flow
Client enters message → POST /conversations/:id/messages
↓ Immediate response (201)
Asynchronously in background: runAgentPipeline()
→ Humanwork sends the exact message and real attachment blocks to the existing Hermes session
→ Hermes resumes SessionDB and retrieves or uses tools on demand
→ Every successful canonical reply is stored and pushed once to the Client; a genuine failure remains a failure
→ Expert observation/correction is optional and happens after delivery
2.4 Outstanding Items
| # | Issue | Priority |
|---|---|---|
| W-1 | When creating a new Thread, if the org has multiple Specialists, the Client must explicitly select a Specialist before creation | High |
| W-2 | The Thread list lacks an icon for the native WebChat source when displaying channel origins (only external-channel icons such as email/slack exist) | Medium |
| W-3 | The Client lacks clear feedback for message status (sending / delivered / failed) | Medium |
| W-4 | Attachment preview: inline image preview exists, but PDFs/files are displayed only as chips and cannot be previewed | Low |
III. Slack Channel Module
3.1 Design Goals
Each AI Specialist has a dedicated Slack App. After a Client org installs the App in its Slack Workspace, employees can communicate with that Specialist through:
- DM: Send a direct message to the Slack App
- Channel @mention: @mention the App in any channel
- Bound Channel (opt-in): After binding a channel to a Specialist, all messages in that channel (without requiring an @mention) are routed to that Specialist
3.2 Slack App Activation Flow
SuperAdmin / AM generates a Slack App Manifest for a Specialist in the Ops console
↓
Create an App in the Slack API Console using the Manifest (including bot scopes / Events API / OAuth)
↓
Configure the App's Client ID / Client Secret / Signing Secret in Humanwork
↓
Store the Specialist ↔ Slack App association in IntegrationCredential (encrypted at rest)
↓
Client org administrator clicks "Add to Slack" → OAuth 2.0 authorization flow
↓
oauth.v2.access → Store bot_token in IntegrationCredential (org level)
↓
Activation complete: employees in the org can communicate with the Specialist via DM / @mention
3.3 Message Trigger Strategy (Three Layers, from the PRD)
Layer 1 — Hard Triggers (Must Respond)
- Direct message to the Slack App
- Direct @mention of the Bot
- Follow-up messages in a previously engaged Thread (Thread continuation)
Layer 2 — Contextual Scoring (Intelligent Evaluation, Phase 2)
composite_score = channel_weight × (keyword_match + question_intent)
score > relevance threshold → Deliver the real message to Hermes
else → Store silently (silent ingest)
Layer 3 — Implicit Relevance (Semantic Vector Matching, Phase 3)
- Embedding similarity matching
- Cold start requires labeled data
3.4 Message Processing Flow
Slack Events API → POST /channels/slack/events
↓ Verify HMAC-SHA256 signature → Immediately return 200
↓
BullMQ channels-inbound queue (asynchronous)
↓
handleRuntimeEvent()
├─ Resolve orgId through team_id → IntegrationCredential
├─ Dedup: event_ts / event_id already processed? → Skip
├─ Determine Trigger type: DM / @mention / Bound Channel / Thread continuation
│ └─ silent ingest (trigger conditions not met) → Store in channel_context_messages
↓
findOrCreateConversation() (Slack user → customer mapping)
↓
conversationsService.sendMessage() [Synchronously await Agent]
↓
Hermes resumes SessionDB and generates the canonical reply
↓
BullMQ channels-outbound
↓
slack.chat.postMessage(channel, text, thread_ts) Reply in the original thread
3.5 Current Implementation Status
| Feature | Status |
|---|---|
| Slack App Manifest generation (SlackManifestSuggester) | ✅ Implemented |
| OAuth 2.0 installation flow (Add to Slack) | ✅ Implemented |
| HMAC-SHA256 signature verification | ✅ Implemented |
| DM message receipt + routing | ✅ Implemented |
| @mention message receipt + routing | ✅ Implemented |
| Thread continuation tracking (slack_engaged_threads) | ✅ Implemented |
| Bound Channel (opt-in, no @mention required) | ✅ Implemented |
| Message Dedup (Redis NX + event_ts) | ✅ Implemented |
| Silent ingest (channel_context_messages) | ✅ Implemented |
| Send Expert replies back to Slack thread | ✅ Implemented |
| Dedicated Slack App for each Specialist | ⚠️ Supported by the architecture, but the current OAuth configuration is globally shared (single SLACK_CLIENT_ID) |
| Layer 2 Contextual Scoring | 🔲 Not implemented (Phase 2) |
| Layer 3 semantic vector matching | 🔲 Not implemented (Phase 3) |
3.6 Outstanding Items
| # | Issue | Priority |
|---|---|---|
| S-1 | Dedicated Slack App for each Specialist: OAuth currently uses global SLACK_CLIENT_ID/SECRET; per-Specialist App credential configuration and installation flows are required | High |
| S-2 | Client-side Slack connection management UI: display connected workspaces and bound channels, with disconnect/reconnect actions | High |
| S-3 | Bound Channel binding UI (currently back-office only; client admins need self-service access) | Medium |
| S-4 | Implement the Layer 2 Contextual Scoring engine | Medium |
| S-5 | Forward image/file attachments in Slack messages to the Expert Dashboard | Medium |
| S-6 | Support rich-text formatting in Expert replies (Slack mrkdwn) | Low |
IV. Expert Dashboard Module
4.1 Feature Description
After signing in, the Expert enters /workspace/queue and can:
- Handle explicit human requests and genuine failures from WebChat + Slack + Email + WhatsApp; ordinary successful deliveries create no work item
- View the canonical Specialist reply and real tool/failure evidence available for audit
- Correct the canonical reply or author a genuine follow-up when needed
- View canonical SessionDB history plus recorded Expert follow-ups
- Sort by multiple dimensions (risk level / creation time / SLA)
4.2 Current Implementation Status
| Feature | Status |
|---|---|
| Attention list (explicit human requests and genuine failures only) | ✅ Implemented |
| Canonical reply / failure evidence display | ✅ Implemented |
| Compatibility confidence/risk metadata (observability only) | ✅ Implemented |
| Expert correction and genuine follow-up | ✅ Implemented |
| Corrected/follow-up reply through original channel (webchat/slack/email) | ✅ Implemented |
| Conversation history (complete message list) | ✅ Implemented |
| Channel source indicator (email/slack, etc.) | ✅ Implemented (email has a badge; other channels need improvement) |
| SLA timer | ✅ Implemented |
| Keyboard shortcuts | ✅ Implemented |
| Real-time new-message notifications via Socket.io | ✅ Implemented |
| Unread message badge | ✅ Implemented |
| Conversation sorting (risk/time/SLA) | ✅ Implemented |
| Message attachment display (images/files) | ✅ Implemented (WebChat attachments; Slack attachment forwarding remains outstanding) |
| Multi-Specialist filtered view | ⚠️ Currently filtered by expert_access permissions; no UI switcher |
| Unread count display (per-conversation) | ⚠️ A global unreadCount exists; per-conversation counts require confirmation |
| Conversation status management | ⚠️ Status values exist (pending/awaiting_client/resolved), but their semantics and transition rules need clarification |
4.3 Outstanding Items
| # | Issue | Priority |
|---|---|---|
| E-1 | Standardize Channel source indicators: display a source badge for every channel (webchat/slack/whatsapp/email) in the Queue list and conversation details | High |
| E-2 | Forward Slack attachments: images/files in Slack messages must be forwarded for viewing in the Expert Dashboard | High |
| E-3 | Clarify conversation status definitions: define the semantics, transition conditions, and UI display rules for pending / open / awaiting_client / resolved | High |
| E-4 | per-Specialist view: when an Expert can access multiple Specialists, support filtering conversations by Specialist | Medium |
| E-5 | Unread message count per-conversation: display the exact unread count for each conversation in the Thread list | Medium |
| E-6 | Rich-text message rendering: formatted display of Slack mrkdwn, Markdown, link previews, and related content | Medium |
| E-7 | Internal Note: internal communication messages between Experts (API exists; UI completeness requires review) | Low |
V. Consolidated Task List
Module 1: Expert Dashboard
| Task ID | Task Description | Priority | Dependency |
|---|---|---|---|
| E-1 | Standardize source badges for all channels in the Queue list (webchat/slack/email/whatsapp) | P0 | — |
| E-2 | Forward Slack attachments: storage + display (Slack images/files viewable in the Expert Dashboard) | P0 | S-5 |
| E-3 | Define and implement conversation status transition rules (including UI status labels) | P0 | — |
| E-4 | per-Specialist filtered view | P1 | — |
| E-5 | Exact per-conversation unread message counts | P1 | — |
| E-6 | Rich-text message rendering (Markdown + Slack mrkdwn) | P2 | — |
| E-7 | Internal Note UI completeness acceptance | P2 | — |
Module 2: Slack Channel
| Task ID | Task Description | Priority | Dependency |
|---|---|---|---|
| S-1 | Support independent per-Specialist Slack App credentials (separate Client ID/Secret/Signing Secret for each) | P0 | — |
| S-2 | Client Admin Slack connection management UI (display connected workspaces / disconnect / reconnect) | P0 | S-1 |
| S-3 | Self-service Bound Channel binding UI (available to Client Admin) | P1 | S-2 |
| S-4 | Layer 2 Contextual Scoring engine (PRD Phase 2) | P1 | — |
| S-5 | Forward image/file attachments in Slack messages to the Expert Dashboard | P1 | — |
| S-6 | Support Slack mrkdwn in Expert replies | P2 | E-6 |
Module 3: WebChat
| Task ID | Task Description | Priority | Dependency |
|---|---|---|---|
| W-1 | Support selecting a target Specialist when creating a new Thread (multi-Specialist org scenario) | P0 | — |
| W-2 | Client-side message sending status feedback (sending / delivered / failed) | P1 | — |
| W-3 | Add the missing WebChat source icon (channel dot) | P2 | — |
| W-4 | PDF/document attachment preview (currently displayed only as a chip) | P2 | — |
VI. Key Data Models
| Entity | Description |
|---|---|
conversations | Each Thread, including channel / status / agentName / orgId |
messages | Canonical message records, including role (user/ai/expert) and real attachments; compatibility review fields cannot gate delivery |
expert_queue_items | Optional Expert observation/correction work records, never a prerequisite for a successful Hermes reply |
integration_credentials | Slack/Email/WhatsApp tokens, encrypted at rest, at org level |
slack_channel_bindings | Channel opt-in binding: channel_id → Specialist |
slack_engaged_threads | Thread continuation tracking (sliding engaged_at TTL window) |
channel_context_messages | Silent ingest context storage (FTS index) |
expert_access | Expert ↔ (Org × Specialist) access authorization (ADR-007) |
VII. Recommended Tasks to Start First
Based on impact scope and dependency order, begin with:
- S-1 — Independent per-Specialist Slack App credentials (unblocks the complete multi-Specialist Slack flow)
- E-1 — Standardize channel source badges (small change, high visibility)
- E-3 — Define conversation statuses (blocks several downstream UI decisions)