Skip to main content
Synced from the repo — do not edit here

Canonical source: docs/claude/atlas-slack-plan.md. This page is generated by docs/scripts/sync-handbook.mjs. Edit the source file in the repo; changes appear here on the next build.

Atlas in Slack — "AI Employee" Plan (Viktor-style)

Planning doc, 2026-06-23. Status: PROPOSAL (not built). Companion to atlas-build-state.md. Goal: Atlas becomes a teammate clinicians talk to in Slack — answers, does real work (behind approvals), and proactively reports — reusing the existing brain, tools, and proactive engine.


✅ DECISIONS LOCKED (2026-06-23, George)

  1. PHI = hybrid, both at once. Default to no-PHI / link-out; build a per-clinic attestation toggle ("our Slack is HIPAA-compliant / BAA on file") that unlocks PHI in that workspace. Until a clinic attests, Atlas shows the no-PHI behavior (ops freely, link-out for patient-specifics).
  2. Surface = operational command center. The point is to run the clinic from Slack: track progress/issues, orders, bookings, add clients & staff, pull reports, and receive automated reports/updates. Lives in each clinic's own Slack, usable in a channel or direct DM.
  3. Install model (FINAL): TWO apps.
    • Interactive Atlas employee = NEW dedicated "Atlas" app, multi-workspace OAuth, installed per-clinic in each clinic's own Slack (per-clinic bot tokens). Reuses the existing helper code from functions_slack_bot.py.
    • System broadcast = REUSE the existing Support Bot app (Basis's single-workspace app + token). This means broadcast uses Slack Connect (clinic channels shared into Basis's workspace; one Basis token posts by channel ID) — a separate relationship from the employee install. Broadcast registry = those Connect channel IDs. Confirmed via screenshot: the standard Slack-Marketplace OAuth "Allow … to access Slack" flow (pick workspace → review permissions → Allow), Viktor-style. Pursue Slack Marketplace approval for the "approved by Slack" trust badge.

Install location (confirmed)

The Atlas employee installs into EACH CLINIC'S OWN Slack workspace (per-clinic OAuth, each clinic's own bot token). It is NOT in Basis's workspace. Basis's own Slack is involved ONLY for the internal System Broadcast trigger (below).

Identity & permissions in Slack (confirmed 2026-06-23)

  • Anyone in the workspace can talk to it (@mention or DM) — but responses/actions are scoped to the person. Atlas maps the Slack user → Basis clinician (by email via users.info), then enforces the same TOOL_PERMISSION_MAP/ClinicPermission model as the web copilot (Coach = coach-level, Admin = everything, Customer Service = no health data).
  • Unmapped Slack users (not Basis staff) → polite refusal, no clinic data. Optional per-clinic allowlist to restrict further.
  • Three permission layers: (1) Slack OAuth scopes [install screen], (2) per-user Basis role, (3) per-clinic settings — allowed channels, PHI attestation, and a recommended "who can approve writes" control (e.g. only admins approve invite-staff / order fulfillment) separate from who can chat.
  • Audit: Slack-initiated actions logged to transactions with source=slack and the resolved Basis uid.

Why this is a good fit

Most "run the clinic" actions are operational, not PHI (booking counts, orders/fulfillment, revenue, adding a client/staff, sequences, reports) — so the no-PHI default already covers ~80% of the vision with zero compliance risk. Patient clinical data is the part gated behind the attestation toggle.

Scope implication — TOOL GAP to fill

"Everything from Slack" needs ops tools beyond today's catalog. Existing & reusable: get_appointments, find/book/reschedule, get_services/products/memberships, get_staff, list_clients, sequences, benchmarks, prepare_create_task, prepare_client_message, schedule_task. Net-new tools to build (confirm-card gated for writes):

  • Orders / fulfillment status — read marketplace orders + their state (no read tool today).
  • Invite clientprepare_invite_client action (send intake invite).
  • Invite staffprepare_invite_staff action (role + home location).
  • Clinic-level reports — bookings/revenue/fulfillment summary (a get_clinic_report tool; patient-level report already exists). These are useful in the web copilot too, so build them as normal tools and Slack inherits them.

What already exists to reuse (we are NOT rebuilding the brain)

  • Brain: orchestrate_queryrun_claude_agent (tools, grounding, model routing). Slack is a new front door to it.
  • Actions w/ approval: confirm-card flow (_stage_copilot_actionexecute_copilot_action + _COPILOT_ACTION_WRITERS). In Slack these become Block Kit buttons.
  • Proactive output: observation engine (functions_observations.py) + heartbeat (functions_heartbeat.py, results in heartbeat_results) + scheduled tasks (schedule_task). Slack becomes an additional delivery channel for these.
  • Identity/permissions: functions_permissions.py (TOOL_PERMISSION_MAP / ClinicPermission). Must be enforced for Slack callers too.

So the Slack work is mostly: (a) ingestion + auth/identity, (b) PHI policy, (c) Block Kit rendering, (d) wiring proactive output to Slack. Not new intelligence.


