Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Select an option

  • Save SammonBabu/7f06177d1125eed13ab96f9ada516c85 to your computer and use it in GitHub Desktop.

Select an option

Save SammonBabu/7f06177d1125eed13ab96f9ada516c85 to your computer and use it in GitHub Desktop.
CRoohM Conversational Business Engine RFC v2.3

RFC-001: CroohM Conversational Business Engine

Status: Draft — Under Review Version: 2.3 Created: 2026-03-18 Last Updated: 2026-04-22 Authors: CroohM Product & Engineering Reviewers: TBD Classification: Internal — Confidential


Table of Contents

  1. Abstract
  2. Tenets
  3. Problem Statement
  4. Background & Motivation
  5. Goals & Success Metrics
  6. Non-Goals
  7. Terminology
  8. System Design
  9. Technology Stack
  10. AI Tool Landscape Analysis
  11. Data Model
  12. API Design
  13. Security & Threat Model
  14. Capacity Planning
  15. Observability, SLIs, SLOs & Alerting
  16. Implementation Plan
  17. Rollout Strategy
  18. Alternatives Considered
  19. Risks & Mitigations
  20. Open Questions
  21. Decision Log
  22. References

1. Abstract

CroohM is a mobile-first CRM and multi-channel messaging platform serving SMB customers primarily on WhatsApp and Gmail. This RFC proposes evolving CroohM into a Conversational Business Engine: a workspace-scoped AI system where business operators issue natural language instructions and CroohM autonomously executes the work — reading CRM state, drafting messages, sending outreach, updating leads, and running scheduled automations — with guardrails, approvals, and full auditability.

This is not "adding a chatbot." This is a new execution layer that sits between the user's intent and every business operation CroohM currently performs manually. The architecture described here is designed to run on Google Cloud Platform (GCP), use OpenRouter as the primary model routing layer, start with MiniMax as the main agent model, experiment with free and open models for low-risk workloads, and be production-grade from Phase 1. The system is designed to improve over time through explicit feedback, eval replay, routing adjustments, prompt versioning, and skill refinement.


2. Tenets

Tenets are ordered. When trade-offs arise, the higher-ranked tenet wins.

  1. Tenant isolation is inviolable. No AI action, retrieval, or context leak may cross workspace or tenant boundaries under any circumstance. Correctness over performance. Isolation over convenience.

  2. Host logic, not model logic, controls routing. The model never selects the tenant, workspace, channel, sender identity, or approval gate. These are infrastructure decisions, not inference decisions.

  3. Approvals before irreversible actions. Any action that sends a message, modifies a customer record, or calls an external API must be approvable or blockable before execution. Drafts are free; sends are guarded.

  4. Observable by default. Every agent run produces a complete, structured trace: inputs, tool calls, decisions, outputs, latency, cost. No black-box execution.

  5. Cost is a product constraint, not a footnote. Token usage, embedding operations, and infrastructure costs must be modeled per feature before shipping. Unconstrained AI compute is a business risk.

  6. Mobile-first UX, not mobile-optional. Approval flows, run status, agent conversations, and workflow monitoring must work on a 375px screen.


3. Problem Statement

3.1 The Manual Loop Problem

Today, a CroohM user who wants to follow up with stale leads must:

  1. Open CRM → filter by last contact date → scan 40 rows manually
  2. Open inbox → check each lead's last WhatsApp message
  3. Decide who needs follow-up → open each record
  4. Draft a message → copy/paste from a template → personalize manually
  5. Send via WhatsApp or Gmail → switch apps
  6. Update lead status in CRM → set a reminder
  7. Repeat for the next lead

This loop takes 3–8 minutes per lead. A rep with 50 stale leads spends 2.5–6.5 hours on manual mechanical work that generates zero new insight.

3.2 What This Costs

  • Leads die in the queue. Response time degrades. Conversion drops.
  • CRM state decays. Records go stale because updating them costs time that competes with selling.
  • Context is lost. Each new conversation starts without historical context because no one has time to read the full thread.
  • Operators can't see the problem. Pipeline risk is invisible until deals die.
  • Team leads have no signal. No digest, no summary, no alert — just noise.

3.3 The Market Window

Gartner estimates that by end of 2026, 75% of B2B customer interactions will be handled by AI agents (up from 30% in 2023). Salesforce (Agentforce), Zoho (Zia Agent Studio with 700+ actions), Freshworks (Freddy AI), and HubSpot (Breeze) have all shipped agent-native CRM features in the past 18 months. CroohM's differentiation is WhatsApp-native + mobile-first + SMB-focused — but only if we ship before this window closes.


4. Background & Motivation

4.1 Competitive Landscape: What CRoohM Replaces

Each of the following products is a standalone company with its own pricing, dashboard, and login. None of them talk to each other. CRoohM does all of it — coordinated — from one app on a phone.

Product What It Does CRoohM Equivalent Current Pricing
Vibe Prospecting Find leads across 150M+ businesses and 800M+ profiles using 4,000 signals (funding events, hiring, tech stack, intent). Draft personalised outreach. Built on Explorium data. Has a Claude MCP connector. Dispatch — one feature inside CRoohM Free tier; paid plans per credits (Explorium: $200/5K credits)
ManyChat Automate conversations on WhatsApp, Instagram, Messenger, SMS. Intent recognition, lead capture, flow builder. AI add-on is an extra $29/month. Conversation Automation — one capability inside CRoohM Free (1K contacts); Pro from $15–435/month by contact count; WhatsApp adds $0.02–0.08/conversation
Intercom Fin AI support agent resolving 67% of customer queries autonomously across 40M+ conversations. Knowledge base RAG, multi-language, Procedures for complex flows. Now spun off as fin.ai. Support Agent — one agent inside CRoohM $0.99/successful resolution; 50-resolution/month minimum; Intercom platform seat costs separate
item.app "The first agentic CRM." Train AI agents like new hires by writing process documents (Notion-style). Agents run outbound sales, inbound management, pipeline warming autonomously. YC-backed. Playbook Engine — one engine inside CRoohM Not publicly listed; enterprise pricing
OpenClaw (formerly Moltbot/ClawdBot, renamed Jan 2026) Open-source personal AI assistant. Connects to WhatsApp, Telegram, Slack, Discord, iMessage, Signal, Teams, Matrix, Google Chat simultaneously. Persistent memory, proactive outreach, shell/browser/calendar control. The spirit of CRoohM's Business Brain — but single-user, not multi-tenant SaaS Free, self-hosted

The insight: Vibe Prospecting is an entire funded company. For CRoohM, it is one feature — Dispatch. That is the scope of what we are building.

4.2 Market Context: The Agentic CRM Window (2026)

The CRM AI market moved from "copilot suggestions" to "agent-executed workflows" as the dominant pattern in 2026:

  • Salesforce Agentforce: $540M ARR by Q3 FY2026, 330% YoY growth. Now bundled free into SMB Starter and Pro plans, eliminating the AI paywall for small teams.
  • HubSpot Breeze AI: Included at no extra cost across core plans. 279,000+ active customers. Leading SMB acquisition with integrated marketing-sales-service agents.
  • Zoho Zia Agent Studio: 700+ configurable actions, agentic workflows across CRM, support, and email.
  • Freshworks Freddy AI: Autonomous agents across sales, support, and ITSM.

The window CRoohM is targeting: these platforms are enterprise-first and desktop-first. Their AI agents live inside complex dashboards. None of them are designed to be operated from a phone. None of them are WhatsApp-native. None of them serve a solo founder or a 3-person team that lives in WhatsApp. That gap is CRoohM's market.

4.3 What We Learned From Reference Products

Intercom Fin (AI support agent):

  • Separates knowledge loading from channel deployment from live conversation ownership — three independent state machines
  • Fact-checked 2026: 67% resolution rate, $0.99/resolution, 40M+ conversations handled. Guarantees 50% automation rate (credits back if Fin resolves fewer than 50%)
  • Uses per-workspace knowledge indexes for strict RAG isolation
  • Heavy Redis for session context caching — keeps LLM calls fast
  • Per-workspace rate limiting prevents noisy-neighbor degradation
  • The key insight: "AI enabled" ≠ "AI deployed" ≠ "AI trusted on that channel"

item.app (agentic CRM, YC-backed):

  • Core mechanism: write a Notion-style process document → item parses it → creates an autonomous agent that executes each step
  • Agents trained in: Outbound Sales, Inbound Management, Growing Existing Accounts, Pipeline Warming
  • The AI Assistant handles ad-hoc queries: "send follow-ups, research leads, or add deals with a simple prompt — no complex UI, no dropdowns, just ask"
  • The key insight: CRoohM's Playbook Engine + AI Assistant must deliver this same "write it like a doc, runs like a workflow" experience

Vibe Prospecting / Explorium:

  • Data layer: 146M+ business entities, 767M+ employee profiles, 50+ sources, 4,000+ signals
  • Real-time triggers: IPOs, M&As, funding events, tech stack changes, hiring signals (EventAPI)
  • MCP server available — Explorium already exposes their data to LLM agents via MCP
  • Pricing: $200 for 5K credits; credits expire after 12 months
  • The key insight: CRoohM's Dispatch does not need to build the data layer. It integrates with Explorium/Vibe Prospecting's MCP server. The value we add is the context (lead is already in the inbox, conversation history exists) and the execution (draft, approve, send — all inside CRoohM)

OpenClaw (formerly Moltbot/ClawdBot — renamed January 27, 2026):

  • Open-source, self-hosted personal AI assistant across 10+ messaging platforms simultaneously
  • Proactive: sends you messages first (reminders, alerts, morning briefings) — not just reactive
  • Persistent memory: remembers everything across sessions, never repeats context
  • Actions: shell commands, browser control, calendar, email — from any chat app
  • Key gap vs CRoohM: single-user, no multi-tenant model, no workspace/team concept, no WhatsApp Business API (personal WhatsApp only), no CRM data layer
  • The key insight: this is the best reference for CRoohM's Brain UX and memory model. Adapt the proactive surface pattern ("3 leads stuck — want me to follow up?") and the persistent memory design

ManyChat (conversation automation):

  • Fact-checked 2026: Pro plan $15–435/month by contact count. WhatsApp is an add-on ($0.02–0.08/conversation, first 1K/month free). AI add-on is an extra $29/month.
  • Automation spans Instagram, WhatsApp, Messenger, SMS, email
  • Key limitation: does not connect to a CRM — you must push data to an external tool via integration
  • The key insight: CRoohM's Conversation Automation beats ManyChat because the data is already in the same system. No Zapier. No Notion database. The conversation, the lead, the history — all one record.

Perplexity Computer (launched Feb 2026):

  • General-purpose digital worker orchestrating 19 AI models in a sandboxed compute environment
  • Runs a routed multi-model stack and treats model selection as an execution policy
  • Priced at $200/month for the Max tier — validates that users pay premium for genuine autonomous execution, not just generation
  • The key insight: users pay for outcomes (tasks completed) not for conversations had

OpenRouter + routed provider ecosystems (2026):

  • Treats providers and models as a routable layer behind one API surface
  • Enables price/performance routing, fallback behavior, and access to both frontier and open models
  • The key insight: model policy should be dynamic and evidence-driven, not frozen into the first shipped provider choice

OpenAI Agents SDK (production-stable 2026):

  • Lightweight Python + TypeScript framework for multi-agent workflows
  • Core primitives: Agent (instructions + tools), Runner (execution loop), Handoff (transfer ownership between agents), Guardrail (input/output validation), Session (persistent memory within an agent loop)
  • The key insight: the abstraction that matters is not the model, it's the agent loop with sessions and handoffs

Google Agent Development Kit (ADK, 2026):

  • Code-first framework for building agents on GCP (Python + TypeScript SDKs)
  • Single command deployment to Cloud Run: adk deploy cloud_run
  • Workflow agents for Sequential, Parallel, Loop patterns
  • MCP support as client — ADK agents can consume MCP servers
  • The key insight: GCP's ADK is the path of least resistance for GCP-native AI services

LangGraph (v1.0 stable, March 2026):

  • Graph-based agent orchestration with stateful, durable execution
  • Used in production by Klarna, Replit, and others
  • Six built-in features: parallelization, streaming, checkpointing, human-in-the-loop, tracing, task queue
  • If an agent crashes mid-execution, it resumes from the last checkpoint
  • The key insight: durable checkpointing is not optional for long-running business workflows

item.app + Intercom Fin (hands-on product testing, March 18, 2026):

  • Item demonstrates the strongest "operator AI" shape: ask for business work, inspect CRM state, invoke actions, create skills, and send real messages through connected tools
  • Intercom Fin demonstrates the strongest "channel AI" shape: knowledge ingestion, test harness, staged deploy, channel routing, and live ownership are separate state machines
  • The key insight: CRoohM must unify both. Business operators need item-style actionability; customer channels need Fin-style deployment discipline

