Skip to main content

Persona Manager → Human.work Integration Spec

Status: approved 2026-05-13 · Builder source: prompts/persona-builder.md

This spec defines the design surface for integrating the Persona Manager (a standalone POC at hwork-persona-manager/) into the Human.work monorepo. It is the authoritative reference for the Builder agent during Phases 0–6 of TODO_PERSONA.md.

1. Scope

The Persona Manager adds two video-conversation workflows to Human.work:

WorkflowTriggerTavus roleAgent-service role
OnboardingFirst deployment of a Specialist to a client orgHosts a ~60min structured intake video call; its own LLM drives the conversationNot in-loop. Tavus webhooks call back to the Human.work API to record function-call outputs.
ReportingScheduled or ad-hoc check-inHosts the video call; in-conversation responses about work history are fetched liveReceives /chat calls from Tavus with role="reporting_meeting" (see §6.3).

2. Five new tables (additive only)

All new tables are created in a single new migration. No existing table is altered. Each table carries organization_id for tenancy and gets an RLS policy in the migration matching the patterns in migrations 9 (RLS), 12 (MemoryRLS), 13 (RlsMissingTables), 17 (OrgOnboardingRLS), 27 (OnboardingTablesRLS), 33 (RlsComplete). PM-0067 corrected the originally-cited list — migration 20 (OnboardingOtps) has no RLS content.

TablePurposeKey FKs
environment_profilesStructured operating-environment facts captured during onboarding for an OrgSpecialistAssignment. One row per (org, specialist) deployment.org_idorganizations, assignment_idorg_specialist_assignments, specialist_idspecialists
meetingsA scheduled or ad-hoc video touchpoint. kind in (onboarding, reporting). References Tavus persona/conversation IDs.org_id, assignment_id, created_byusers
meeting_decisionsDecisions logged via reporting function calls. Also mirrored into actions (see §4).meeting_id, org_id
meeting_prioritiesPriority changes logged via reporting function calls.meeting_id, org_id
tavus_function_definitionsPersona function-call library. Versioned JSON Schema. SuperAdmin-managed.none (global)

Full column-level schema is defined in the PM-0003 migration (Phase 0).

3. Entity mapping — POC ↔ hwork-app

The standalone POC has its own entity model. The integration maps as follows:

POC entity (hwork-persona-manager)hwork-app equivalent
client_orgOrganization (existing)
user (with tier)User + platformRole + OrgMembership.org_role (existing)
role_template + role_template_versionSpecialist (existing); versioning deferred to ADR-0003
deploymentOrgSpecialistAssignment (existing)
environment_profileenvironment_profiles (new)
meetingmeetings (new)
work_log_referenceNot ported. The brief assembler reads live from Conversation/Message/Action via service-layer queries (ADR-0007 of the POC is moot here).
function_call_definitiontavus_function_definitions (new)
audit_log (POC)Not ported. Use existing AuditService.log(...)audit_logs table.

4. The Action extension-point pattern

The existing Action entity (created in migration 11) is designed as an extension point. It carries actorType, actionType, payload, result, risk_level, status. The persona manager uses it for reporting decisions only:

await actionRepo.save({
orgId,
conversationId: null, // reporting decisions are not message-bound
messageId: null,
actorType: 'reporting_meeting',
actionType: 'decision_logged',
payload: { meetingId, decisionId, summary, manager_user_id },
result: { meetingDecisionId },
riskLevel: 'low',
status: 'completed',
});

This is the only sanctioned write to an existing table from persona manager code. All other mutations go to the new tables.

Reporting escalations are different — they are not Action writes; they are calls to ExpertQueueService.create(...), which itself creates an ExpertQueueItem and emits the existing notification events. The persona manager does not duplicate the queue surface.

5. Tavus webhook HMAC mirror

The Tavus webhook controller lives in a new module (api/src/tavus/tavus.controller.ts) and mirrors the HMAC verification pattern used in api/src/channels/channels.controller.ts (lines 47–62 for the boot-guard pattern, body verification inline at each endpoint).