⚠️ THE GATING DECISION: PHI in Slack (HIPAA)

Posting patient data to Slack sends PHI to a third party. Slack only supports PHI under a BAA + the right plan (Slack offers HIPAA compliance on certain tiers/Enterprise Grid). This dictates the whole design. Three postures:

  1. Notify-only / link-out (SAFEST, recommended default). Atlas in Slack posts non-PHI notifications and deep-links back into Basis ("⚠️ Something needs you for a client — open in Basis →"). It answers operational/clinic-config/growth questions freely (no PHI), but for anything patient-specific it links out. No BAA needed; PHI never leaves the platform.
  2. PHI-enabled per clinic (behind a gate). A clinic that has its own Slack BAA flips a setting ("our Slack is HIPAA-compliant") → Atlas may include patient data in that workspace. Requires explicit opt-in + a recorded attestation; we still avoid PHI in channel names/previews.
  3. Hybrid (recommended end-state). Default to #1; allow #2 per-clinic via an explicit, attested toggle. DMs (1:1 with the clinician) can carry more than public channels.

Recommendation: build #1 first (ship value with zero PHI risk), architect for #3 (per-clinic PHI toggle) from day one.


Architecture

Connection / install

  • One Basis Slack app (single app, multi-workspace via OAuth). Each clinic installs it → we store, per clinic, the bot token (encrypted), team/workspace id, default channel, and a Slack-user → Basis-clinician map.
  • Firestore: clinicsv2/{clinic}/integrations/slack = { teamId, botTokenEncrypted, defaultChannelId, phiEnabled (bool, attested), installedBy, userMap: {slackUserId: basisUid} }. Reverse lookup slackTeams/{teamId} → clinicId (top-level) so inbound events resolve the clinic fast.
  • Identity mapping: on first message from a Slack user, resolve via Slack users.info email → match a clinician email in the clinic; cache in userMap. Unmapped sender → polite refuse (no PHI).