4.4 Why CRoohM Is Well-Positioned

CroohM already has the substrate that takes competitors years to build:

Asset Current State What It Enables
Multi-tenant workspace model ✅ Exists Natural isolation boundary for AI
WhatsApp transport + webhooks ✅ Exists Real channel execution without integration work
Lead + conversation data model ✅ Exists Rich context for AI grounding
Interaction logging ✅ Exists Foundation for agent run traces
Team-based workflow expectations ✅ Exists Approval and handoff UX model
Mobile-first product posture ✅ Exists Differentiated AI UX on mobile
GCP infrastructure ✅ Exists Native integration with ADK, Cloud Run, Pub/Sub

What is missing is only the AI execution layer on top of this foundation.


5. Goals & Success Metrics

5.1 Goals

  • G1: Build a workspace-scoped conversational agent that executes real business operations in natural language
  • G2: Support three agent modes: channel agent (customer-facing), operator agent (internal user), workflow agent (event/scheduled)
  • G3: Implement a tool execution framework with approval gates for irreversible actions
  • G4: Build a knowledge and retrieval layer with strict workspace-scoped RAG
  • G5: Instrument every agent run with full traces, token counts, and cost attribution
  • G6: Support multi-channel deployment: WhatsApp, Gmail, web chat
  • G7: Make the architecture BYOK-compatible (Bring Your Own Key) for enterprise

5.2 Success Metrics

Leading indicators (measured during build):

Metric Target Measurement
Agent task completion rate ≥ 85% on internal golden test set Automated eval suite
Tool call accuracy ≥ 90% correct tool + parameters Eval vs labeled dataset
Retrieval faithfulness ≥ 80% (RAGAS faithfulness score) RAGAS eval pipeline
P95 operator agent response latency < 4 seconds Langfuse traces
P95 channel agent response latency < 2 seconds Langfuse traces

Lagging indicators (measured post-launch):

Metric Target at 90 days Measurement
Manual follow-up time per rep -50% vs baseline Time-tracking survey
Lead response rate +20% vs control group CRM conversion funnel
CRM record update rate +35% vs baseline Firestore write events
Workspace AI feature activation rate ≥ 40% of active workspaces Feature flag analytics
AI credit usage per workspace/month Avg $8–15 platform cost Token × model price

6. Non-Goals

  • Not building a general-purpose autonomous shell accessible to end users
  • Not exposing arbitrary code execution to business users
  • Not supporting all model providers at parity in V1 (OpenRouter-first with controlled routing and provider abstraction)
  • Not building a public plugin marketplace in V1
  • Not fine-tuning any model in V1
  • Not replacing human judgment on high-stakes decisions — AI assists and drafts, humans approve and send
  • Not building a no-code workflow builder in V1 — product-defined templates only

7. Terminology

Term Definition
Workspace A CroohM tenant's operating unit. All agents, channels, and data are workspace-scoped.
Agent An LLM-powered executor with a system prompt, tool access, and a run lifecycle
Tool A typed, schema-defined function the agent can call (read CRM, send WhatsApp, draft email, etc.)
Skill A reusable business capability composed of a system prompt policy + allowed tools + output contract
Agent Run A single execution instance of an agent: input → planning → tool calls → output
Run Trace Structured log of every step in an agent run: inputs, tool calls, LLM responses, latencies, costs
Session Lane A serialized execution context per entity (conversation, lead, workspace operator session) that prevents concurrent conflicting mutations
Approval Gate A pause point before an irreversible action where a human can approve or block execution
Handoff Transfer of conversation ownership from agent to human, or between agents
Knowledge Source A document, website, snippet, or CRM object indexed for retrieval
RAG Retrieval-Augmented Generation — retrieving relevant context chunks before LLM generation
BYOK Bring Your Own Key — customer provides their own LLM provider API keys
MCP Model Context Protocol — an open standard for connecting AI models to external tools and data
SLI Service Level Indicator — the measured metric
SLO Service Level Objective — the target for the SLI

8. System Design

8.1 Architecture Overview

graph TB
    subgraph Surfaces["CroohM Surfaces"]
        MA[Mobile App<br/>React Native / Expo]
        WA[Web App]
        WP[WhatsApp<br/>Meta Cloud API]
        GM[Gmail]
        WC[Web Chat]
    end

    subgraph Gateway["API Gateway — Go / Cloud Run"]
        GW[croohm-api<br/>Auth · JWT · IAP · Rate Limit<br/>Inject tenantId + workspaceId]
    end

    subgraph Orchestrator["Orchestration Layer — TypeScript / Cloud Run"]
        direction TB
        RR[Request Router<br/>Deserializes intent]
        CC[Context Engine<br/>CRM · Memory · Knowledge · Config]
        PE[Policy & Approval Engine<br/>Guardrails · Tool allowlist]
        AR[Agent Runtime<br/>LangGraph.js + OpenRouter tool-use loop]
        SL[Session Lane Manager<br/>Redis distributed locks]
    end

    subgraph Tools["Tool Runtime — Typed dispatch"]
        CT[CRM Tools<br/>read_leads · update_lead]
        MT[Message Tools<br/>draft_whatsapp · send_whatsapp<br/>draft_gmail · send_gmail]
        WT[Workflow Tools<br/>trigger_workflow · schedule_callback]
    end

    subgraph Workers["Realtime Worker Layer — Cloud Run + Pub/Sub"]
        EW[Event Workflow Worker]
        AW[Approval Resume Worker]
        SD[Send Dispatcher<br/>idempotent external actions]
        CS[Context Summarizer]
    end

    subgraph Batch["Batch Worker Layer — Cloud Run Jobs"]
        EP[Embedding Pipeline]
        ER[Eval Runner]
        AA[Audit Archiver]
        RS[Retention Sweeper]
    end

    subgraph Storage["Storage Layer"]
        FS[(Firestore<br/>Leads · Convs · Agents<br/>Runs · Approvals)]
        VS[(Vector Store<br/>Workspace namespaces<br/>Knowledge Index)]
        RD[(Redis<br/>Session locks<br/>Rate limit counters)]
        GCS[(Cloud Storage<br/>Docs · Trace archives)]
    end

    subgraph LLM["LLM Provider — via OpenRouter"]
        OR[OpenRouter<br/>MiniMax primary · OSS fallback<br/>Route policy versioned]
    end

    Surfaces --> Gateway
    Gateway --> Orchestrator
    Orchestrator --> Tools
    Orchestrator --> Workers
    Workers --> Batch
    Orchestrator <--> Storage
    Tools <--> Storage
    Workers <--> Storage
    Batch <--> Storage
    AR <-->|tool-use loop| OR
Loading

8.2 Component Deep Dives

8.2.1 API Gateway (croohm-api)

  • Language: Go
  • Platform: Cloud Run (min instances: 2, max: 100)
  • Responsibilities:
    • Authenticate requests (Firebase Auth / Identity Platform JWT validation)
    • Enforce Google IAP for internal service-to-service traffic
    • Extract and inject tenantId + workspaceId into every downstream request header — nothing downstream trusts the request body for these values
    • Per-workspace rate limiting: token bucket in Redis, 1000 req/min default, configurable per plan
    • Route to orchestration, connector, or standard CRUD handlers
    • Expose approval APIs and run inspection APIs to the mobile/web clients

8.2.2 Orchestration Layer (croohm-orchestrator)

  • Language: TypeScript
  • Platform: Cloud Run (min instances: 1, max: 50)
  • Framework: LangGraph.js for stateful agent loops with checkpointing
  • Responsibilities:
    • Assemble the composed run context (8 layers — see Section 8.4)
    • Classify request: channel agent, operator agent, or workflow agent
    • Execute the tool-use loop via OpenRouter with provider-aware routing and streaming
    • Manage session lanes — acquire a distributed lock per (workspaceId, sessionBoundaryId) before any mutation-capable run
    • Enforce approval gates — pause run, emit ApprovalRequest to Firestore, wait for approval webhook before continuing
    • Emit structured run trace to Langfuse on every step
    • Handle handoffs: agent-to-human (update conversation handoffState), agent-to-agent (spawn sub-run)

Agent Tool-Use Loop (OpenRouter):

User Request
    │
    ▼
[System Prompt Assembly]
 Platform policy + Workspace config + User role + Object context
 + Conversation memory + Knowledge retrieval results + Run scratchpad
    │
    ▼
[Model Inference — routed via OpenRouter]
 Default: MiniMax for orchestration
 Fallback: OSS/free or alternate providers based on route policy
 Tool use mode: tools = workspace_allowed_tools filtered by risk policy
    │
    ├──► [Tool Call] → Tool Runtime → Result → back to model
    ├──► [Tool Call] → Approval Gate → wait → resume or abort
    └──► [Final Response] → Channel Formatter → User / Channel

Prompt Caching Strategy:

  • Static prefix (platform policy + workspace config + user role) → cached with cache_control: ephemeral
  • Dynamic suffix (object context + retrieval results + conversation) → not cached
  • Expected cache hit rate: 60–70% of tokens on repeat operator sessions → ~50% cost reduction on those sessions

Routing Policy Strategy:

  • Route selection is host-controlled and versioned
  • Initial policy:
    • MiniMax via OpenRouter for planner/executor paths
    • low-cost OSS/free models for classification, extraction, and summarization after eval approval
    • premium fallback route reserved for failures, high-stakes runs, or regression recovery
  • Every run persists: provider, model, routePolicyVersion, credentialProfileId, fallbackUsed

8.2.3 Context Engine

Five retrieval operations assembled before every run:

  1. CRM Object Context — fetch lead/conversation/task from Firestore by ID
  2. Conversation Memory — fetch ContextSummary for the session (short summary, working summary, extracted facts, open loops)
  3. Knowledge Retrieval — vector search against workspace's knowledge index with hard filters on workspaceId + visibility
  4. Workspace Config — agent persona, brand voice, operating rules, approval policies
  5. User Role + Permissions — what tools this user is allowed to invoke

All five are assembled in parallel (Promise.all). Total context assembly target: < 300ms P95.

8.2.4 Tool Runtime

Each tool is a typed, schema-validated function registered in the ToolRegistry. Every tool definition includes:

interface ToolDefinition {
  name: string;
  description: string;            // shown to the model
  inputSchema: JSONSchema;
  outputSchema: JSONSchema;
  riskLevel: ToolRisk;            // "read" | "draft" | "write" | "external_send" | "admin"
  requiredPermissions: string[];
  requiredConnector?: string;     // "whatsapp" | "gmail" | null
  approvalBehavior: ApprovalMode;
  rateLimitPerWorkspace?: number; // calls/min
  observabilityTags: string[];
}

Tool execution is always:

  1. Permission check against user role
  2. Approval gate check against workspace policy
  3. Acquire session lane lock if mutation
  4. Execute
  5. Emit tool call span to run trace
  6. Release lock

8.2.5 Connector Layer (croohm-connectors)

  • Language: TypeScript
  • Platform: Cloud Run
  • Responsibilities:
    • Gmail: OAuth callback handling, Gmail watch setup (Pub/Sub push), thread-to-conversation mapping, draft and send via Gmail API
    • WhatsApp: Meta Cloud API webhook ingestion, template sync, 24-hour window enforcement, approved template fallback
    • Web chat: WebSocket or SSE channel for real-time chat widget

8.2.6 Realtime Worker Layer (croohm-workers)

  • Language: TypeScript + Python
  • Platform: Cloud Run services triggered by Pub/Sub and Cloud Tasks
  • Responsibilities:
    • Event Workflow Worker: Execute low-latency event-triggered automations (e.g. inbound WhatsApp → qualify → draft → approval)
    • Approval Resume Worker: Resume paused runs after approval or rejection
    • Send Dispatcher: Commit prepared external actions with idempotency keys and webhook correlation
    • Context Summarizer: Sliding-window conversation summarization to keep context compact

8.2.7 Batch Worker Layer (croohm-batch)

  • Language: Python
  • Platform: Cloud Run Jobs (triggered by Cloud Scheduler and explicit admin actions)
  • Responsibilities:
    • Embedding Pipeline: Chunk knowledge sources, generate embeddings, write to vector index
    • Eval Runner: Nightly runs of the agent eval suite, write results to Firestore eval_results
    • Audit Archiver: Flush completed run traces from Firestore to Cloud Storage as Parquet for long-term storage and cost control
    • Retention Sweeper: Execute TTL deletion, workspace erasure, and vector cleanup jobs

8.3 Workspace and Tenant Model

