Skip to content

Building a Vertical on Purple8 ​

Purple8 is delivered as a platform and a set of vertical products built on it. The platform is Purple8 Graph and Purple8 DocIntel. A vertical is configuration and a front-end. This page defines what a vertical consists of, what it must not contain, and the order in which to build one.

Platform and verticals ​

  Vertical products      AML Platform   Customer Onboarding   Supplier Risk   …
  (thin: config + UI)         │                 │                  │
                              └────────────┬────┴──────────────────┘
                                           │  REST API · MCP
  Platform                 Purple8 Graph              Purple8 DocIntel
  (all logic lives here)   graph · vector · full-text · Journey Engine · RBAC
                           audit · encryption · replication · algorithms · egress
                                           │
  Delivery                 Self-Hosted · Customer VPC · Managed Service
                           (identical for every vertical)

A vertical inherits, without additional work: authentication and RBAC, encryption at rest, audit trail, replication and failover, backup, multi-tenancy, observability, MCP access for AI agents, and all four deployment models.

Definition of a vertical ​

A vertical consists of exactly six artifacts.

#ArtifactLives inMechanism
1SchemaPurple8 GraphNode types, edge types, property constraints registered via /schema or schema.* MCP tools
2Journey templatesPurple8 GraphJourneyDefinition specs: stages, SLA policies, HITL gates, AI-assist hooks. Loaded via journey.define or journey_templates.py
3Extraction profilePurple8 DocIntelExtractionProfile with domain ontology (entity and relationship types), chunking strategy, confidence threshold, GLiNER or LLM backend
4Detection configurationPurple8 GraphWhich built-in algorithms run, on which labels and edge types, with which thresholds. Optionally an evolutionary tuning objective
5Domain vocabularyFront-endLabels, edge types, prompt framing, display text, role descriptions. One typed configuration object per tenant or market
6Front-endStatic SPAReact application calling the Purple8 Graph REST API and MCP endpoint directly. No intermediate server

Anything not in this list belongs in the platform, not the vertical.

What a vertical must not contain ​

ProhibitedReasonWhere it belongs
A backend service or API layerBreaks the single-process delivery model; adds an operational component to every deploymentPurple8 Graph router or MCP tool
A database, cache or queuePurple8 Graph is the storePurple8 Graph
Custom authentication or authorizationSecurity controls must be uniform across productsPurple8 Graph RBAC, OIDC, SAML
Graph algorithmsAlgorithms are domain-neutral and must be tested oncecore/algorithms.py
Document parsing or extraction codeDocIntel owns the parse-chunk-extract pipelineDocIntel parser or profile
Direct storage accessBypasses audit, encryption and tenancyREST or MCP

If a vertical needs a capability the platform lacks, add it to the platform. Every other vertical then receives it.

Build order ​

1. Schema ​

Define the node and edge types for the domain. Use the platform's schema registry so that validation, the LCNC graph browser and DocIntel emit all agree.

json
POST /schema/node-types
{
  "type_name": "Account",
  "data_classification": "confidential",
  "properties": {
    "account_id": { "type": "str", "required": true },
    "opened_at":  { "type": "str" },
    "risk_tier":  { "type": "str", "enum": ["low", "medium", "high"] }
  },
  "immutable_properties": ["account_id"]
}

POST /schema/edge-types
{
  "type_name": "TRANSFERRED_TO",
  "source_node_types": ["Account"],
  "target_node_types": ["Account"],
  "properties": {
    "amount":   { "type": "float", "required": true },
    "currency": { "type": "str",   "required": true },
    "ts":       { "type": "str",   "required": true }
  }
}

AI agents perform the same step with schema.define_node_type and schema.define_edge_type.

2. Journey templates ​

Model the lifecycle the vertical manages. Each stage carries an SLA policy and, where a human decision is required, a HITL gate.

python
TEMPLATE = {
    "journey_type": "aml_case",
    "description": "AML investigation: triage → investigation → review → filed.",
    "stages": [
        {"name": "triage",        "owner_system": "alerting",
         "sla_warn_seconds": 7_200,  "sla_breach_seconds": 14_400},
        {"name": "investigation", "owner_system": "investigations_team",
         "sla_warn_seconds": 86_400, "sla_breach_seconds": 259_200,
         "ai_step": {"trigger": "on_enter", "auto_execute": False,
                     "system_prompt": "Summarise the evidence graph for this case."}},
        {"name": "review",        "owner_system": "compliance_officer",
         "sla_warn_seconds": 43_200, "sla_breach_seconds": 86_400,
         "hitl": {"required": True, "assigned_role": "admin",
                  "title": "Approve SAR filing", "expires_in_seconds": 86_400}},
        {"name": "filed",         "owner_system": "regulatory_reporting", "terminal": True},
    ],
}