Specifically:

  • A boot guard fails fast in deployed envs if TAVUS_WEBHOOK_SECRET is unset — mirrors channels.controller.ts:47-62 (the email boot-guard block).
  • Each webhook endpoint reads the raw body, computes createHmac('sha256', secret), and uses timingSafeEqual against the header. The cleanest existing reference for the per-request verification is the email handler at channels.controller.ts:445-465 (single-secret HMAC-SHA256). Slack (v0: prefix, lines 396-405), Twilio (HMAC-SHA1, line 1360+), and WeChat (line 1665) are variants of the same shape. Header name: accept both Tavus-Signature and X-Tavus-Signature; accept bare hex or sha256= prefix.
  • No code from channels.controller.ts is imported or modified. The pattern is reproduced cleanly so the channels module stays decoupled.

Idempotency: each webhook payload carries a Tavus idempotency key. The router dedupes in Redis (using the existing getRedisClient() from api/src/common/redis.util.ts) with a tavus:webhook:idem:<key> namespace and a 24-hour TTL.

6. Agent service touchpoints

6.1 Onboarding prompt — new file only

agent/prompts/onboarding_meeting.txt is a new template, parameterized via the existing {agent_name} and {agent_context_section} placeholders. The template is also rendered by persona-generator.service.ts (in NestJS) when creating the Tavus persona — NestJS reads the file from disk and substitutes parameters before calling tavusClient.createPersona(prompt).

6.2 Reporting prompt — new file only

Same pattern: agent/prompts/reporting_meeting.txt. The reporting persona's pre-call brief is injected as part of {agent_context_section} via a structured envelope (see PM-0040 brief assembler).

6.3 Loader behavior — no code change required

agent/prompts_loader.py:load_prompt(role) resolves prompt files by role. A chat call with role="onboarding_meeting" will naturally load prompts/onboarding_meeting.txt. No mode parameter or loader change is needed. Builder rule #9 was originally drafted under the assumption a mode param would be required; PM-0001 context read confirmed otherwise. The rationale is captured inline above; no separate ADR is needed (PM-0071 cleanup).

7. Frontend surface

New routes only:

  • /client/admin/specialists/[id]/onboarding/ — start, in-progress, post-call review
  • /client/admin/specialists/[id]/meetings/ — list, detail, in-session, post-session
  • /ops/personas/function-calls (SuperAdmin) — function-call CRUD
  • /ops/personas/replicas (SuperAdmin, Phase 5) — Tavus replica directory
  • /ops/personas/templates (SuperAdmin, Phase 5) — persona prompt templates

Additive functions are appended to frontend/src/lib/api.ts: startOnboarding, getEnvironmentProfile, updateEnvironmentProfile, approveEnvironmentProfile, plus meeting CRUD/start. No signature changes to existing functions.

WebSocket events extend the existing /notifications namespace: meeting_started, meeting_function_call, meeting_completed. Emitted via the existing NotificationsGateway — handlers obtain the gateway via DI and call server.to('org:<orgId>').emit(...).

8. SOUL.md non-mutation

The persona manager generates orgs/<slug>/SOUL.proposed.md only. The operator review/promote workflow for SOUL.md itself remains the existing manual process. The Environment Profile approval does not write to SOUL.md; it only updates a row in environment_profiles and writes the proposed file.

9. Out of scope (deferred)

  • Role-template versioning (POC role_template_version) — deferred to ADR-0003 when a versioning need actually arises.
  • POC's Celery + Redis async workers — replaced by BullMQ (already installed) only for the persona archival job (PM-0066).
  • POC's separate Postgres database — collapsed into the main hwork-app Postgres. Tables live under the same connection.

10. References

  • prompts/persona-builder.md — Builder operating prompt
  • docs/decisions/persona-manager/ADR-0001-integration-approach.md — chosen integration approach (forthcoming, PM-0002)
  • hwork-persona-manager/docs/architecture.md — POC architecture (reference only; not the integration's authority)
  • api/migrations/ 9, 12 (MemoryRLS), 13, 17, 27, 33 — RLS patterns to mirror
  • api/src/channels/channels.controller.ts:23-62 — HMAC pattern to mirror
  • api/src/notifications/notifications.gateway.ts — Socket.io pattern to extend
  • agent/prompts_loader.py — prompt assembly pipeline