graph TD
    T[Tenant] --> W1[Workspace A<br/>Sales Team]
    T --> W2[Workspace B<br/>Support Team]
    T --> W3[Workspace N<br/>...]

    W1 --> WA1[WorkspaceAgent<br/>channel / operator / workflow]
    W1 --> CD1[ChannelDeployments<br/>WhatsApp number · Gmail · Web chat]
    W1 --> WD1[WorkflowDefinitions<br/>triggers + steps]
    W1 --> KS1[KnowledgeSources<br/>docs · website · snippets]
    W1 --> CP1[CredentialProfiles<br/>platform-managed or BYOK]
    W1 --> U1[Users]

    WA1 --> SK1[SkillDefinitions<br/>qualify_lead · follow_up_pipeline]
    WA1 --> TA1[ToolAllowlist<br/>per-agent tool permissions]

    U1 --> UR1[Owner<br/>all permissions + approval authority]
    U1 --> UR2[Sales Rep<br/>assigned queues + draft/send]
    U1 --> UR3[CSM<br/>read + draft only]

    style T fill:#f5f5f5,stroke:#333
    style W1 fill:#dbeafe,stroke:#2563eb
    style W2 fill:#dbeafe,stroke:#2563eb
    style W3 fill:#dbeafe,stroke:#2563eb
Loading

Key decisions:

  • Channels are workspace assets, not user assets
  • Agent behavior (persona, tools, approval policy) is workspace-configured
  • User overlays add: role-based permissions, personal defaults, optional personal memory
  • A workspace cannot see or act on another workspace's data — enforced at the API gateway (tenantId/workspaceId injection) and at every Firestore query and vector retrieval

8.4 Context Layers (Run Composition)

Every agent run composes context from exactly these 8 ordered layers:

Layer 1: Platform Policy         ← hardcoded, never tenant-overridable
Layer 2: Tenant Policy           ← from Firestore TenantConfig
Layer 3: Workspace Config        ← WorkspaceAgent + CredentialProfile + brand voice
Layer 4: User Role + Permissions ← from Firestore UserRecord
Layer 5: Object Context          ← Lead | Conversation | Task | Deal fetched live
Layer 6: Conversation Memory     ← ContextSummary (summary + facts + open loops)
Layer 7: Knowledge Retrieval     ← top-K chunks from vector store, workspace-scoped
Layer 8: Run Scratchpad          ← tool call results accumulated during this run

Layer 1 is always prepended and cannot be overridden by any workspace. This includes the tenant/workspace isolation instructions and approval enforcement rules.

8.5 Session Lane Design

Concurrent conflicting mutations are one of the highest-risk failure modes in agent systems (duplicate sends, conflicting lead updates, double booking). CroohM serializes runs per session lane using distributed locks in Redis.

Session lane boundaries:

Session Type Lane Key
Customer-facing conversation conv:{conversationId}
Lead-scoped operator run lead:{workspaceId}:{leadId}
Workflow background run wf:{workflowRunId}:{targetId}
Workspace operator session ops:{workspaceId}:{userId}:{sessionId}
  • Lock TTL: 120 seconds (auto-released on run completion or timeout)
  • Lock acquisition timeout: 5 seconds (fast fail — return "agent busy on this entity" error)
  • Lock owner: agent run ID (enables detecting stale locks from crashed runs)

Important rule: session lane locks protect active mutation windows, not multi-hour approvals. A run must release the active lock before waiting on human approval, then reacquire it for the final commit step.

8.6 Write Path Semantics: Prepare → Approve → Commit

All side-effecting actions use a three-stage protocol:

  1. Prepare
    • The agent computes intent and produces a normalized action payload
    • The tool runtime validates permissions, policy, and connector readiness
    • A PreparedAction record is written with:
      • preparedActionId
      • runId
      • sessionLaneKey
      • toolName
      • targetObjectId
      • idempotencyKey
      • providerPayload
      • status = "prepared"
  2. Approve / Reject
    • If policy requires approval, an ApprovalRequest references the PreparedAction
    • The active session lock is released while waiting
    • Approval callback carries a one-time approval token and the prepared action ID
  3. Commit
    • The resume worker reacquires the session lane lock
    • Re-validates entity state, connector state, and approval freshness
    • Executes the external send or mutation using the original idempotencyKey
    • Marks PreparedAction.status = "committed" or "aborted"
sequenceDiagram
    participant Agent
    participant ToolRuntime
    participant Firestore
    participant User
    participant ResumeWorker
    participant Connector

    Agent->>ToolRuntime: prepare send_whatsapp / send_gmail
    ToolRuntime->>Firestore: write PreparedAction(idempotencyKey, status=prepared)
    ToolRuntime->>Firestore: write ApprovalRequest(preparedActionId)
    ToolRuntime-->>User: approval needed
    User->>Firestore: approve or reject
    ResumeWorker->>Firestore: load PreparedAction + approval
    ResumeWorker->>ResumeWorker: reacquire session lane lock
    ResumeWorker->>Connector: commit with idempotencyKey
    Connector-->>ResumeWorker: provider message id / result
    ResumeWorker->>Firestore: mark committed, attach provider ids
Loading

Why this matters:

  • duplicate approval taps must not create duplicate external sends
  • expired approvals must not revive stale drafts
  • resumed runs must be replay-safe after crashes

8.7 Idempotency and Webhook Deduplication

Every external action must persist:

  • idempotencyKey
  • sendRequestId
  • providerMessageId if returned
  • providerThreadId if relevant
  • deliveryStateVersion

Rules:

  • Gmail and WhatsApp send tools always execute through PreparedAction
  • repeated approval callbacks for the same prepared action are ignored after first commit
  • duplicate provider webhooks are deduplicated by (provider, providerMessageId, status, timestampBucket)
  • status transitions are monotonic:
    • prepared -> committed -> accepted -> delivered/read/failed
  • any non-monotonic or duplicate transition is stored as a no-op audit event, not applied to user-visible state

8.8 Realtime vs Batch Execution

CroohM explicitly separates low-latency event handling from heavy background work.

Execution Class Platform Examples
Realtime Cloud Run services + Pub/Sub + Cloud Tasks inbound message handling, approval resume, send commit, task creation
Batch Cloud Run Jobs + Scheduler nightly evals, embeddings backfills, archive export, retention sweeps

This split prevents implementers from accidentally routing interactive channel work through batch infrastructure.

8.9 Sub-Agent Orchestration

sequenceDiagram
    participant U as User (Mobile)
    participant P as Planner Agent<br/>(OpenRouter: MiniMax)
    participant O as Orchestrator
    participant E1 as Executor Sub-agent<br/>Lead L1
    participant E2 as Executor Sub-agent<br/>Lead L2
    participant EN as Executor Sub-agent<br/>Lead LN
    participant AG as Approval Gate
    participant WA as WhatsApp Connector

    U->>O: "Follow up all hot leads with no reply in 48h"
    O->>P: build execution plan
    P-->>O: [{leadId: L1}, {leadId: L2}, ..., {leadId: LN}]

    par Fan-out to N executors in parallel
        O->>E1: read context + draft message for L1
        O->>E2: read context + draft message for L2
        O->>EN: read context + draft message for LN
    end

    E1-->>O: {draft, approvalRequestId}
    E2-->>O: {draft, approvalRequestId}
    EN-->>O: {draft, approvalRequestId}

    O->>AG: write N ApprovalRequests to Firestore
    AG->>U: FCM push: "20 follow-up drafts ready for review"

    U->>AG: approve all / review / reject per lead

    par Dispatch approved sends
        AG->>WA: commit send L1 (idempotencyKey)
        AG->>WA: commit send L2 (idempotencyKey)
        AG->>WA: commit send LN (idempotencyKey)
    end

    WA-->>O: provider message IDs
    O->>U: "20 follow-ups sent. 2 skipped (rejected)."
Loading

Orchestration paths:

Complexity Path
Simple read/summary Single agent + tool loop
Drafting Single agent + draft tool (no approval needed)
Write or external send Planner → Executor → Approval Gate
Customer-facing reply Executor → Channel Formatter → send or approval
Bulk operation Planner → N parallel Executor sub-agents → aggregate

8.10 Deterministic Host Control

The following are never decided by the model. They are injected by infrastructure and are immutable during a run:

  • tenantId
  • workspaceId
  • sender identity (which phone number, which Gmail account)
  • delivery channel
  • approval requirement
  • escalation target
  • tool allowlist (filtered before being sent to the model)

Violation of this principle is a critical security defect, not a product bug.


9. Technology Stack

9.1 Language & Runtime Choices

Service Language Rationale
croohm-api (gateway) Go Goroutine-based concurrency for high-throughput routing; single binary; fast cold start on Cloud Run; strong standard library for auth + HTTP
croohm-orchestrator TypeScript / Node.js OpenRouter-compatible SDK usage + LangGraph.js are TypeScript-native; async I/O is ideal for LLM API calls (mostly waiting); same language as web app frontend → shared types
croohm-connectors TypeScript / Node.js Gmail API + WhatsApp API SDKs have strong TypeScript support; WebSocket handling; event-driven pattern
croohm-workers Python Best ML/embedding ecosystem; sentence-transformers, RAGAS, DeepEval are Python-native; eval tooling is Python-dominant
Mobile App React Native / Expo Existing stack (per croohm-mobile directory)

Why not Python for orchestration? Python's GIL limits true parallelism for concurrent agent sessions. At 50 concurrent workspace sessions, TypeScript's event loop significantly outperforms Python asyncio for I/O-bound LLM API calls. Go was considered but LangGraph.js and the JavaScript model-routing ecosystem make TypeScript the pragmatic choice for the orchestration layer.

Why not a single language? Python must be used for the embedding pipeline — no production-grade alternative exists. Go must be used for the API gateway — TypeScript's startup time and memory overhead under load is a meaningful cost at 100+ instances. TypeScript is optimal for orchestration. Polyglot with clear service boundaries is the right trade-off here.

9.2 Model Routing and Provider Strategy

9.2.1 Two Concepts That Must Not Be Confused

Before describing the routing architecture, it is important to be precise about what "self-hosted" means in different contexts, because the terms are used loosely in the industry and conflating them leads to wrong architectural decisions.

graph TD
    subgraph A["Option A: Hosted Gateway (OpenRouter)"]
        direction LR
        A1[CRoohM Orchestrator<br/>on GCP Cloud Run] -->|HTTPS prompt| A2[OpenRouter<br/>hosted by OpenRouter Inc.]
        A2 -->|HTTPS prompt| A3[LLM Provider<br/>MiniMax / Anthropic / Google]
        A3 -->|response| A2
        A2 -->|response| A1
    end

    subgraph B["Option B: Self-Hosted Gateway (LiteLLM on GCP)"]
        direction LR
        B1[CRoohM Orchestrator<br/>on GCP Cloud Run] -->|HTTPS prompt| B2[LiteLLM Proxy<br/>on GCP Cloud Run — YOUR infra]
        B2 -->|HTTPS prompt| B3[LLM Provider<br/>MiniMax / Anthropic / Google]
        B3 -->|response| B2
        B2 -->|response| B1
    end

    subgraph C["Option C: Self-Hosted Model (GPU VM)"]
        direction LR
        C1[CRoohM Orchestrator<br/>on GCP Cloud Run] -->|HTTPS prompt| C2[Your GPU VM<br/>running Llama / Mistral / Qwen<br/>model weights on your hardware]
        C2 -->|response| C1
    end

    style A fill:#bbf7d0,stroke:#16a34a
    style B fill:#dbeafe,stroke:#2563eb
    style C fill:#fef9c3,stroke:#ca8a04
Loading

Option A — Hosted Gateway (OpenRouter): CRoohM's orchestrator sends prompts to OpenRouter's servers. OpenRouter routes the prompt to the chosen LLM provider (e.g. MiniMax). The model runs at MiniMax's data center. Your prompt passes through two third-party systems: OpenRouter and MiniMax.

Option B — Self-Hosted Gateway (LiteLLM on your Cloud Run): You run the routing proxy yourself inside GCP. The model still runs at Anthropic's / MiniMax's / Google's data center — nothing changes there. Your prompt passes through only one third-party system: the final LLM provider. The gateway layer is on your infra.

Option C — Self-Hosted Model (GPU VM running Llama/Mistral): You download open-source model weights and run the actual inference on your own GPU hardware. Prompts never leave your infrastructure. This requires GPU VMs (A100/H100 class), significant MLOps work, and is only practical with open-weight models (Llama 3, Mistral, Qwen, Phi, etc.). Enterprise pricing.

CRoohM V1 uses Option A. Option B is the upgrade path for enterprise data residency requirements. Option C is not in scope.


9.2.2 Model Gateway Comparison