The spec shape matches TEMPLATE_SPECS in journey_templates.py. Load with journey.define (MCP) or a load_*() function following the same module. Every transition, SLA breach and HITL decision is written to the graph as an immutable edge; the vertical writes no audit code.

3. Extraction profile ​

Create extraction/profiles/<domain>.py in Purple8 DocIntel. The ontology's entity and relationship types must match the schema from step 1 so that emitted entities land on the correct node types.

python
PROFILE = ExtractionProfile(
    name="aml",
    entity_backend="gliner",
    gliner_model="urchade/gliner_medium-v2.1",
    confidence_threshold=0.55,
    chunking=ChunkingStrategy(mode="table_aware", size=1200, overlap=150),
    ontology=ExtractionOntology(
        entity_types=["Person", "Account", "Company", "Transaction", "Amount", "Date", "Jurisdiction"],
        relationship_types=["OWNS", "TRANSFERRED_TO", "CONTROLS", "LOCATED_IN"],
        two_pass=True,
    ),
)

Register in extraction/router.py. Documents processed with profile_hint=aml are emitted to Purple8 Graph with deterministic entity IDs, so the same real-world entity always resolves to the same node.

4. Detection configuration ​

Select platform algorithms and bind them to the domain's labels and edge types. No new algorithm code.

DetectionPlatform primitiveVertical supplies
Ring or mule networkdetect_communitiesEdge types that carry value; minimum density
Hub or facilitatorbetweenness_centrality, pagerankLabels to rank; top-k
Sanctions or PEP exposureshortest_pathTarget label; maximum hops
StructuringQuery DSL over transaction edgesThreshold amount; window
Threshold tuningEvolutionary optimisation (core/evolution.py)Objective: precision, recall, alert capacity

Store configuration as graph nodes or in the tenant's settings so it is versioned, audited and per-tenant.

5. Domain vocabulary ​

One typed configuration object per tenant or market. The AML platform's tenantConfig.ts is the reference:

ts
export interface TenantConfig {
  displayName: string;
  pivotLabels: Set<string>;          // shared-infrastructure node types
  entityLabels: Set<string>;         // match targets
  ownershipEdgeTypes: string[];
  transactionEdgeTypes: string[];
  analystRole: string;               // injected into LLM prompts
  typologyQuestion: (entity: string) => string;
}

All API and algorithm calls are identical across tenants. Only labels, edge types, prompt framing and display text differ. This is what makes the One-to-Many and Many-to-One topologies configuration rather than code.

6. Front-end ​

A static React application. It calls Purple8 Graph directly.

