ADR-0184: Navin Customer Operations Agent, one common engine and three sector packs on top of the Control Plane
- Status: accepted on 2026-11-04; three points settled by the user the same day (see "Decision on the points to validate")
- Date: 2026-11-04
- Scope: new project
navin-customer-operations/(FastAPI backend, workers, screens in the shared sector-agent frontend (ADR-0180), Navin integration, docs), additive Control Plane domainservices/control-plane/src/eai/domains/customer_ops/(lifecycle), migrationsV220toV229, additive OpenFGA types (deploy/policies/openfga/model.fga), OPA packageeai.customer_ops(deploy/policies/opa/customer_ops.rego), activation screens of the Enterprise portal, service template prepared but not published - Related documents: ADR-0101 (licence policy), ADR-0103 (vLLM and LiteLLM), ADR-0108 (Opik), ADR-0166 (ClamAV and
YARA-X scanning), ADR-0173 (Asterisk, Kamailio, LiveKit telephony), ADR-0174 (Mem0 and Cognee memory), ADR-0175 (RAG
Agent, reference model), audit
navin-customer-operations/docs/NAVIN_INTEGRATION_AUDIT.md
Context
The customer asks for a customer operations agent for banking, insurance and retail: multichannel intake, customer identification, understanding and routing of requests, cases and SLA, workflows, document search, controlled memory, lookups in business systems, authorized actions, handoff to an advisor, console and copilot, dashboards and quality.
The audit of 2026-11-04 shows that Navin already provides the agent runtime (runs, subagents, approvals, resume), the
model gateway in front of LiteLLM, knowledge bases (V206, V207), memory through the Navin Memory Provider contract with
Cognee, file scanning, SeaweedFS storage, Presidio, evaluation (Ragas, Promptfoo), the channels domain (inbound
only), a generic connectors domain with the Connector Broker and deduplicated webhooks, the telephony platform and,
in the RAG Agent, a complete product layer (BFF, SSE with resume, citations, lifecycle, unpublished template). Missing
are external customer identity, outbound sending on channels, every vendor connector (Shopify, Salesforce, carriers,
payment: absent from the Control Plane), a generic realtime layer for a console and a business workflow engine.
The detailed specification cited by the tasks (numbered sections) is not available in the repository: on 2026-11-04
the user chose to continue with the board task descriptions. The lists (events, tool contract, policy decisions,
scenarios) are therefore defined by this ADR and by the v1 contracts, and can be realigned on the specification
when it is provided.
Decision
1. A product layer on the Control Plane, as in ADR-0175
| Who | Does what |
|---|---|
| Navin Manager | installs and runs the product runtime (API, workers, web), its dependencies, TLS, health, backups, upgrades |
| Control Plane | tenants, projects, roles, models, inbound channels, knowledge bases, memory, file scanning, storage, connectors and secrets, quotas, audit, policies, traces, instance lifecycle |
| Product backend | conversations, customer context, intents and routing, cases, SLA, workflows, handoffs, console, actions, packs; it calls the Control Plane only through the Python SDK enterprise_ai |
The backend never calls Qdrant, Cognee, LiteLLM, Docling, ClamAV, YARA-X or Presidio directly: it goes through the Control Plane domains.
2. One common engine and three packs, not three applications
A single product carries the engine (conversations, cases, SLA, workflows, tools, handoff, console). Sectors are
versioned packs validated by schema (contracts/v1): intents, connectors, workflows, policies, case types, forms,
response templates, escalation rules, indicators and default SLA. Three packs are delivered: Banking, Insurance,
Retail. No common deadline is imposed on the three sectors.
3. Reuse
- From the RAG Agent: project layout, authentication, authorization, ephemeral Redis, durable jobs, SSE, Markdown rendering, citations, interface shell, lifecycle in the Control Plane, unpublished template. The code is taken into the new project and adapted; no cross import between products.
- From the Compliance & Audit Agent: developed in parallel, nothing is taken in this version; a possible sharing happens after the merge, through a separate decision.
- The Guidia ecosystem is not reused (user choice of 2026-11-04).
4. External customer identity
- End customers get no Keycloak account. Their identity comes from one of the sources configured per instance: the customer OIDC provider (token checked on its JWKS, expected issuer and audience), a federation (same check), a session of the existing customer portal (signed assertion), or step-up authentication delegated to the business system (the source system confirms and the product only sees the result).
- The result is a customer authentication context bound to the conversation: verified identity, access scope (opaque references), assurance level, source, expiry.
- Levels: 0 public (general information), 1 identified (declared identity verified by a link or a channel), 2 authenticated (OIDC token or session verified), 3 controlled action (recent delegated step-up authentication). Each action declares its minimum level; step-up goes through a secure journey outside the chat.
- The chat never asks for a password, a PIN or an authentication code; such a code written by a customer is masked before storage and never sent to the model.
- Internal users (advisors, supervisors, administrators) go through Keycloak as in the RAG.
5. Channels
- Inbound through the
channelsdomain of the Control Plane (email, WhatsApp, web, API) when configured; web chat, embeddable widget, customer portal and console in the product. - Channel webhooks carry an HMAC signature with a 5 minute window; the product adds deduplication by delivery
identifier, absent from the
channelsdomain. - Outbound sending (user choice): product adapters (SMTP, WhatsApp Cloud API) through the egress guard, secrets in OpenBao; a channel without settings is reported "not configured", never simulated.
- Optional telephony on the existing platform (ADR-0173), no new PBX.
- Each channel has a sensitivity ceiling: no banking or insurance data on a channel whose level does not allow it.
6. Business connectors
- Only the
connectorsdomain of the Control Plane and adapters following the Navin connector contract (Connectormanifest, Connector Broker, egress guard, OpenBao secrets). - Read only by default; writing only with permission, policy decision and approval. No SQL query generated by a model.
- No copy of the CRM, core banking, policies or orders: the product schema keeps only references and operational data; business systems stay the owners of their data.
- A connector is declared operational only after a real test or on a local test server that follows the published API; its status is documented.
7. Product data
customer_opsschema through Alembic in a dedicated database, async SQLAlchemy 2, asyncpg; forced RLS on every tenant table, context set bySET LOCALin each transaction; indexes by tenant and project.- Durable jobs in PostgreSQL (
FOR UPDATE SKIP LOCKED) with signed identity, outbox; Redis only for ephemeral data (cache, rate, locks, idempotency, streaming coordination).
8. Workflows and rules
- No competing orchestrator: product workflows are persisted state machines run by the durable jobs, with the runs, approvals and resumes of the Navin runtime.
- Deterministic eligibility rules (code or source system): a model can neither change nor bypass them; it proposes, the engine decides.
9. Models, execution and subagents
- Logical agents are agents of the Navin registry run by its runtime; no privilege gain through delegation; a simple request is handled with a single model call.
- Every model call goes through the
/v1/gateway/*gateway in front of LiteLLM; allowed models read from Navin; Navin budgets and quotas.
10. Memory
- Navin Memory Provider contract, Cognee per the validated RAG trial (
navin-enterprise-rag/docs/COGNEE_TRIAL.md: pgvector vectors, embedded LadybugDB graph, proven isolation); sensitive identifiers, secrets, codes and payment data never stored; graphs never replace the business truth.
11. Security and authorization
- OpenFGA (additive types for the instance, conversation, case, customer reference, tool, document, team, queue,
export and metrics) and OPA (
eai.customer_ops) fail-closed: refusal when an engine does not answer; 404 for a resource of another tenant. - Presidio through the
privacydomain, ClamAV and YARA-X scanning of every attachment, document and tool result content treated as untrusted data.
12. Observability
Compliant with ADR-0101: OpenTelemetry to the Navin collector, AI traces in Opik through the Control Plane without the content of accounts, contracts, claims or payments, Prometheus metrics without high cardinality labels, logs to Alloy and OpenSearch, alerts through Alertmanager, technical traces in Jaeger, analytics in ClickHouse. Grafana, Loki and Tempo are refused (AGPL-3.0).
13. Activation and lifecycle
On the rag_agent model: customer_ops domain of the Control Plane, traced states and steps, Ready only after the
health checks and the smoke test, idempotent transitions, deletion limited to owned resources. Activation journey in
the Enterprise portal. Template prepared per the real Manager schema and never published without the explicit
validation of the user.
14. Truth of capabilities
No function is declared done without a real test; no capacity, SLA or HA is announced without measurement. Limits are
written in navin-customer-operations/docs/KNOWN_LIMITATIONS.md.
Consequences
- A single engine to maintain for three sectors; one more sector is a pack, not an application.
- Vendor connectors remain to be written and tested one by one: nothing is announced without a test.
- Two migration tools in the repository (Alembic for
customer_ops,V*.sqlfor the Control Plane), as for the RAG. - The code taken from the RAG is duplicated until a common library is decided.
Points to validate by the customer
- Outbound sending on the email and WhatsApp channels, absent from the
channelsdomain. - Guidia ecosystem, not found in the repository.
- Detailed specification, not found in the repository.
- Dedicated installation per instance for banks while the Cognee separation is only logical (taken from ADR-0175).
- Replacement of Grafana, Loki and Tempo by the allowed components (taken from ADR-0175).
Decision on the points to validate
On 2026-11-04 the user decided:
- Outbound sending through product adapters (SMTP, WhatsApp Cloud API) through the egress guard and OpenBao, channel
reported "not configured" without settings; the shared
channelsdomain is not changed. - Guidia is not reused for this product.
- The lists are defined from the board task descriptions; the gap with the specification is noted here and can be realigned.
Points 4 and 5 take the decisions already accepted in ADR-0175.
Rejected alternatives
- Three sector applications: triple maintenance and diverging governance.
- Keycloak accounts imposed on end customers: contrary to the identity the customer already holds.
- Copy of the CRM or core banking in the product: double truth and sensitive data outside the source systems.
- External workflow engine competing with the Navin runtime.
- Immediate extension of the shared
channelsdomain for outbound sending: rejected by the user to avoid conflicts with the other products developed in parallel. - Direct calls to LiteLLM or to the engines (Qdrant, Cognee, Presidio).
Delivery plan
Forty-five "CO" steps tracked on the project board: audit and architecture (P1), foundations (P2), conversations and channels (P3), requests, cases, SLA and workflows (P4), knowledge and memory (P5), connectors, customer data, actions and agents (P6), packs, handoff and console (P10), screens (P11), security, observability and quality (P12), lifecycle and activation (P13), final validation (P14).