Gateway Type Models Available Key Advantage Key Limitation Data Path
OpenRouter Hosted 300+ models, 50+ providers including MiniMax, Claude, Gemini, Llama, free models Zero ops, MiniMax available, free model tier, OpenAI-compatible API Prompts pass through OpenRouter's servers before reaching the LLM provider Your cloud → OpenRouter (US) → LLM provider
LiteLLM Self-hosted (you run it on Cloud Run) Same 100+ providers as OpenRouter, OpenAI-compatible API Prompt never leaves GCP — only goes to the final LLM provider. Full control over logs, caching, routing logic. Adds a service to operate (Docker, Redis, Postgres). You own uptime. Your cloud → LiteLLM on GCP → LLM provider
Portkey Hosted or self-hosted 200+ LLMs, OpenAI-compatible Enterprise observability, semantic caching, guardrails baked in Hosted version has same data residency concern as OpenRouter Your cloud → Portkey → LLM provider
Google Vertex AI GCP-managed Gemini, Claude (via Anthropic partnership), Mistral, Llama Fully GCP-native, managed infra, data stays in GCP region, no extra proxy hop MiniMax not available; locks you into GCP's model catalogue Your cloud → Vertex (same GCP region) → model
AWS Bedrock AWS-managed Claude, Titan, Mistral, Llama, Cohere AWS-native, data residency in AWS region Not relevant if CRoohM is on GCP; MiniMax not available Your cloud → Bedrock (AWS) → model
Direct provider APIs N/A (no proxy) One provider per integration (Anthropic API, OpenAI API, etc.) Simplest setup, no proxy in the chain Must write and maintain separate SDK integrations per provider; routing logic lives in your orchestrator code Your cloud → LLM provider directly

Why OpenRouter is selected for V1 over the alternatives:

  1. MiniMax availability: The RFC's primary model choice (MiniMax) is available on OpenRouter. It is not on Vertex AI or Bedrock. Going direct to MiniMax's API is an option but loses the routing abstraction.

  2. Free model tier: OpenRouter operates a free model router — eligible open models can be called at $0 token cost for low-risk workloads (classification, summarization, intent detection). This directly enables CRoohM's $8–15/workspace/month cost target.

  3. Routing abstraction: The orchestrator calls one endpoint with one auth header. Model selection, fallback ordering, and provider failover are controlled by the RoutePolicy record in Firestore — no orchestrator code changes when a route policy is updated.

  4. 300+ models in one API surface: MiniMax today, Claude for high-stakes tasks tomorrow, a free OSS model for classification next week — all through the same API call shape.

Why LiteLLM is the V2 upgrade path (not V1):

LiteLLM is the right choice when enterprise customers raise data residency concerns — specifically, the question "does our customer data (lead names, conversation content in prompts) pass through a US-based third party's servers?" With OpenRouter, the answer is yes. With LiteLLM self-hosted on GCP in the customer's preferred region, the answer is no.

The switch from OpenRouter to LiteLLM requires:

  • deploying a LiteLLM Docker container to Cloud Run (one-time)
  • updating the OPENROUTER_BASE_URL env var in the orchestrator to point at LiteLLM instead
  • migrating RoutePolicy records to use LiteLLM route format

That is a configuration change, not an architecture change. The orchestrator code does not change because both OpenRouter and LiteLLM expose an OpenAI-compatible API.


9.2.3 Call Flow: Prompt to Response

sequenceDiagram
    participant MA as Mobile App
    participant GW as API Gateway (Go)
    participant OR as Orchestrator (TypeScript)
    participant RP as RoutePolicy (Firestore)
    participant ORouter as OpenRouter<br/>(or LiteLLM in V2)
    participant LLM as LLM Provider<br/>(MiniMax / Anthropic / etc.)

    MA->>GW: POST /agent/run {message, contextObjectId}
    GW->>OR: forward + inject {tenantId, workspaceId}

    OR->>RP: load RoutePolicy for useCase="planner"
    RP-->>OR: {primaryRoute: "openrouter:minimax", fallback: ["openrouter:free"]}

    OR->>OR: assemble context (8 layers)<br/>build system prompt + tools + user message

    OR->>ORouter: POST /chat/completions<br/>Authorization: Bearer OPENROUTER_KEY<br/>model: "minimax/minimax-01"<br/>tools: [...workspace_allowed_tools]

    ORouter->>LLM: forward to MiniMax API<br/>(OpenRouter handles auth + routing)

    LLM-->>ORouter: {tool_call: "read_lead", arguments: {leadId}}
    ORouter-->>OR: stream tool call delta

    OR->>OR: execute tool: read_lead(leadId)<br/>scoped to {tenantId, workspaceId}

    OR->>ORouter: POST /chat/completions (tool result appended)
    ORouter->>LLM: next inference step
    LLM-->>ORouter: {content: "Here are the 5 leads..."}
    ORouter-->>OR: stream final response

    OR-->>MA: SSE events: token stream + run_complete
Loading

9.2.4 Route Policy Design

Every agent capability has a named route policy stored in Firestore. The orchestrator reads the policy at run time — it never hardcodes a model name.

// RoutePolicy document in Firestore
{
  id: "planner_v3",
  useCase: "planner",
  primaryRoute: "openrouter:minimax/minimax-01",
  fallbackRoutes: [
    "openrouter:anthropic/claude-3-haiku",  // if MiniMax is degraded
    "openrouter:google/gemini-flash-1.5"    // if Claude is also degraded
  ],
  evalVersion: "eval_2026_04_10",
  status: "active"
}

{
  id: "classification_v2",
  useCase: "classification",
  primaryRoute: "openrouter:free",           // free model router
  fallbackRoutes: ["openrouter:minimax/minimax-01"],
  evalVersion: "eval_2026_04_08",
  status: "active"
}

Rules:

  • Route changes require replay against the failure bucket eval suite before promotion to status: "active"
  • openrouter:free is only permitted for useCase values in: ["classification", "extraction", "summarization"]
  • external_send and admin tool calls may only execute on routes with evalVersion dated within 30 days
  • A route degradation event (OpenRouter reports provider down) automatically promotes the first fallback and logs a RouteFailoverEvent

9.2.5 Route Use Case Table

Use Case V1 Primary Route V1 Fallback Why
Operator agent orchestration (planner + executor) openrouter:minimax/minimax-01 openrouter:anthropic/claude-3-haiku Strong reasoning, tool-use accuracy, cost-effective
Channel agent responses openrouter:minimax/minimax-01 openrouter:anthropic/claude-3-haiku One strong default until live evals justify divergence
Intent classification openrouter:free openrouter:minimax/minimax-01 Low stakes, simple binary/categorical output, free is sufficient
Lead summarization openrouter:free openrouter:minimax/minimax-01 Low stakes, no external send
Knowledge retrieval judge openrouter:minimax/minimax-01 none Faithfulness check before customer-facing response
Embeddings Single provider, fixed per env Mixed embedding spaces break vector search
Web-grounded research (Phase 5) Perplexity Sonar API Best-in-class search grounding, separate from action loop

Cost levers:

  • Prompt caching on workspace config + platform policy prefix (expected 60–70% cache hit rate on repeat sessions)
  • Free model route for classification before invoking the expensive planner
  • Context compaction: ContextSummary replaces raw conversation history beyond a sliding window
  • Route tuning based on task completion rate and correction rate — not raw token cost alone

9.3 Learning, Feedback, and Adjustment Loop

CroohM agents must improve continuously. This is a closed-loop system:

  • collect explicit feedback: approve, reject, thumbs up/down, edited-before-send
  • collect implicit feedback: customer replied positively, customer ignored, user rewrote draft, tool retried, human took over
  • run nightly replay against recent failures and golden datasets
  • adjust prompts, skills, tool descriptions, retrieval settings, and route policy based on measured outcomes
flowchart LR
    PR["Production Runs"] --> FB["User + System Feedback"]
    PR --> TR["Run Traces"]
    FB --> EV["Eval + Review"]
    TR --> EV
    EV --> PV["Prompt Versions"]
    EV --> SV["Skill / Tool Updates"]
    EV --> RV["Route Policy Updates"]
    EV --> KV["Knowledge Tuning"]
    PV --> NX["Next Deployable Agent Config"]
    SV --> NX
    RV --> NX
    KV --> NX
Loading

Required failure buckets:

  • wrong tool selected
  • wrong target object
  • bad retrieval or missing source
  • hallucinated answer
  • poor channel formatting
  • weak personalization
  • approval-worthy action missed

No route, prompt, or skill change should be promoted without replaying those buckets.

9.4 Agent Orchestration Framework

Primary: LangGraph.js (TypeScript)

LangGraph reached v1.0 stable with 38M monthly downloads (March 2026). It is used in production by Klarna and Replit. Its six built-in primitives — parallelization, streaming, checkpointing, human-in-the-loop, tracing, and task queue — are all required for CroohM's agent platform.

Key LangGraph features we depend on:

  • Checkpointing: If an orchestrator crashes mid-run, the run resumes from the last checkpoint on restart — critical for approval-gate workflows that can take hours
  • Human-in-the-loop: Native support for pausing execution pending human approval — maps directly to our ApprovalRequest model
  • Streaming: Real-time token streaming to mobile client via SSE
  • Parallelization: Concurrent sub-agent fan-out for bulk operations

Alternative considered: Temporal

Temporal provides durable execution at a higher infrastructure level (separate Temporal cluster). It is the right choice for workflows measured in hours/days. For CroohM V1, LangGraph's native checkpointing in Firestore is sufficient and reduces operational complexity. Temporal is the V2 upgrade path when workflow durations exceed 30 minutes regularly.

Alternative considered: Google ADK

Google ADK (TypeScript) is compelling on GCP. Its adk deploy cloud_run single-command deployment is excellent. However, ADK is Gemini-optimized and ties orchestration more tightly to Vertex AI. CroohM's primary routing layer is OpenRouter and the runtime must stay model-agnostic, so LangGraph gives us more control over the tool-use loop. ADK is worth revisiting if we add Gemini-optimized workflows in V2.

Alternative considered: OpenAI Agents SDK (TypeScript)

Production-stable, provider-agnostic, excellent primitives (Agent, Runner, Handoff, Guardrail, Session). The handoff model maps cleanly to agent-to-human escalation. However, LangGraph's graph model is better suited to CroohM's complex multi-step workflow needs (parallel fan-out, conditional branching, long-running pauses). OpenAI Agents SDK is better for simpler linear agent flows.

9.5 Vector Database

Recommendation: shared vector infrastructure with strict namespace isolation

Rationale:

  • V1 does not need one physical vector database per workspace
  • every chunk must include tenantId, workspaceId, sourceId, and visibility
  • every retrieval query must enforce tenant/workspace filters before any semantic result is used
  • the security model relies on CroohM-controlled filters, audit logs, and delete behavior, not vendor marketing claims
  • dedicated enterprise indexes can be added later for residency or compliance needs

Migration path:

  • V1: managed shared vector backend with strict namespace filtering and deletion support
  • V2: dedicated enterprise indexes or self-hosted isolation mode where required

Rejected as default: per-workspace physical vector stores — operationally expensive and unnecessary for most SMB workloads.

Hard requirement regardless of vendor: filtered retrieval, namespace isolation, deletion support, and query auditability.

9.6 Primary Database

Firestore for all application state (existing infrastructure):

  • AgentRun, AgentRunStep, ApprovalRequest, WorkspaceAgent, ContextSummary, etc.
  • Multi-named databases: one Firestore database per environment (prod, staging, dev)
  • Document-level security rules enforce workspace isolation as a defense-in-depth measure
  • Real-time listeners for approval status polling on mobile (no polling needed — Firestore pushes updates)

Firestore is the right choice here because:

  • CroohM already operates on Firestore — no migration cost
  • Real-time listeners are critical for approval flow UX (user must see "approved" update instantly on mobile)
  • Schema flexibility is valuable for the evolving agent run step structure
  • Firestore scales automatically — no capacity planning needed

9.7 Infrastructure

Component GCP Service
Container runtime Cloud Run (API, Orchestrator, Connectors)
Batch jobs Cloud Run Jobs
Task queue Cloud Tasks (guaranteed delivery + retry)
Event bus Pub/Sub (Gmail watch → Connector; Connector → Orchestrator)
Scheduler Cloud Scheduler (workflow triggers)
Secret storage Secret Manager (model API keys, connector OAuth tokens)
Key management Cloud KMS (envelope encryption for secrets in Firestore)
Object storage Cloud Storage (knowledge docs, run trace archives, eval datasets)
Cache + locks Memorystore for Redis (session lane locks, rate limit counters, context cache)
Monitoring Cloud Monitoring + Cloud Trace + Error Reporting
LLM observability Langfuse (self-hosted on Cloud Run)
Container registry Artifact Registry
Auth Firebase Auth / Identity Platform
Push notifications Firebase Cloud Messaging (approval request notifications to mobile)