Inbound (clinician → Atlas) — new functions

  • slack_events (on_request, signature-verified via SLACK_SIGNING_SECRET, HMAC + timestamp). Slack requires a 200 ack within 3s → ack immediately, then enqueue (slack_queue doc) and let a worker do the slow Atlas run. (Reuse the dispatcher→queue→worker pattern; don't run the LLM inline in the ack path.)
  • slack_worker (on slack_queue create, has ANTHROPIC_API_KEY) → resolves clinic+clinician+permissions → orchestrate_query with a Slack-thread session id → posts the reply via chat.postMessage to the thread.
  • Thread context: map Slack thread_ts → an Atlas session id so follow-ups in a thread keep context (store clinicsv2/{clinic}/integrations/slack/threads/{thread_ts}).
  • Triggers: app_mention (in channels), message.im (DMs). Optional slash command /atlas <query>.

Approvals (confirm cards in Slack) — slack_interactivity

  • When Atlas proposes an action, render a Block Kit message with Approve / Edit / Discard buttons carrying the draft id.
  • slack_interactivity (on_request, signature-verified) → on Approve, call the same execute_copilot_action writer path (permission-checked) → update the Slack message to "✓ Done". Edit → opens a Slack modal (or links to Basis for complex edits).

Outbound (Atlas → Slack, proactive)

  • Add a Slack delivery step to existing producers (gated by phiEnabled / posture):
    • Daily/weekly briefing → post the dashboard briefing digest to the clinic's channel (link-out for PHI in posture #1).
    • Tier-3 (push) observations → post to channel/DM the assignee.
    • Scheduled-task results (heartbeat_results, the reminder/report kinds) → DM the assignee in Slack in addition to the in-app inbox.
    • New urgent client message (from auto-categorize urgent) → ping the channel ("link to open").
  • Implementation: a small _post_to_slack(clinic_id, target, blocks) helper reused by the observation/heartbeat writers; respects posture + opt-in.

Secrets / infra

  • SLACK_SIGNING_SECRET, SLACK_CLIENT_ID, SLACK_CLIENT_SECRET (Secret Manager). Bot tokens encrypted at rest (reuse the Stripe-style encrypt helper pattern).
  • New functions are on_request (like clinical_agent_sse, which deployed fine) — but watch the 3s ack rule and the new-fn startup-probe gotcha; keep the ack handler tiny and push work to the worker.

⚠️ ALREADY EXISTS — reuse, don't rebuild (found 2026-06-23)

functions/src/functions_slack_bot.py is a working Support/Triage bot: registered Slack app (SLACK_CLIENT_ID/SECRET/SIGNING_SECRET secrets set), verify_slack_signature (HMAC), get_slack_bot_token (single token from system/slack_config), post_slack_message, file→GCS, get_slack_user_info, a live slack_events endpoint, and it already calls run_claude_agent. BUT it is single-workspace (Basis's own Slack), not multi-tenant. So Slack plumbing is DONE; the only net-new infra (if per-clinic install) is multi-workspace OAuth + per-clinic token + team_id→clinic mapping + tenant-aware get_slack_bot_token(team_id)/slack_events. Likely a NEW dedicated "Atlas" app (existing one is branded "Support Bot"); reuse the helper code.

Build phases (ops-first)

  • Phase 0 (REVISED) — distribution decision + extend the existing app: NOT from scratch. Decide per-clinic OAuth install (multi-workspace, their Slack) vs reuse single app + Slack Connect (our Slack). If per-clinic: register the dedicated Atlas app, enable OAuth distribution, scopes (app_mentions:read, chat:write, im:history, channels:history, users:read, users:read.email, commands); reuse verify_slack_signature/post_slack_message/etc.
  • Phase 1 — install + identity + settings: slack_oauth install → store clinicsv2/{clinic}/integrations/slack + slackTeams/{teamId}→clinic; Slack-user→clinician map (email). Basis Settings → Integrations → Slack: Connect, pick default channel, and the PHI attestation toggle (records who/when). Default = no-PHI.
  • Phase 2 — inbound ops Q&A: slack_events (3s ack) → slack_queueslack_worker runs orchestrate_query (clinic+clinician+permissions, thread session) → replies in thread. Ships with the existing READ ops tools (bookings, services, products, memberships, staff, clients, sequences). PHI link-out unless attested.
  • Phase 3 — ops tool buildout: add the gap tools (orders/fulfillment status, prepare_invite_client, prepare_invite_staff, get_clinic_report) — usable in web copilot too. Writes are confirm-card gated.
  • Phase 4 — approvals in Slack: Block Kit Approve/Edit/Discard → slack_interactivityexecute_copilot_action; message updates to "✓ Done".
  • Phase 5 — proactive / automated: _post_to_slack wired into daily briefing, tier-3 observations, scheduled report/reminder results, urgent-message flags → channel or assignee DM (PHI-gated). This delivers the "automated reports & updates."
  • Phase 6 — depth: slash command /atlas, richer modals, growth tools (ad/search performance) as they land, PHI-enabled flows once clinics attest.

System-wide Incident Broadcast (separate INTERNAL component)

Internal Basis-admin tool to blast a release/feature/outage notice — and later a "✅ Resolved:" — to all client Slack channels at once. Distinct from the per-clinic Atlas employee.

Distribution (DECIDED): reuse the existing Support Bot app + Slack Connect (option B). Clinic channels are shared into Basis's workspace; Basis's single token (system/slack_config) posts by channel ID via the existing post_slack_message. Registry = those Connect channel IDs (maintained, or auto-appended as clinics share a channel). Separate from the per-clinic employee install. (Option A — loop per-clinic employee-app tokens — was considered but we're reusing the Support Bot app instead.)

Carries over from the spec (all good, mirrors our patterns): 3s ack → async worker → final report via response_url (30-min window); per-channel isolated failures collected into a result list; mandatory two-step broadcast → confirm with recipient count; admin allowlist (Basis team Slack user IDs); full audit doc slack_broadcasts/{id} (kind incident|resolved, results[], sent/failed counts, parentId to link resolve→incident); enabled:false to pause a clinic.

Adds: trigger ALSO available from the platform admin UI (Post announcement / Resolve form with preview), not only the slash command. Reuse post_slack_message + signature-verified slash router.

Trigger location: Basis's internal workspace / platform admin (admins = Basis staff) — the only legitimate "Basis's own Slack" piece.

Open items (smaller, can decide as we build)

  1. Who can use it — any mapped clinician, or admins/managers only to start? (Lean: respect each clinician's existing permissions — a Coach gets coach-level answers, an Admin gets everything. No separate gate.)
  2. Channel vs DM behavior — in a shared channel, replies are threaded; proactive posts go to the configured channel; DMs are 1:1 and can carry more (incl. PHI once attested) than a public channel.
  3. Non-clinician/PII actions — inviting a client/staff puts a name/email in Slack (operational PII, not PHI). Allowed under no-PHI posture but worth a note in the attestation copy.
  4. Audit — log Slack-initiated actions to the transactions audit trail (same as web), tagged source=slack.

Reuse map (what we touch vs. build)

  • BUILD: slack_oauth, slack_events, slack_worker, slack_interactivity, _post_to_slack, Settings→Integrations→Slack UI, Firestore config + rules + slackTeams reverse index.
  • REUSE: orchestrate_query/run_claude_agent, execute_copilot_action + writers, observation/heartbeat producers, permissions map, grounding.

Open decisions (need George)

  1. PHI posture to start: notify-only/link-out (#1, recommended) vs per-clinic PHI toggle now (#3).
  2. First surface: inbound DM Q&A first, or proactive briefing-to-channel first? (Recommend inbound Q&A — it's the "wow," and proves identity/auth.)
  3. Scope of who can use it: any mapped clinician, or admins only to start?
  4. One shared Basis Slack app (we manage) — confirm (vs. per-clinic custom apps; shared is far better).