Skip to main content

h.work — Client × AI Specialist Interaction

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.


1. Architecture Overview

Client (org_admin / org_member)
├── WebChat (/client/chat)
└── Slack Channel (DM or @mention in a channel)

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 — no cross-channel mixing
  • Every successful Hermes reply is delivered once; no confidence, risk, review, clarification, or approval state withholds it
  • Humanwork sends only the exact user message and native attachment blocks; Hermes owns history, retrieval, tools, and response behavior
  • Message dedup + idempotent writes to prevent double-processing

2. WebChat Module

2.1 Feature Description

After logging in, a Client navigates to /client/chat and can:

  • View all Specialists assigned to the org (left-side profile panel)
  • Start a new Thread with any Specialist
  • Maintain multiple independent Threads per Specialist
  • Send text, images, and file 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

FeatureStatus
Specialist selection + profile display✅ Done
New Thread / Thread list (left sidebar)✅ Done
Send message (text)✅ Done
Message attachments (images / files)✅ Done
Socket.io real-time reply delivery✅ Done
Thread rename / Resolve / Reopen✅ Done
Unread message badge✅ Done
Thread list sorted by latest message (descending)✅ Done
Thread status display (in_progress / awaiting_client / resolved)✅ Done
Channel source indicator (Slack / Email / WhatsApp icon)✅ Done

2.3 Message Flow

Client types message → POST /conversations/:id/messages
↓ Returns immediately (201)
Background async: runAgentPipeline()
→ Humanwork sends the exact message + real attachment blocks to the existing Hermes session
→ Hermes resumes SessionDB, retrieves/uses tools on demand, and returns the canonical reply
→ Every successful reply is stored and pushed once to the Client; a genuine failure remains a failure
→ Expert observation/correction is optional and occurs after delivery

2.4 Open Items

#IssuePriority
W-1When creating a new Thread in an org with multiple Specialists, the user must explicitly select which Specialist to addressHigh
W-2WebChat's own channel icon is missing in the Thread list (only external-channel icons like email/slack are shown)Medium
W-3Client-side message status feedback is missing (sending / delivered / failed)Medium
W-4Attachment preview: inline image preview works; PDF/file shows only a chip with no content previewLow

3. Slack Channel Module

3.1 Design Goal

Each AI Specialist maps to a dedicated Slack App. Once a Client org installs the App into their Slack Workspace, org members can communicate with that Specialist via:

  • DM: Direct message the Slack App
  • Channel @mention: @mention the App in any channel
  • Bound Channel (opt-in): A channel explicitly bound to a Specialist routes all messages to that Specialist — no @mention required

3.2 Slack App Activation Flow

SuperAdmin / AM generates a Slack App Manifest for a Specialist in the Ops dashboard

Create the App in the Slack API Console using the Manifest
(includes bot scopes / Events API / OAuth settings)

Configure the App's Client ID / Client Secret / Signing Secret in Humanwork

Specialist ↔ Slack App association stored in IntegrationCredential (encrypted)

Client org admin clicks "Add to Slack" → OAuth 2.0 authorization flow

oauth.v2.access → bot_token stored in IntegrationCredential (org-scoped)

Activation complete: org members can DM or @mention the Specialist via Slack

3.3 Message Trigger Strategy (Three Layers, per PRD)

Layer 1 — Hard Triggers (always respond)

  • DM sent directly to the Slack App
  • @mention of the bot in any channel
  • Follow-up messages in a Thread the bot has already participated in (Thread continuation)

Layer 2 — Contextual Scoring (intelligent decision, Phase 2)

composite_score = channel_weight × (keyword_match + question_intent)

score > relevance threshold → deliver the real message to Hermes
else → silent storage

Layer 3 — Implicit Relevance (semantic vector matching, Phase 3)

  • Embedding-based similarity matching
  • Requires cold-start labeled data

3.4 Message Processing Flow

Slack Events API → POST /channels/slack/events
↓ HMAC-SHA256 signature verification → return 200 immediately

BullMQ channels-inbound queue (async)

handleRuntimeEvent()
├── team_id → IntegrationCredential → resolve orgId
├── Dedup: event_ts / event_id already processed? → skip
├── Classify trigger: DM / @mention / Bound Channel / Thread continuation
│ └── No trigger → silent ingest into channel_context_messages

findOrCreateConversation() (Slack user → customer mapping)

conversationsService.sendMessage() [synchronous — waits for Agent]

Hermes resumes SessionDB and generates the canonical reply

BullMQ channels-outbound

slack.chat.postMessage(channel, text, thread_ts) → reply in original thread

3.5 Current Implementation Status

FeatureStatus
Slack App Manifest generation (SlackManifestSuggester)✅ Done
OAuth 2.0 install flow (Add to Slack)✅ Done
HMAC-SHA256 signature verification✅ Done
DM message ingestion + routing✅ Done
@mention message ingestion + routing✅ Done
Thread continuation tracking (slack_engaged_threads)✅ Done
Bound Channel (opt-in, no @mention required)✅ Done
Message dedup (Redis NX + event_ts)✅ Done
Silent ingest (channel_context_messages)✅ Done
Expert reply dispatched back to Slack thread✅ Done
Per-Specialist independent Slack App⚠️ Architecture supports it, but OAuth currently uses shared global SLACK_CLIENT_ID
Layer 2 Contextual Scoring🔲 Not implemented (Phase 2)
Layer 3 Semantic vector matching🔲 Not implemented (Phase 3)

3.6 Open Items