9.8 LLM Observability: Langfuse

Langfuse (self-hosted on Cloud Run, backed by Postgres on Cloud SQL):

  • Every agent run emits a Langfuse trace with spans for: context assembly, each LLM call, each tool execution, approval gate events
  • Captures: input tokens, output tokens, cached tokens, model, latency per span, total cost
  • LLM-as-judge eval pipeline runs nightly: scores run traces on task completion, faithfulness, hallucination
  • Prompt versioning: all system prompts version-controlled in Langfuse prompt management
  • Zero data residency concern: self-hosted, all trace data stays on GCP

10. AI Tool Landscape Analysis

10.1 MCP and Tool Ecosystem Integration

CroohM should build an MCP server exposing CroohM capabilities to the broader agent ecosystem. This serves two purposes:

  1. Developer tooling: Engineers using MCP-capable clients can interact with CroohM data during development and debugging without leaving the terminal
  2. Ecosystem reach: Any MCP-compatible client can connect to CroohM's tools — turning CroohM into an AI-accessible business platform, not just an app

Proposed CroohM MCP Server tools:

// Read tools
list_leads(workspaceId, filters)  Lead[]
get_lead(leadId)  Lead + conversation history
get_pipeline_summary(workspaceId)  PipelineSummary
search_knowledge(workspaceId, query)  KnowledgeChunk[]

// Draft tools (no approval needed)
draft_whatsapp_message(leadId, context)  MessageDraft
draft_gmail_reply(conversationId, context)  EmailDraft

// Write tools (approval required)
update_lead_status(leadId, status, notes)  Lead
send_whatsapp_message(leadId, messageId)  SendResult
send_gmail(conversationId, draftId)  SendResult

MCP server deployment: Cloud Run service behind IAP, with OAuth 2.0 scoped to workspace access.

10.2 OpenRouter as the Provider Control Plane

OpenRouter is not just a model marketplace for CroohM. It acts as the provider control plane:

  • one auth and routing layer for multiple model providers
  • route ordering and fallback can be changed without modifying the tool runtime
  • free/open models can be introduced gradually behind eval gates
  • cost, latency, and success rate can be tracked at the route-policy level instead of hardcoding a single vendor forever

This fits CroohM's product posture: business users should not care which provider was used, only whether the task was completed safely and cheaply.

10.3 Dispatch Data Layer: Explorium / Vibe Prospecting MCP

Decision: integrate, do not build.

Vibe Prospecting is built on Explorium's data platform. Explorium already exposes their full dataset via an MCP server (explorium-ai/mcp-explorium on GitHub), covering:

  • 146M+ business entities, 767M+ employee profiles across 50+ data sources
  • 4,000+ signals: funding events, IPOs, M&As, hiring signals, tech stack changes, website changes, intent data
  • APIs: EventAPI (real-time triggers), FetchAPI (filter-based company/people search), EnrichAPI (multi-source enrichment)
  • 10K records/min throughput, 97.8% firmographic accuracy
  • Pricing: $200 for 5K credits (12-month expiry, no rollover)

CRoohM's Dispatch capability should consume Explorium's MCP server rather than building a proprietary data layer. The differentiation CRoohM adds is not the data itself — it is:

  1. The context layer: leads are already in the CRoohM inbox with conversation history — enrichment is applied to records the user already knows
  2. The execution layer: draft, approve, send WhatsApp/Gmail outreach — all inside CRoohM without switching apps
  3. The memory layer: Dispatch results feed the Brain's ContextSummary — future interactions are informed by the prospect research

This is the correct build vs buy decision for V1. Revisit building a proprietary data layer at Phase 4 if Explorium's coverage or pricing becomes limiting.

Integration approach:

  • Dispatch agent exposes Explorium as a tool in its tool registry (search_prospects, enrich_lead, get_intent_signals)
  • Tool calls route to Explorium MCP server via the tool runtime
  • Credit consumption is tracked per workspace and attributed to AI usage billing
  • Enriched data is written back to the Lead record in Firestore with sourceType: "explorium" and timestamp

Cost model:

  • Light enrichment (email + phone per lead): ~1–2 credits per lead
  • Full enrichment (firmographics + signals + intent): ~5–10 credits per lead
  • Prospect list search (20 results): ~10–20 credits
  • At $200/5K credits: full enrichment runs ≈ $0.20/lead — well within SMB budget if leads are pre-qualified

10.4 Perplexity Computer Integration

Perplexity Computer (Feb 2026) orchestrates a routed multi-model environment in a sandboxed execution layer.

What this means for CroohM:

  • The $200/month Perplexity Max user is CroohM's ideal enterprise customer profile — they pay for autonomous execution
  • Perplexity's Sonar API (search-grounded LLM responses) is useful within CroohM's operator agent for research tasks: "Find this company's latest funding round" or "What is this contact's LinkedIn background?"
  • CroohM can optionally route research-type tool calls to Perplexity Sonar rather than building its own web search — reduces build scope, leverages best-in-class search grounding

10.5 OpenClaw (formerly Moltbot/Clawdbot — renamed January 27, 2026)

OpenClaw is an open-source, self-hosted personal AI assistant. The product went through three names: ClawdBot → Moltbot → OpenClaw. It connects to WhatsApp, Telegram, Slack, Discord, iMessage, Signal, Microsoft Teams, Matrix, Google Chat (10+ platforms simultaneously) and acts as one unified conversation layer across all of them.

Key capabilities (2026 verified):

  • Proactive outreach: sends you messages first — reminders, alerts, morning briefings — without waiting to be prompted
  • Persistent memory: remembers everything across sessions; never repeats context when picking up unfinished work
  • Task execution: runs shell commands, controls the browser, reads/writes files, manages calendar, sends emails — all triggered by a text message in WhatsApp or Telegram
  • Self-hosted: no SaaS subscription; you own the data and the compute

What this means for CRoohM:

  • OpenClaw validates the core CRoohM thesis: multi-channel AI that acts beats single-channel AI that talks
  • OpenClaw's biggest gaps are exactly CRoohM's strengths: no multi-tenant model, no workspace/team concept, no WhatsApp Business API (uses personal WhatsApp only), no CRM data layer
  • OpenClaw's proactive surface pattern is the design reference for CRoohM's Brain proactive alerts ("3 leads haven't been followed up — want me to draft outreach?")
  • OpenClaw's persistent memory model (facts, preferences, ongoing projects across sessions) maps directly to CRoohM's ContextSummary schema
  • The skill/plugin marketplace approach is worth studying for CRoohM's V3 Playbook template marketplace

10.6 OpenAI Agents SDK

Production-stable in 2026. Provider-agnostic (100+ LLMs). Key primitives: Agent, Runner, Handoff, Guardrail, Session.

Decision: Do not use OpenAI Agents SDK as CroohM's orchestration framework.

Rationale: LangGraph's graph model is better suited to CroohM's complex workflow needs (parallel fan-out, conditional approval branching, long-running pauses, checkpointing). OpenAI Agents SDK excels at linear agent flows. However, OpenAI Agents SDK's Guardrail primitive is a useful pattern to copy: pre-run and post-run validation functions that block unsafe inputs/outputs before they reach the agent or the user.

CroohM should implement a GuardrailLayer with the same semantics:

  • Input guardrails: block prompt injection attempts, enforce workspace scope in user messages
  • Output guardrails: detect PII in channel-bound messages, block unsupported instructions, enforce brand voice

10.7 Google ADK

Google's Agent Development Kit (Python + TypeScript, deployed to Cloud Run with adk deploy cloud_run). Supports Sequential, Parallel, Loop workflow agents. Integrates with Vertex AI Agent Engine. Uses MCP as a client standard.

Decision: Use as deployment reference, not as orchestration framework.

CroohM will use Cloud Run (ADK's target deployment platform) and will implement MCP (ADK's integration standard) but will use LangGraph instead of ADK's agent runtime. If CroohM adds Gemini as a V2 LLM provider, ADK becomes a natural orchestration option for Gemini-specific workflows.


11. Data Model

11.1 New Entities

WorkspaceAgent

{
  id: string;
  workspaceId: string;
  tenantId: string;
  type: "channel" | "operator" | "workflow";
  status: "draft" | "live" | "paused" | "archived";
  name: string;
  persona: string;                   // system prompt persona section
  brandVoice: string;                // tone and style instructions
  allowedSkills: string[];           // Skill IDs
  approvalPolicy: ApprovalPolicy;
  channelDeployments: string[];      // ChannelDeployment IDs
  modelOverride?: string;            // override default model for this agent
  createdAt: Timestamp;
  updatedAt: Timestamp;
}

AgentRun

{
  id: string;                        // runId
  workspaceId: string;
  tenantId: string;
  agentId: string;
  agentType: AgentType;
  sessionLaneKey: string;
  status: RunStatus;
  triggeredBy: "user" | "workflow" | "webhook" | "scheduler";
  triggeredByUserId?: string;
  input: {
    message: string;
    objectType?: "lead" | "conversation" | "task";
    objectId?: string;
    channelId?: string;
  };
  output?: {
    message?: string;
    actions: ActionRecord[];
  };
  modelUsed: string;
  tokenUsage: {
    inputTokens: number;
    outputTokens: number;
    cachedTokens: number;
    estimatedCostUsd: number;
  };
  startedAt: Timestamp;
  completedAt?: Timestamp;
  durationMs?: number;
  langfuseTraceId?: string;
  error?: string;
  steps: AgentRunStep[];             // subcollection
}

AgentRunStep

{
  id: string;
  runId: string;
  stepType: "llm_call" | "tool_call" | "approval_gate" | "handoff" | "context_assembly";
  toolName?: string;
  toolInput?: Record<string, unknown>;
  toolOutput?: Record<string, unknown>;
  llmModel?: string;
  promptTokens?: number;
  completionTokens?: number;
  cachedTokens?: number;
  latencyMs: number;
  status: "completed" | "failed" | "pending_approval" | "approved" | "rejected";
  sequenceNumber: number;
  createdAt: Timestamp;
}

ApprovalRequest

{
  id: string;
  runId: string;
  stepId: string;
  workspaceId: string;
  requestedByUserId?: string;
  approvalMode: ApprovalMode;
  actionType: ToolRisk;
  toolName: string;
  payload: Record<string, unknown>;  // what will be executed on approval
  humanReadableSummary: string;      // plain language description shown in mobile UI
  status: "pending" | "approved" | "rejected" | "expired";
  reviewedByUserId?: string;
  reviewedAt?: Timestamp;
  expiresAt: Timestamp;              // auto-reject after TTL
  createdAt: Timestamp;
}

PreparedAction

{
  id: string;
  workspaceId: string;
  tenantId: string;
  runId: string;
  sessionLaneKey: string;
  toolName: string;
  targetObjectId: string;
  idempotencyKey: string;
  providerPayload: Record<string, unknown>;
  providerName?: string;
  providerMessageId?: string;
  sendRequestId: string;
  status: "prepared" | "committed" | "aborted" | "expired";
  expiresAt: Timestamp;
  committedAt?: Timestamp;
  createdAt: Timestamp;
}

KnowledgeSource

{
  id: string;
  workspaceId: string;
  tenantId: string;
  type: "website" | "document" | "snippet" | "crm_object" | "template" | "playbook";
  name: string;
  syncStatus: "pending" | "syncing" | "synced" | "failed";
  reviewStatus: "unreviewed" | "approved" | "rejected";
  visibility: "workspace_internal" | "customer_safe" | "agent_only";
  lastSyncedAt?: Timestamp;
  chunkCount?: number;
  rawFileGcsUri?: string;
  createdAt: Timestamp;
  updatedAt: Timestamp;
}

ContextSummary

{
  id: string;
  workspaceId: string;
  sessionLaneKey: string;            // the entity this summary belongs to
  summaryShort: string;             // 1–2 sentence summary for context assembly
  summaryWorking: string;           // working memory: current state, pending items
  extractedFacts: string[];         // structured facts extracted from conversation
  openLoops: string[];              // unresolved commitments or questions
  customerIntent?: string;          // for channel agents: what the customer wants
  lastUpdatedAt: Timestamp;
  turnCount: number;
}

CredentialProfile

{
  id: string;
  workspaceId: string;
  tenantId: string;
  provider: "anthropic" | "openai" | "perplexity" | "google_vertex";
  ownerScope: "platform" | "tenant" | "workspace";
  mode: "platform_managed" | "byok";
  allowedModels: string[];
  allowedUseCases: string[];
  healthStatus: "healthy" | "degraded" | "failed";
  cooldownUntil?: Timestamp;
  regionPolicy?: string;
  billingLabel: string;
  secretManagerRef: string;         // path in Secret Manager — never the key itself
  createdAt: Timestamp;
}