ConcernImplementation
AuthenticationOIDC redirect to the customer IdP, or Purple8 JWT login; token in Authorization: Bearer
DataGET /nodes, POST /graph/traverse, POST /algorithms/*, POST /rag/hybrid-query
Workflowjourney.* endpoints for case status, advancement, HITL queue
AI assistancePOST /mcp (SSE) for streamed, evidence-cited explanations
ConfigurationBuild-time VITE_API_BASE_URL; runtime TenantConfig
HostingS3 + CloudFront, or any static host. See AWS Deployment Patterns

There is no server-side rendering, session store or API gateway in the vertical.

Acceptance criteria ​

A vertical is complete when all of the following hold.

  • [ ] Schema registered; schema.validate passes on seeded data.
  • [ ] Journey template loads; an instance can be started, advanced through every stage, blocked at each HITL gate, and audited via journey.audit.
  • [ ] Extraction profile registered; a representative document set emits entities whose types all exist in the schema.
  • [ ] Detection configuration produces expected results on the seeded data set; thresholds are stored per tenant, not hard-coded.
  • [ ] Front-end runs against an unmodified Purple8 Graph instance with only VITE_API_BASE_URL and a TenantConfig changed.
  • [ ] Repository contains no server code, no database client, no authentication logic.
  • [ ] Deploys unchanged on the reference AWS stack.

Reference: Purple8 AML Platform ​

ArtifactLocation
Schema and seed datagenerate_demo_data.py, ingest_ibm_aml.py
Journey templatescompliance_review (platform), AML case template (vertical)
Extraction profilePurple8-DocIntel/extraction/profiles/financial.py
Detection configurationTypologyManager.tsx, dimensional_ablation_aml.py
Domain vocabularysrc/tenantConfig.ts (banking, asset_mgmt, prime_brokerage)
Front-endsrc/App.tsx, AmlGraph.tsx, ClaudePanel.tsx, api.ts

Three tenant vocabularies share one code base and one platform instance. Adding a fourth is a TenantConfig entry.

Reference: Hybrid Human–Agent Orchestration ​

A vertical in which AI agents and humans work the same cases, in the same state machine, with the same audit trail. No orchestration framework is added; the Journey Engine is the orchestrator and the graph is the shared state.

Why this is native rather than integrated ​

Orchestration concernConventional stackPurple8
Shared state between agentsMessage bus + state storeThe graph. Agents read and write nodes and edges; every write is visible to every other agent and every human on the next read.
Workflow definitionSeparate DAG or graph DSLJourneyDefinition. One definition serves humans and agents.
Agent stepFramework node with tool bindingsAIStepConfig on a stage: trigger (on_enter, on_sla_warn, on_sla_breach, manual), auto_execute, allowed_actions, system_prompt.
Human stepCustom approval servicehitl on a stage: required, assigned_role, title, expires_in_seconds. Surfaced via journey.list_hitl; cleared via journey.resolve_hitl.
Hand-off agent → humanCallback or webhookAgent returns suggest_advance, flag or hold. Instance waits at the HITL gate.
Hand-off human → agentTrigger callHuman resolves the HITL task; the next stage's on_enter AI step fires.
Wake-up on changePolling or pub/sub infrastructuregraph.wait_for_changes (long-poll) or graph.poll_changes (cursor).
Scheduled workCron servicescheduler.add_trigger.
Tool access for agentsPer-agent tool wiringMCP server, 125 MCP tools across 16 namespaces, RBAC per tool. External tools via registry.register_tool and registry.register_mcp_server.
GuardrailsMiddlewareguardrails.evaluate before any agent-proposed action is applied.
Tracing and auditSeparate tracing serviceEvery transition, AI recommendation, HITL decision and SLA event is an immutable graph edge. journey.audit returns the full trail.
LearningFine-tuning or prompt storefeedback.open / feedback.record / feedback.resolve; memory.history / memory.search.

Agents and humans are peers. Both are principals with roles; both act through the same API; both leave the same audit records.

Roles in the state machine ​

PrincipalRoleActs viaAllowed actions
Triage agenteditor (API key)MCP journey.*, graph.*, rag.*annotate, suggest_advance, flag
Research agenteditor (API key)MCP rag.hybrid_query, graph.traverse, data.ingest_*annotate
Supervisor agenteditor (API key)MCP journey.sla_alerts, journey.advanceforce_advance where auto_execute: true, hold
Case officereditor (OIDC)Front-endAdvance, annotate, resolve HITL tasks assigned to their role
Approveradmin (OIDC)Front-end or LCNCResolve admin HITL gates

Which AIActionType values an agent may return is set per stage in allowed_actions. force_advance requires auto_execute: true on that stage; every other action leaves the decision with a human.

The six artifacts ​

#ArtifactContent for this vertical
1SchemaCase, Evidence, Recommendation, Decision node types; SUPPORTS, CONTRADICTS, RECOMMENDED_BY, DECIDED_BY edge types. Recommendation and Decision carry principal_id and principal_type (agent or human).
2Journey templateBelow.
3Extraction profileDomain profile for incoming evidence documents.
4Detection configurationNot applicable, or the domain's own (e.g. AML detections if this orchestration wraps AML).
5Domain vocabularyStage names, role names, agent system prompts per tenant.
6Front-endCase board showing current stage, pending HITL tasks for the signed-in role, agent recommendations with evidence links, full audit timeline.

Journey template ​

python
TEMPLATE = {
    "journey_type": "hybrid_case",
    "description": "Agents triage and research; humans decide; supervisor agent enforces SLA.",
    "stages": [
        {"name": "received", "owner_system": "intake",
         "sla_warn_seconds": 900, "sla_breach_seconds": 3_600,
         "ai_step": {"trigger": "on_enter", "auto_execute": True,
                     "allowed_actions": ["force_advance", "flag"],
                     "system_prompt": "Classify the case. Advance to 'research' if in scope; flag if not."}},

        {"name": "research", "owner_system": "research_agent",
         "sla_warn_seconds": 7_200, "sla_breach_seconds": 14_400,
         "ai_step": {"trigger": "on_enter", "auto_execute": False,
                     "allowed_actions": ["annotate", "suggest_advance"],
                     "system_prompt": "Gather evidence via rag.hybrid_query and graph.traverse. "
                                      "Write Evidence nodes. Recommend a decision with citations."}},

        {"name": "decision", "owner_system": "case_officer",
         "sla_warn_seconds": 43_200, "sla_breach_seconds": 86_400,
         "hitl": {"required": True, "assigned_role": "editor",
                  "title": "Review agent recommendation and decide", "expires_in_seconds": 86_400},
         "ai_step": {"trigger": "on_sla_warn", "auto_execute": False,
                     "allowed_actions": ["annotate"],
                     "system_prompt": "Summarise what is blocking the decision."}},

        {"name": "approval", "owner_system": "approver",
         "sla_warn_seconds": 43_200, "sla_breach_seconds": 86_400,
         "hitl": {"required": True, "assigned_role": "admin",
                  "title": "Approve decision", "expires_in_seconds": 86_400}},

        {"name": "closed", "owner_system": "records", "terminal": True},
    ],
}

Execution sequence ​

 Intake (webhook / data.ingest_file)
   │  journey.start
   ▼
 received ──on_enter──► Triage agent ──force_advance──► research
                                     └─flag──────────► held for human
   │
 research ──on_enter──► Research agent
   │                       rag.hybrid_query · graph.traverse · graph.add_node(Evidence)
   │                       suggest_advance("decision") + annotate(citations)
   ▼
 decision  [HITL: editor]  Case officer reads recommendation + evidence, decides
   │            └─on_sla_warn──► Supervisor agent annotates blocker; journey.sla_alerts raised
   │  journey.resolve_hitl
   ▼
 approval  [HITL: admin]   Approver confirms
   │  journey.resolve_hitl
   ▼
 closed

Every arrow is an ADVANCED_TO, SLA_BREACHED or HITL edge in the graph. journey.audit returns the sequence with principal, timestamp, action and evidence references.

Agent runtime ​

Agents are external processes holding an API key. A minimal loop:

  1. graph.wait_for_changes filtered to JourneyInstance nodes entering the agent's stage, or scheduler.add_trigger for periodic sweeps.
  2. journey.status to load the instance; graph.traverse and rag.hybrid_query to gather context.
  3. guardrails.evaluate on the proposed action.
  4. journey.advance (only where auto_execute permits) or write a Recommendation node and annotate.
  5. feedback.record when a human later overrides the recommendation.

Any MCP-capable agent runtime (Claude, Copilot, a custom loop) can play any agent role. Purple8 does not prescribe the runtime.

Acceptance additions ​

  • [ ] An agent-initiated force_advance is rejected on stages where auto_execute is false.
  • [ ] A HITL gate cannot be passed by an agent principal.
  • [ ] journey.audit distinguishes agent and human principals for every transition.
  • [ ] Overriding an agent recommendation records a feedback entry linked to the instance.

Pattern catalogue ​

Use cases published on purple8.ai and in Use Cases, expressed as the six artifacts. Each row is a vertical; none requires platform code.

VerticalSchema (key types)JourneyExtraction profileDetection / analyticsVocabulary axis
AML / financial crimePerson, Account, Transaction, Companyaml_casefinancialcommunities, centrality, shortest path, evolutionary tuningbanking / asset management / prime brokerage
Customer onboardingCustomer, Document, Check, Productcustomer_onboardinggeneral, contractduplicate detection (vector), link predictionretail / commercial / wealth
Supplier and vendor riskSupplier, Contract, Site, Certificationsupplier_approvalcontractPageRank (criticality), bridges (single points of failure)industry
Insurance claimsClaim, Policy, Party, Providerclaims_lifecyclegeneral, financialcommunities (fraud rings), trianglesline of business
Healthcare care coordinationPatient, Encounter, Provider, Orderpatient_journeyscientificshortest path (referral), temporal PageRankspecialty
Manufacturing traceabilityOrder, Batch, Machine, Inspectionproduction_ordergeneralBFS impact propagation, MSTplant
Government service deliveryCitizen, Application, Agency, Documentcitizen_servicegeneralduplicate detection, SLA analyticsprogramme
Pharma clinical trialsTrial, Site, Patient, Submissioncompliance_reviewscientificlink prediction (recruitment), lineagetherapeutic area
Regulatory compliance graphRegulation, Control, Evidence, Ownercompliance_reviewcontractcoverage gaps (traversal), betweennessjurisdiction
CRM deal intelligenceAccount, Contact, Opportunity, Interactiondeal_lifecyclegeneralcommunity (buying group), temporal PageRank (momentum)segment
Hybrid human–agent orchestrationCase, Evidence, Recommendation, Decisionhybrid_casedomain-specificas per wrapped domainagent roles / prompts
HR org-chart assistantPerson, Team, Role, Skillnonegeneralshortest path, centralitybusiness unit

Adding a vertical from this table is: register schema, load template, register extraction profile, set detection configuration, write TenantConfig, build front-end. Deployment is the same stack in every case.

Purple8 Hyper Graph v0.72.0 · AI-Native Execution Infrastructure · NVIDIA Inception Member · Red Hat Technology Partner.