#IssuePriority
S-1Per-Specialist Slack App: current OAuth uses a global SLACK_CLIENT_ID/SECRET; need per-Specialist App credentials and independent install flowHigh
S-2Client-facing Slack connection management UI: show connected workspace, bound channels, disconnect / reconnect actionsHigh
S-3Bound Channel self-service UI (currently back-end only; Client Admin should be able to bind channels themselves)Medium
S-4Layer 2 Contextual Scoring engine implementationMedium
S-5Slack message image/file attachments forwarded to Expert DashboardMedium
S-6Expert replies support Slack mrkdwn rich-text formattingLow

4. Expert Dashboard Module

4.1 Feature Description

After logging in, an Expert navigates to /workspace/queue and can:

  • Handle explicit human requests and genuine failures from WebChat + Slack + Email + WhatsApp; ordinary successful deliveries create no work item
  • Read the canonical Specialist reply and real tool/failure evidence available for audit
  • Correct the canonical reply or author a genuine follow-up when needed
  • Browse the canonical conversation history from SessionDB plus recorded Expert follow-ups
  • Sort conversations across multiple dimensions (risk level / created time / SLA)

4.2 Current Implementation Status

FeatureStatus
Attention list (explicit human requests and genuine failures only)✅ Done
Canonical reply / failure evidence display✅ Done
Compatibility confidence/risk metadata (observability only)✅ Done
Expert correction and genuine follow-up✅ Done
Corrected/follow-up reply dispatched via original channel (webchat / slack / email)✅ Done
Full conversation history (complete message list)✅ Done
Channel source badge (email / slack etc.)✅ Done (email has badge; other channels incomplete)
SLA timer✅ Done
Keyboard shortcuts✅ Done
Socket.io real-time new message notification✅ Done
Unread message badge✅ Done
Queue sorting (risk / time / SLA)✅ Done
Message attachment display (images / files)✅ Done (WebChat attachments; Slack attachment forwarding pending)
Multi-Specialist filter view⚠️ Filtered by expert_access permissions; no UI toggle
Per-conversation unread count⚠️ Global unreadCount exists; per-conversation count needs verification
Conversation status management⚠️ Status values exist (pending / awaiting_client / resolved); transition rules need to be defined

4.3 Open Items

#IssuePriority
E-1Unified channel source badge: all channels (webchat / slack / whatsapp / email) display their source badge in both the Queue list and conversation detailHigh
E-2Slack attachment forwarding: images and files from Slack messages must be forwarded and viewable in the Expert DashboardHigh
E-3Conversation status definition: formally define pending / open / awaiting_client / resolved — meanings, transition conditions, and UI display rulesHigh
E-4Per-Specialist filter view: when an Expert has access to multiple Specialists, support filtering conversations by SpecialistMedium
E-5Per-conversation unread count: show exact unread message count per Thread in the conversation listMedium
E-6Rich-text message rendering: Slack mrkdwn, Markdown, link previewsMedium
E-7Internal Note: Expert-to-Expert internal messages (API exists; UI completeness to be verified)Low

5. Task Summary

Module 1 — Expert Dashboard

Task IDDescriptionPriorityDepends On
E-1Unified channel source badge in Queue list for all channelsP0
E-2Slack attachment forwarding: storage + display in Expert DashboardP0S-5
E-3Define and implement conversation status transition rules + UI labelsP0
E-4Per-Specialist filter viewP1
E-5Per-conversation precise unread message countP1
E-6Rich-text message rendering (Markdown + Slack mrkdwn)P2
E-7Internal Note UI completeness auditP2

Module 2 — Slack Channel

Task IDDescriptionPriorityDepends On
S-1Per-Specialist independent Slack App credentials (separate Client ID / Secret / Signing Secret per Specialist)P0
S-2Client Admin Slack connection management UI (connected workspaces / disconnect / reconnect)P0S-1
S-3Bound Channel self-service binding UI for Client AdminP1S-2
S-4Layer 2 Contextual Scoring engine (PRD Phase 2)P1
S-5Slack message image/file attachment forwarding to Expert DashboardP1
S-6Expert reply supports Slack mrkdwn formattingP2E-6

Module 3 — WebChat

Task IDDescriptionPriorityDepends On
W-1Support Specialist selection when creating a new Thread (multi-Specialist org scenario)P0
W-2Client-side message send status feedback (sending / delivered / failed)P1
W-3WebChat channel icon in Thread list (channel dot)P2
W-4PDF / document attachment preview (currently shows chip only, no content preview)P2

6. Key Data Models

EntityDescription
conversationsEach Thread — contains channel / status / agentName / orgId
messagesCanonical message records — role (user / ai / expert) and real attachments; compatibility review fields cannot gate delivery
expert_queue_itemsOptional Expert observation/correction work records; never a prerequisite for a successful Hermes reply
integration_credentialsSlack / Email / WhatsApp tokens — encrypted, org-scoped
slack_channel_bindingsChannel opt-in binding: channel_id → Specialist
slack_engaged_threadsThread continuation tracking (sliding-window engaged_at TTL)
channel_context_messagesSilent ingest context store (FTS index)
expert_accessExpert ↔ (Org × Specialist) access grant (ADR-007)

Based on impact and dependency order, suggested first tasks:

  1. S-1 — Per-Specialist Slack App credentials (unlocks the full multi-Specialist Slack story)
  2. E-1 — Unified channel source badge (low effort, high visibility)
  3. E-3 — Conversation status definition (blocking several downstream UI decisions)