RoutePolicy

{
  id: string;
  workspaceId?: string;             // optional override; defaults to platform policy
  name: string;
  useCase: "planner" | "channel_reply" | "classification" | "summarization" | "retrieval_judge";
  primaryRoute: string;             // e.g. openrouter:minimax
  fallbackRoutes: string[];
  evalVersion: string;
  status: "draft" | "active" | "deprecated";
  updatedAt: Timestamp;
}

RunFeedback

{
  id: string;
  runId: string;
  workspaceId: string;
  source: "user" | "system" | "reviewer";
  signalType: "thumbs_up" | "thumbs_down" | "approved" | "rejected" | "edited_before_send" | "handoff" | "task_completed" | "task_failed";
  label?: string;                   // failure bucket label
  notes?: string;
  createdByUserId?: string;
  createdAt: Timestamp;
}

11.2 Extended Existing Entities

Lead (additions)

priorityScore: number;             // 0–100, AI-computed
nextAction: string;
nextActionAt: Timestamp;
qualificationState: "unqualified" | "mql" | "sql" | "opportunity" | "lost" | "won";
lastAgentTouchAt?: Timestamp;
ownerTeamId?: string;

Conversation (additions)

agentDeploymentId?: string;
handoffState: "agent" | "human" | "closed";
lastAgentRunId?: string;
summaryShort?: string;
summaryWorking?: string;
openLoops?: string[];
customerIntent?: string;
resolutionState: "open" | "resolved" | "escalated";

Message (additions)

generatedByAgent: boolean;
approvalState?: "pending" | "approved" | "rejected" | "auto_sent";
runId?: string;
channelFormattingMode?: "whatsapp" | "email" | "chat";

11.3 Type Reference

type AgentType = "channel" | "operator" | "workflow";
type RunStatus = "queued" | "planning" | "running" | "waiting_approval" | "completed" | "failed" | "cancelled";
type ToolRisk = "read" | "draft" | "write" | "external_send" | "admin" | "connector_admin";
type ApprovalMode = "none" | "send_only" | "external_only" | "all_mutations" | "policy_driven";
type CredentialMode = "platform_managed" | "byok";
type KnowledgeSourceType = "website" | "snippet" | "document" | "crm_object" | "conversation" | "template" | "playbook";
type HandoffState = "agent" | "human" | "closed";
type ResolutionState = "open" | "resolved" | "escalated";

12. API Design

12.1 Agent Interaction APIs

POST /v1/workspaces/{workspaceId}/agent/run
  Body: { message: string, contextObjectType?, contextObjectId?, channelId? }
  Response: { runId, status, streamUrl }
  → Creates an agent run, returns SSE stream URL for real-time token streaming

GET /v1/workspaces/{workspaceId}/agent/runs/{runId}
  Response: AgentRun with steps subcollection

GET /v1/workspaces/{workspaceId}/agent/runs
  Query: status?, agentType?, limit?, startAfter?
  Response: AgentRun[]

POST /v1/workspaces/{workspaceId}/approvals/{approvalId}/approve
  Body: { reviewNotes?: string }
  Response: { status: "approved", resumeRunId }

POST /v1/workspaces/{workspaceId}/approvals/{approvalId}/reject
  Body: { reason: string }
  Response: { status: "rejected" }

GET /v1/workspaces/{workspaceId}/approvals
  Query: status=pending
  Response: ApprovalRequest[]

POST /v1/workspaces/{workspaceId}/agent/runs/{runId}/feedback
  Body: { signalType, label?, notes? }
  Response: RunFeedback

12.2 Agent Configuration APIs

POST /v1/workspaces/{workspaceId}/agents
GET  /v1/workspaces/{workspaceId}/agents
PATCH /v1/workspaces/{workspaceId}/agents/{agentId}
POST /v1/workspaces/{workspaceId}/agents/{agentId}/deploy    → sets status=live
POST /v1/workspaces/{workspaceId}/agents/{agentId}/pause     → sets status=paused

12.3 Knowledge APIs

POST /v1/workspaces/{workspaceId}/knowledge/sources
  Body: { type, name, url? } + multipart file upload
  Response: KnowledgeSource (syncStatus=pending, triggers async indexing)

GET  /v1/workspaces/{workspaceId}/knowledge/sources
GET  /v1/workspaces/{workspaceId}/knowledge/sources/{sourceId}
DELETE /v1/workspaces/{workspaceId}/knowledge/sources/{sourceId}

POST /v1/workspaces/{workspaceId}/knowledge/search
  Body: { query, topK?, visibilityFilter? }
  Response: KnowledgeChunk[]

12.4 Streaming (SSE)

Agent responses stream as Server-Sent Events:

event: token
data: {"token": "Sure", "runId": "run_abc123"}

event: tool_call_start
data: {"toolName": "read_lead", "runId": "run_abc123"}

event: tool_call_result
data: {"toolName": "read_lead", "result": {...}, "latencyMs": 45}

event: approval_required
data: {"approvalId": "apr_xyz", "summary": "Send WhatsApp to John Doe: 'Following up...'"}

event: run_complete
data: {"runId": "run_abc123", "status": "completed", "durationMs": 3420}

12.5 Transport Protocol Decision: REST + SSE vs gRPC vs WebSocket

This section documents the evaluated options and the rationale behind CroohM's chosen transport model.

12.5.1 Options Evaluated

Option A: REST + SSE (Selected)

How it works:

  • All control-plane calls (start run, approve, reject, configure) → standard REST/HTTP POST/GET
  • Agent response streaming → Server-Sent Events (SSE) on a long-lived HTTP connection
  • Push notifications for approvals → Firebase Cloud Messaging (FCM)
  • Real-time Firestore listeners on mobile for approval state changes
sequenceDiagram
    participant App as Mobile App
    participant GW as API Gateway (Go)
    participant OR as Orchestrator
    participant FS as Firestore

    App->>GW: POST /agent/run {message, contextObjectId}
    GW->>OR: forward with injected {tenantId, workspaceId}
    OR-->>App: 200 {runId, streamUrl}

    App->>OR: GET /stream/{runId} (SSE connection)
    loop Token streaming
        OR-->>App: event: token {data: "Sure,"}
        OR-->>App: event: tool_call_start {data: "read_lead"}
        OR-->>App: event: tool_call_result {data: {...}}
    end
    OR-->>App: event: approval_required {approvalId, summary}
    OR-->>App: event: run_complete {status: "waiting_approval"}

    Note over App,FS: FCM push notification triggers app foreground

    App->>FS: listen on ApprovalRequests/{approvalId}
    App->>GW: POST /approvals/{approvalId}/approve
    GW->>OR: resume run
    OR-->>App: event: run_complete {status: "completed"}
Loading

Why SSE and not polling:

  • SSE is unidirectional server-to-client — exactly what token streaming requires
  • SSE works over HTTP/1.1 — no infrastructure changes, CDN-compatible, Cloud Run native
  • SSE reconnects automatically on disconnect — React Native handles this with the EventSource polyfill
  • Firestore listeners handle the approval state change event — no polling needed

Option B: gRPC + gRPC Streaming (Not Selected for V1)

How it works:

  • Bidirectional streaming via .proto service definitions
  • Client and server exchange structured protobuf messages
  • Single persistent connection for the full run lifecycle

Evaluated against:

Criterion gRPC REST + SSE
Mobile client support Needs grpc-web proxy layer + React Native adapter Native fetch + EventSource — no adapter
Cloud Run + load balancer Requires HTTP/2 end-to-end — extra LB config HTTP/1.1 SSE — works out of the box
Streaming Bidirectional — more power than needed Server-to-client only — correct for this use case
Schema enforcement Protobuf — strict and auto-generated OpenAPI + JSONSchema — sufficient
Debug toolability Requires specialized tooling (grpcurl, BloomRPC) curl, browser DevTools, Postman — zero setup
Team familiarity Requires .proto authoring learning curve REST is universal

Decision: gRPC is the right choice when you have high-throughput bidirectional streaming between internal services (e.g. ML inference pipelines). For CroohM's use case — a mobile client receiving token streams and occasional control messages — REST + SSE is simpler to operate and debug with no meaningful capability gap.

Revisit gRPC for: internal service-to-service calls between croohm-orchestrator and croohm-connectors if inter-service throughput becomes a bottleneck. This is a backend-only change with no client-side impact.

Option C: WebSocket (Not Selected)

How it works:

  • Full-duplex TCP socket connection
  • Client and server exchange arbitrary messages in both directions

Evaluated against:

Criterion WebSocket REST + SSE
Connection management Stateful session — hard to route across Cloud Run replicas without sticky sessions Stateless — any replica handles any SSE request
Mobile reconnect behavior Must implement reconnect logic manually EventSource auto-reconnects with Last-Event-ID
Cloud Run scaling Sticky sessions or external connection registry needed No special config — works natively
Use case fit Required when client sends many messages on the same connection Client only sends on control endpoints; server streams output
Operational complexity Higher — need to handle heartbeats, ping/pong, connection registry Lower — HTTP standard behavior

Decision: WebSocket is the right choice for web chat widget (bidirectional, low-latency chat). It is not the right choice for the agent run streaming channel, where the server does the talking and the client only sends control signals on separate REST endpoints.

WebSocket used for: croohm-connectors web chat widget only — where the browser and CroohM need true bidirectional chat.

12.5.2 Transport Decision Matrix

graph TD
    A{What is being<br/>transported?} -->|Agent run streaming<br/>token-by-token output| B[REST + SSE<br/>GET /stream/runId]
    A -->|Control commands<br/>run · approve · reject · configure| C[REST HTTP<br/>POST / GET / PATCH]
    A -->|Approval push<br/>notify mobile even when app is closed| D[FCM Push<br/>via Firebase Cloud Messaging]
    A -->|Real-time approval<br/>state change while app is open| E[Firestore<br/>onSnapshot listener]
    A -->|Web chat widget<br/>browser ↔ agent, bidirectional| F[WebSocket<br/>in croohm-connectors]
    A -->|Internal service calls<br/>orchestrator → connectors| G[REST HTTP<br/>V1 — revisit gRPC if bottleneck]

    style B fill:#bbf7d0,stroke:#16a34a
    style C fill:#bbf7d0,stroke:#16a34a
    style D fill:#bbf7d0,stroke:#16a34a
    style E fill:#bbf7d0,stroke:#16a34a
    style F fill:#dbeafe,stroke:#2563eb
    style G fill:#bbf7d0,stroke:#16a34a
Loading

12.5.3 Connection Lifecycle on Mobile

stateDiagram-v2
    [*] --> Idle

    Idle --> Connecting: User sends instruction
    Connecting --> Streaming: POST /agent/run → 200 OK + open SSE
    Streaming --> StreamingTools: event: tool_call_start
    StreamingTools --> Streaming: event: tool_call_result
    Streaming --> WaitingApproval: event: approval_required
    WaitingApproval --> WaitingApproval: Firestore listener active
    WaitingApproval --> Resuming: User taps Approve
    WaitingApproval --> Idle: User taps Reject
    Resuming --> Streaming: SSE resumes
    Streaming --> Idle: event: run_complete
    Streaming --> Idle: SSE disconnects → auto-reconnect via Last-Event-ID
Loading

12.5.4 Streaming Protocol: SSE Event Reference

# Agent starts
event: run_started
data: {"runId": "run_abc123", "agentType": "operator"}

# Token stream (one event per token chunk)
event: token
data: {"token": "Sure,", "runId": "run_abc123"}

# Tool called
event: tool_call_start
data: {"toolName": "read_lead", "runId": "run_abc123", "stepId": "step_001"}

# Tool returned
event: tool_call_result
data: {"toolName": "read_lead", "latencyMs": 45, "status": "ok"}

# Approval needed — client shows approval UI
event: approval_required
data: {"approvalId": "apr_xyz789", "summary": "Send WhatsApp to John Doe: 'Following up on...'", "expiresAt": "2026-03-18T12:15:00Z"}

# Run paused for approval — SSE stream ends here
event: run_paused
data: {"runId": "run_abc123", "status": "waiting_approval"}

# After user approves — new SSE stream opened on resume
event: run_resumed
data: {"runId": "run_abc123", "approvalId": "apr_xyz789"}

# Final completion
event: run_complete
data: {"runId": "run_abc123", "status": "completed", "durationMs": 3420, "actionsCommitted": 3}

# Error
event: run_error
data: {"runId": "run_abc123", "error": "Lead not found", "retryable": false}

Reconnect strategy:

  • SSE client sends Last-Event-ID header on reconnect
  • Orchestrator replays missed events from the last acknowledged event ID using LangGraph checkpoint state
  • Max reconnect window: 5 minutes from run start; after that, client fetches run state via GET /agent/runs/{runId} instead

13. Security & Threat Model

13.1 Threat Actors

Threat Actor Motivation Example Attack
Malicious tenant user Access another workspace's data Inject workspace ID in request body
Adversarial customer Manipulate agent behavior Prompt injection via customer message
Compromised workspace user Exfiltrate data via agent "List all leads and email them to me@external.com"
LLM supply chain Model behavior exploit Jailbreak via crafted knowledge source content

13.2 Controls

Tenant Isolation:

  • tenantId and workspaceId are extracted from JWT and injected by the API gateway — never trusted from request body
  • Every Firestore query is parameterized with workspaceId — no exceptions; enforced via middleware
  • Every vector retrieval query includes mandatory tenantId + workspaceId filters — hardcoded in retrieval service, not configurable by callers
  • Firestore security rules provide defense-in-depth isolation

Prompt Injection Defense:

  • User messages and customer-provided content are tagged with clear delimiters in the system prompt: <user_message>, <customer_message> — never mixed into trusted instructions
  • Input guardrail runs before every LLM call: checks for known injection patterns, workspace override attempts
  • Knowledge source content is indexed from controlled ingestion pipeline — not passed raw into prompts

Tool Execution Controls:

  • Tool allowlist is workspace-configured and injected by infrastructure before the model sees it — user cannot expand the allowlist at runtime
  • High-risk tools (external_send, admin) require explicit workspace policy enablement + approval gate
  • Tool call payloads are validated against JSONSchema before execution

Credential Security:

  • LLM API keys and OAuth tokens stored only in Secret Manager — never in Firestore documents
  • Firestore stores only the Secret Manager reference path
  • KMS-backed envelope encryption for any credential metadata stored in Firestore
  • BYOK keys isolated to the workspace's credential profile — no cross-workspace key reuse

Audit Log:

  • Every agent run, tool call, approval decision, and handoff is written to a structured audit log in Cloud Logging
  • Audit log is append-only — no delete API
  • Run traces are archived to Cloud Storage as immutable objects after 30 days

PII Controls:

  • Langfuse traces have PII masking for known patterns (phone numbers, email addresses) before trace is written
  • Provider retention and logging policy must be reviewed per active route and documented in CredentialProfile; CroohM must not assume one provider's retention defaults apply to all routes

13.3 Compliance Checklist

  • GDPR: right-to-erasure implementation — delete lead data cascades to vector chunks and context summaries
  • WhatsApp Business API Terms: no unsolicited messages outside 24h window; approved template fallback
  • SOC 2 Type II: audit log completeness, access control review, encryption at rest/transit
  • Data residency: Firestore region-pinning, vector region tagging for EU workspaces

13.4 Data Retention Matrix

Artifact System of Record Default Retention Delete Behavior
Messages / conversations Firestore product retention policy cascade delete on lead/workspace deletion where legally allowed
Agent runs Firestore + archive 30 days hot, then archived scrub PII references on delete request; retain minimal audit envelope if required
Agent run steps Firestore + archive 30 days hot, then archived deleted with parent run archive policy
Approval requests Firestore 90 days preserved until audit minimum, then purged
Prepared actions Firestore 30 days after terminal state deleted after reconciliation window
Context summaries Firestore rolling latest + 30-day history hard-delete with source conversation/lead deletion
Knowledge chunks / embeddings vector store + metadata until source deleted or resynced delete by sourceId, workspaceId, tenantId
Uploaded knowledge artifacts Cloud Storage until source deleted or retention TTL hard-delete plus tombstone record
Langfuse traces self-hosted Langfuse 30 days hot by default redacted or deleted according to workspace policy
Audit archives Cloud Storage compliance-driven immutable until retention expiry

14. Capacity Planning

14.1 Assumptions (Year 1)

Parameter Estimate
Active workspaces 500 at launch, 2,000 by month 12
Agent runs per workspace per day 15 average (operator: 10, workflow: 4, channel: 1)
Tokens per operator agent run ~4,000 input, ~800 output (MiniMax-class route)
Tokens per channel agent turn ~2,000 input, ~300 output (MiniMax-class route)
Tokens per workflow batch run ~80,000 input, ~15,000 output (mixed routed batch, 20 leads)
Knowledge chunks per workspace ~1,000 average, 300-dim embeddings
Concurrent active runs (peak) ~80 (4% of workspaces at peak hour)

14.2 Monthly LLM Cost Estimate (500 workspaces)

Workload Runs/month Tokens/run Route Class Cost/run Total
Operator agent 5,000 5K in / 1K out MiniMax primary route-dependent baseline target only
Workflow batch 2,000 80K in / 15K out MiniMax + low-cost batch route route-dependent baseline target only
Channel agent 500 2K in / 300 out MiniMax primary route-dependent baseline target only
Classification 7,500 500 in / 100 out OSS/free route route-dependent baseline target only
Total LLM cost budget target: $8–15/workspace/month

Planning note:

  • exact route costs must be recomputed from live OpenRouter pricing and actual chosen models at rollout time
  • RFC budgeting should optimize for outcome cost per successful task, not raw token price
  • launch target remains: stay within a blended AI compute budget of $8–15/workspace/month

14.3 Infrastructure Sizing

croohm-orchestrator (Cloud Run):

  • 1 vCPU, 2GB RAM per instance
  • Average run duration: 3.5 seconds (mostly waiting on model/provider API)
  • At 80 concurrent runs: 80 instances peak
  • Cloud Run auto-scales to 0 at off-peak → significant cost reduction vs always-on

Vector backend:

  • 500 workspaces × 1,000 chunks = 500,000 vectors at launch
  • 2,000 workspaces × 2,000 chunks = 4,000,000 vectors at month 12
  • managed shared vector backend should remain well below a dedicated-per-workspace design at month 12 scale

Redis (Memorystore):

  • Session lane locks: ~80 concurrent (tiny)
  • Rate limit counters: ~2,000 workspaces × 10 keys = 20,000 keys (tiny)
  • Context cache: ~500 active sessions × 4KB = 2MB (tiny)
  • Smallest Memorystore instance (1GB): more than sufficient

Firestore:

  • Agent runs: 500 workspaces × 450 runs/month = 225,000 documents/month
  • At 5KB/document: 1.1GB/month write — well within Firestore free tier for writes
  • Run steps: 10 steps/run × 225,000 runs = 2.25M step documents/month — ~$0.45/month at $0.18/100K writes

14.4 Total Infrastructure Cost Estimate (Month 12, 2,000 workspaces)

Component Monthly Cost
LLM API (OpenRouter routed mix) workload-dependent
Embedding API provider-dependent
Cloud Run (all services) ~$800
Vector backend provider-dependent
Firestore ~$150
Memorystore (Redis) ~$100
Cloud Storage ~$50
Pub/Sub + Cloud Tasks ~$50
Langfuse (Cloud Run + Cloud SQL) ~$150
Misc (Secret Manager, KMS, Logging) ~$100
Total to be re-estimated from selected routes before implementation freeze

Commercial model recommendation:

  • include a small AI allowance in higher plans for activation
  • add usage-based AI credits for heavier automation and bulk runs
  • enterprise BYOK customers can pay platform fee + lower AI margin, or pure platform fee when CroohM does not bear model cost

14.5 Pricing and Monetization Model

CroohM should not charge only on tokens. Users buy outcomes.

Recommended commercial structure:

  • Plan allowance: every qualifying workspace plan includes a monthly AI allowance for light operator use
  • AI credits: bulk automations, high-volume channel sends, and heavy workflow runs consume credits
  • Premium automation add-on: unlocks scheduled workflows, bulk runs, and advanced approvals
  • BYOK enterprise mode: workspace supplies model credentials; CroohM charges platform fee for orchestration, observability, approvals, connectors, and storage

Metering dimensions:

  • operator tasks completed
  • channel agent sessions handled
  • bulk workflow runs
  • external sends committed
  • premium research actions

Why this model:

  • token billing is too abstract for SMB customers
  • credits map better to user value and control spend better
  • BYOK customers still pay for CroohM's orchestration layer, not just raw model access

15. Observability, SLIs, SLOs & Alerting

15.1 SLI/SLO Definitions

SLI SLO Window Alert Threshold
Operator agent P95 response latency < 4,000ms 30-day rolling Alert if > 6,000ms for 5 min
Channel agent P95 response latency < 2,000ms 30-day rolling Alert if > 3,000ms for 2 min
Agent run success rate ≥ 98.5% 7-day rolling Alert if < 97% for 15 min
Approval gate delivery latency (FCM → mobile) < 3,000ms 30-day rolling Alert if > 5,000ms
Knowledge retrieval P95 latency < 300ms 30-day rolling Alert if > 500ms
API gateway availability ≥ 99.9% 30-day rolling Alert if < 99.5% for 5 min

Error budget: 1 - SLO. For 99.9% availability: 43.8 minutes/month error budget. Burn rate alerts at 2x and 5x burn rate.

15.2 Key Metrics

Business metrics (emitted by orchestrator):

croohm_agent_run_total{agent_type, status, workspace_id}
croohm_agent_run_duration_ms{agent_type, model, p50/p95/p99}
croohm_token_usage_total{model, type="input|output|cached", workspace_id}
croohm_tool_call_total{tool_name, status}
croohm_approval_request_total{status, action_type}
croohm_approval_resolution_time_ms{status}
croohm_handoff_total{from, to}
croohm_run_feedback_total{signal_type, label}
croohm_route_policy_success_rate{route_policy, use_case}

Infrastructure metrics (Cloud Monitoring):

run.googleapis.com/request_count{service, status}
run.googleapis.com/request_latencies{service, p95}
run.googleapis.com/container/instance_count{service}
firestore.googleapis.com/document/read_count
redis.googleapis.com/stats/memory/usage_ratio

15.3 Langfuse Dashboard (LLM-specific)

  • Token usage per workspace per day (cost breakdown)
  • P50/P95 latency per model per agent type
  • Cache hit rate per workspace
  • Tool call success/failure rate per tool
  • LLM-as-judge eval scores per agent type (task completion, faithfulness, hallucination rate)
  • Prompt version comparison (before/after prompt change)

15.4 Eval Suite (Automated)

Run nightly via Cloud Scheduler → Cloud Run Job:

Suite # Test Cases Eval Method Pass Threshold
Tenant isolation 50 Verify cross-workspace retrieval returns 0 results 100%
Approval gate enforcement 30 Verify external_send without approval = blocked 100%
Operator agent task completion 100 LLM-as-judge on pinned eval route ≥ 85%
Channel agent faithfulness 80 RAGAS faithfulness score ≥ 0.80
Session lane concurrency 20 Simulate concurrent runs on same leadId 100% no duplicates
Knowledge retrieval recall 60 Context recall score (RAGAS) ≥ 0.75
Prompt injection resistance 40 Adversarial inputs, verify refusal ≥ 95%
BYOK isolation 20 Verify workspace A's key not used for workspace B 100%
Route regression 40 Compare new route policy against previous production baseline no critical regression

Any suite falling below threshold triggers a Slack alert and blocks the next release.


16. Implementation Plan

Phase 1 — Foundation (Weeks 1–8)

Goal: Production-ready operator agent with read + draft tools and full run tracing.

Deliverables:

  • WorkspaceAgent, AgentRun, AgentRunStep, ApprovalRequest Firestore schemas
  • croohm-orchestrator service (TypeScript + LangGraph.js) — deploy to Cloud Run
  • OpenRouter integration with primary MiniMax route and route policy registry
  • Prompt caching on workspace config + platform policy prefix
  • Context Engine v1: CRM object fetch + workspace config assembly
  • Tool Runtime v1: read_leads, get_lead, search_leads, get_pipeline_summary (all read-only)
  • Tool Runtime v2: draft_whatsapp_message, draft_gmail_reply (draft-only, no sends)
  • Session lane manager (Redis distributed locks)
  • PreparedAction + idempotent commit path
  • Run trace emission to Langfuse
  • Feedback capture (RunFeedback) + failure bucket labeling
  • Approval gate infrastructure (Firestore + FCM push notification to mobile)
  • Approval UI in mobile app (list of pending approvals + approve/reject)
  • API endpoints: /agent/run, /agent/runs/{runId}, /approvals/{id}/approve, /approvals/{id}/reject
  • Phase 1 eval suite: tenant isolation + approval gate enforcement + operator task completion

Milestone gates:

  • M1.1 (Week 4): Operator can ask "Show me all hot leads with no reply in 48h" and get a correct list — with full run trace in Langfuse
  • M1.2 (Week 6): Operator can ask "Draft follow-up WhatsApp messages for all hot leads" — drafts returned, no sends
  • M1.3 (Week 8): Approval flow end-to-end: mobile push notification → review draft → approve/reject → run continues or aborts

Acceptance criteria for Phase 1:

  • Tenant isolation eval: 100% pass
  • Approval gate enforcement eval: 100% pass
  • Operator task completion rate: ≥ 75% on golden dataset
  • P95 response latency: < 5 seconds
  • Zero production incidents in 2-week soak

Phase 2 — WhatsApp + Gmail Execution (Weeks 9–16)

Goal: Agent can actually send messages with approval gates.

Deliverables:

  • update_lead_status write tool (with approval gate)
  • send_whatsapp_message external send tool (requires send_only approval)
  • WhatsApp template sync (approved templates for 24h window fallback)
  • 24-hour window enforcement logic in connector
  • Gmail OAuth per workspace, mailbox watch via Pub/Sub
  • Gmail thread → Conversation mapping
  • draft_gmail_reply, send_gmail tools (send requires approval)
  • send_whatsapp_template tool for out-of-window contacts
  • Bulk operator run: Planner → N parallel Executor sub-agents for "follow up all hot leads"
  • Phase 2 eval suite: WhatsApp send + Gmail send + 24h window logic + no-double-send concurrency

Milestone gates:

  • M2.1 (Week 12): Agent sends WhatsApp message to a real lead (with approval) — zero duplicates under concurrent test
  • M2.2 (Week 14): Agent replies to Gmail thread (with approval) — thread mapping correct
  • M2.3 (Week 16): Bulk follow-up run: 20 leads, 20 drafts, batch approval UI, 20 sends — all correct

Phase 3 — Knowledge + Web Chat (Weeks 17–24)

Goal: RAG-powered channel agent on web chat.

Deliverables:

  • Knowledge ingestion pipeline (Python worker): document chunking, embedding, vector write
  • Shared vector namespace model with strict tenant/workspace filtering
  • search_knowledge tool — retrieval with workspace filter
  • KnowledgeSource management APIs
  • Knowledge review workflow (source must be approved before being used in customer-facing agent)
  • Knowledge source state model: syncedapprovedlive on channel
  • Web chat channel deployment (WebSocket/SSE widget)
  • Channel agent persona and behavior configuration
  • Agent escalation + human handoff (set handoffState = "human" on lead/conversation)
  • Auto-close logic (inactivity timeout)
  • Context summarizer worker (sliding-window summary for long conversations)
  • CroohM MCP server (read + draft tools exposed via MCP)
  • Phase 3 eval suite: knowledge retrieval recall/faithfulness + handoff quality + unsupported question refusal

Milestone gates:

  • M3.1 (Week 20): Web chat agent answers 10 test questions from workspace knowledge base — faithfulness ≥ 0.80
  • M3.2 (Week 22): Agent correctly escalates when confidence is low — handoff state transitions correctly
  • M3.3 (Week 24): CroohM MCP server operational — an MCP-compatible client can run list_leads and draft_whatsapp_message

Phase 4 — Workflow Engine + WhatsApp Channel Agent (Weeks 25–32)

Goal: Event-driven and scheduled automations; WhatsApp channel agent.

Deliverables:

  • WorkflowDefinition schema + workflow authoring API
  • Product-defined workflow templates (V1: no-code authoring)
    • "Follow up leads with no reply after N days"
    • "Daily pipeline digest for workspace owner"
    • "Qualify new inbound leads from WhatsApp"
    • "Route hot leads to owner and notify by WhatsApp"
  • Workflow trigger: event-based (Pub/Sub) + scheduled (Cloud Scheduler)
  • WhatsApp channel agent deployment (workspace phone number → agent)
  • WhatsApp inbound → conversation → agent response → send (with approval or auto, per policy)
  • Sub-agent bounded orchestration for workflow execution
  • Role-based agent packs (owner, sales rep, CSM — different tool allowlists)
  • Phase 4 eval suite: workflow execution correctness + WhatsApp agent quality

Phase 5 — Enterprise + BYOK (Weeks 33–40)

Goal: Enterprise readiness, BYOK, provider failover, advanced evals.

Deliverables:

  • BYOK credential profile management (workspace provides OpenRouter, OpenAI, or Vertex credentials as allowed)
  • Credential health monitoring + cooldown state
  • Provider failover: if primary credential is degraded, failover to platform credential (if workspace permits) or queue run for retry
  • Enterprise vector isolation mode (dedicated index namespace or self-hosted deployment)
  • Per-tenant KMS envelope encryption
  • Advanced eval loop: automatic regression detection, model upgrade A/B testing
  • Langfuse-based eval experiment comparison (before vs after model change)
  • Perplexity Sonar integration (research tool within operator agent)

17. Rollout Strategy

17.1 Phase 1 Rollout

  • Dark launch (Week 7–8): Deploy orchestrator to production but disable all write and send tools. Run operator agent in read+draft mode with internal team workspaces only.
  • Dogfood (Week 8): CroohM team's own workspace uses the agent daily for pipeline review and draft generation. Collect run traces, measure latency, identify prompt quality gaps.
  • Alpha (Week 9): 5 friendly customer workspaces enabled. 2-week soak. Monitor: task completion rate, latency, approval request volume, error rate.
  • Beta (Week 11): 50 workspaces. Feature flag rollout via workspace plan tier.
  • GA (Week 13): All workspaces on AI-enabled plan tiers.

17.2 Feature Flag Model

All agent features controlled by WorkspaceFeatureFlags:

ai_operator_agent: boolean
ai_channel_agent_webchat: boolean
ai_channel_agent_whatsapp: boolean
ai_gmail_integration: boolean
ai_workflow_engine: boolean
ai_byok: boolean
ai_bulk_runs: boolean

Flags set per workspace by CroohM admin — enables progressive rollout and instant kill switch per feature per workspace.

17.3 Rollback Plan

  • Orchestrator: Cloud Run traffic split — 100% old revision in < 30 seconds
  • Workflow engine: Cloud Scheduler job pause — stops all scheduled runs immediately
  • Agent kill switch: set all WorkspaceAgent.status = "paused" via admin API — stops all agent runs within seconds
  • Langfuse traces are the rollback evidence — all decisions are auditable

18. Alternatives Considered

A. User-Scoped Agent Brains (Rejected)

Each user gets their own private AI brain with personal memory and context.

Rejected because:

  • Breaks shared inbox — two reps get different contexts on the same customer
  • Duplicates CRM and conversation context per user
  • Complicates approval and handoff flows
  • Channel agents must be workspace-deterministic — a WhatsApp number can't have 5 different AI personas

B. Per-Tenant Physical Vector Database (Rejected for V1)

One physical vector deployment per customer workspace.

Rejected because:

  • At 500 workspaces: 500 clusters to provision, monitor, and scale
  • Cost is prohibitive — minimum instance per cluster × 500
  • Operational complexity scales linearly with customer count
  • shared vector infrastructure with strict host-side filtering provides sufficient V1 isolation without per-cluster overhead
  • Revisit at 5,000+ workspaces or for enterprise compliance requirements

C. Python for All Services (Rejected)

Single-language stack for simplicity.

Rejected because:

  • GIL limits concurrency in orchestration layer at scale
  • Cold start times and memory footprint make Python uncompetitive for the API gateway
  • Cost at 100+ Cloud Run instances is meaningfully higher than Go for the gateway role
  • Python is still the right choice for the embedding and eval workers where ML ecosystem matters

D. Temporal Instead of LangGraph for All Orchestration (Deferred to V2)

Temporal provides durable execution with its own server cluster.

Deferred because:

  • Adds a Temporal cluster to operate (or Temporal Cloud cost: ~$200-500/month)
  • LangGraph's Firestore-backed checkpointing is sufficient for V1 workflow durations (< 30 minutes)
  • Temporal is the right upgrade path when workflows regularly exceed 30 minutes or need cross-datacenter durability
  • Decision: re-evaluate at Phase 4 when workflow engine is built

E. Hardcoding a Single Model Provider as Primary (Rejected)

Bind the RFC to one vendor-specific orchestration path from day 1.

Rejected because:

  • CroohM wants to start with MiniMax and open-model experimentation, which requires routing flexibility
  • pricing, latency, and quality are moving too quickly to lock the platform to one provider assumption
  • provider abstraction is part of the commercial model because BYOK and enterprise routing are product requirements
  • OpenRouter-first keeps the runtime adaptable while preserving one operational API surface

F. No Approval Gates, Auto-Execute Everything (Rejected)

Simplify UX by executing all tools automatically without approval.

Rejected because:

  • Irreversible external sends (WhatsApp, Gmail) require human review — this is a hard business requirement
  • Approval gates are the primary trust mechanism for AI adoption among SMB users
  • Without approval gates, a single bad agent run can send hundreds of incorrect messages
  • The right model: approval gates on external_send and write, not on read and draft

19. Risks & Mitigations

Risk Likelihood Impact Mitigation
Prompt injection via customer message Medium High Input guardrails + delimiter-based separation in system prompt + adversarial eval suite
Cross-workspace retrieval leak Low Critical Mandatory tenant/workspace retrieval filter + Firestore security rules + isolation eval suite (100% pass gate)
Duplicate WhatsApp sends (session lane failure) Low High Redis distributed locks + idempotency keys on send tool + no-double-send eval suite
LLM cost overrun from runaway loops Medium Medium Max tool call limit per run (configurable, default 20) + token budget per run + per-workspace monthly credit cap
Primary model route latency spikes blocking channel agent Medium High P95 < 2s SLO + Langfuse alerting + route fallback policy + error message to customer with retry
WhatsApp business API violations Low Critical 24h window enforcement in connector + approved template fallback + meta compliance audit
Knowledge base contamination (approved bad content) Low High Review workflow before source goes live + faithfulness eval + human review gate for customer-safe sources
Over-building orchestration before core tools are reliable High Medium Phase 1 acceptance criteria gates — must pass eval suite before Phase 2 begins
BYOK key misuse (workspace A's key used for workspace B) Very Low Critical CredentialProfile scoped strictly to workspaceId + BYOK isolation eval suite (100% pass gate)
Approval fatigue leading to blind approvals Medium Medium Batch approval UI (review multiple at once) + intelligent grouping + approval analytics dashboard

20. Open Questions

  1. Enterprise vector isolation: Should enterprise customers get a dedicated vector deployment or dedicated namespace isolation as a paid add-on from day 1 (Phase 5), or wait until demand is demonstrated by actual customer requests?

  2. Web chat vs WhatsApp channel agent launch order: Web chat is technically simpler (no WhatsApp 24h window complexity). WhatsApp is higher business value for CroohM's customer base. Should Phase 3 prioritize web chat (faster to ship) or WhatsApp channel agent (higher customer impact)?

  3. Approval UX: Single-approval (one tap per draft) vs batch-approval (approve all drafts in one swipe) as the default. Single is safer; batch is necessary for bulk workflows. What is the right default per operation type?

  4. Workflow authoring scope for V1: Product-defined templates only (fastest to build), or a simple condition-based no-code editor (higher flexibility)? Templates are lower risk but create a support burden when customers want customization.

  5. Perplexity Sonar integration scope: Integrate as an optional research tool in operator agent from Phase 2, or defer to Phase 5? The integration is 1–2 days of work given the provider abstraction, but adds an external API dependency and cost.

  6. MCP server auth model: OAuth 2.0 scoped to workspace (correct but adds auth complexity) vs API key per workspace (simpler but less secure). What is the right initial model for the developer audience?


21. Decision Log

Date Decision Rationale Owner
2026-03-18 OpenRouter as provider control plane Enables MiniMax-first routing, OSS experimentation, and BYOK/provider flexibility behind one API surface Engineering Lead
2026-03-18 TypeScript for orchestration LangGraph.js ecosystem and strong provider-routing SDK support; same language as web frontend Engineering Lead
2026-03-18 Go for API gateway Concurrency model, low memory footprint, fast cold start Engineering Lead
2026-03-18 LangGraph.js over OpenAI Agents SDK Graph model required for parallel fan-out, conditional branching, long-running approval pauses Engineering Lead
2026-03-18 Shared vector infrastructure with strict host-side filtering Lower operational cost while preserving required tenant/workspace isolation semantics Engineering Lead
2026-03-18 Langfuse self-hosted Open source, data residency on GCP, full LLM tracing + eval integration Engineering Lead
2026-03-18 Temporal deferred to V2 LangGraph Firestore checkpointing sufficient for V1 workflow durations Engineering Lead
2026-03-18 Workspace-first operating model Channels are workspace assets; team consistency requires workspace-level AI behavior Product Lead
2026-03-18 Approval gates on external_send and write Trust mechanism for AI adoption; irreversible actions require human review Product Lead

22. References

Model Routing and Providers

Perplexity

Moltbot

Frameworks

Infrastructure

Channels

Competitive Reference Products

Market Context

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment