Architecture Overview¶
System Architecture (v0.3.0)¶
SCP uses a graph-based dynamic context selection model with two distinct paths:
┌─────────────────────────────────────────────────────────────────────────┐
│ INGESTION PATH │
│ │
│ Versioned Bundle ──► Bundle Registry ──► Graph Database │
│ (API) (relationships) │
│ │ │
│ ▼ │
│ Rules Engine ──────► Graph Database │
│ (formularies) (operational edges) │
└─────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────┐
│ RUNTIME PATH │
│ │
│ Agent Request ──► Auth ──► Intent Check ──► Graph Query ──► Stream │
│ │ │ │ │ │ │
│ │ │ │ │ ▼ │
│ API Key Agent Registry Allowed Role-based Context │
│ (identity/role) Intents Traversal Delivery │
└─────────────────────────────────────────────────────────────────────────┘
Services¶
| Service | Port(s) | Purpose | Technology |
|---|---|---|---|
| Control Plane API | 8000 | Bundle Registry, Agent Registry, REST context API | FastAPI |
| Context Service | 8002 (gRPC), 8003 (webhook) | Real-time streaming, tag subscriptions | gRPC, aiohttp |
| Rules Engine | 8001 | Custom business rules (formularies, networks) | FastAPI |
| Telemetry Service | 8004 | Usage reporting | FastAPI |
| Graph Database | 5432 | Relationship storage, Cypher queries | PostgreSQL + Apache AGE |
| Redis | 6379 | Pub/sub for real-time updates | Redis |
| Caddy | 443, 8443 | TLS termination, reverse proxy | Caddy |
Technology Stack¶
- Backend: FastAPI (async Python), gRPC (asyncio)
- Database: PostgreSQL with Apache AGE extension (graph + relational)
- Pub/Sub: Redis (for context update broadcasting)
- Connection Pooling: asyncpg
- Type Safety: Pydantic, Protocol Buffers
- Servers: Uvicorn (ASGI), gRPC server
Core Concepts¶
The Control Hierarchy¶
Global context (bundles/graph) ──► applies to all agents
│
▼
Role-based context (role nodes) ──► applies to all agents with this role
│
▼
Agent-specific context (overrides) ──► applies to ONE agent
Key Insight: Separation of Authoring from Selection¶
- Bundles define the world (stable, generic, reusable)
- Graph indexes the world (relationships, traversable)
- Context Service enforces the rules (policy gating)
- Agents operate inside the slice they're given
Graph Database¶
Why Graph?¶
-
Relationships already exist - Bundles have structural relationships (imports, references, applies_to). Graph surfaces these in queryable form.
-
Dynamic selection without manual mapping - No need for explicit role → context mappings. Graph traverses relationships based on request.
-
Agent-level control - Can adjust context for individual misbehaving agents without code changes.
-
Simpler context authoring - Authors create well-connected content. Graph figures out what's relevant at runtime.
Graph Schema¶
Nodes:
- Bundle - Versioned context packages
- SCD - Structured Context Documents
- Role - Agent roles (prior-auth-agent, claims-processor)
- Agent - Individual agent instances
Edges (from bundles):
- CONTAINS - Bundle contains SCDs
- IMPORTS - Bundle imports another bundle
- APPLIES_TO - SCD applies to role
- GOVERNED_BY - SCD governed by another SCD
- REFERENCES - SCD references another SCD
Edges (from rules DB):
- ON_FORMULARY - Drug on formulary
- IN_NETWORK - Provider in network
- REQUIRES_PRIOR_AUTH - Service requires PA
Edges (from agent registry):
- HAS_ROLE - Agent has role
- HAS_OVERRIDE - Agent has SCD override
- HAS_RESTRICTION - Agent has SCD restriction
Example Cypher Queries¶
Get all SCDs for a role:
MATCH (s:SCD)-[:APPLIES_TO]->(r:Role {id: 'role:prior-auth-agent'})
RETURN s.id, properties(s)
Get SCDs with governance chain:
MATCH (s:SCD)-[:APPLIES_TO]->(r:Role {id: 'role:prior-auth-agent'})
OPTIONAL MATCH (s)-[:GOVERNED_BY]->(g:SCD)
OPTIONAL MATCH (s)-[:REFERENCES]->(ref:SCD)
RETURN s.id, collect(DISTINCT g.id), collect(DISTINCT ref.id)
Agent Registry¶
Agent Registration Model¶
Agents are registered with: - Identity - Unique agent ID - Role - What role this agent has (determines base context) - Allowed Intents - What task types this agent can request context for - API Key - Authentication credential
The Thin Client Model¶
The agent becomes a thin client: - Minimal baked-in knowledge - Gets context from SCP at runtime - Can be controlled/adjusted via the control plane
# Agent registration example
{
"agent_id": "agent:prior-auth-prod",
"name": "Prior Auth Production Agent",
"role_id": "role:prior-auth-agent",
"allowed_intents": [
"prior_auth_check",
"formulary_lookup",
"clinical_guidelines_check"
],
"status": "active"
}
Policy Overrides¶
Individual agents can have: - Overrides - Additional SCDs beyond their role's default - Restrictions - SCDs to exclude from their context
# Agent with restrictions
{
"agent_id": "agent:prior-auth-restricted",
"role_id": "role:prior-auth-agent",
"restrictions": ["scd:project:phi-handling"] # This SCD will be excluded
}
Context Request Flow (v0.3)¶
1. Authentication¶
Agent sends request with API key:
POST /api/context
X-API-Key: sk_abc123...
Content-Type: application/json
{
"task_type": "prior_auth_check",
"params": {"drug": "Keytruda", "diagnosis": "lung cancer"}
}
2. Intent Validation¶
Orchestrator checks:
- Is API key valid?
- Is agent active?
- Is prior_auth_check in agent's allowed_intents?
3. Graph Query¶
Based on agent's role, query graph for relevant SCDs:
MATCH (s:SCD)-[:APPLIES_TO]->(r:Role {id: 'role:prior-auth-agent'})
RETURN s.id
4. Policy Filtering¶
Apply agent-specific overrides/restrictions: - Add any override SCDs - Remove any restricted SCDs
5. Context Delivery¶
Return filtered SCDs to agent:
{
"success": true,
"agent_id": "agent:prior-auth-prod",
"role_id": "role:prior-auth-agent",
"task_type": "prior_auth_check",
"scd_ids": [
"scd:standards:hipaa-privacy-rule",
"scd:project:clinical-guidelines-v1.2",
"scd:project:formulary-2024"
],
"scd_content": { ... },
"processing_time_ms": 34
}
6. Audit Logging¶
Every request logged: - Agent ID, Role ID - Task type, Parameters - SCDs returned - Timestamp, Processing time
Bundle Hierarchy¶
The bundle system uses a hierarchical import model:
Meta Bundle (SCS Foundation)
↓ imports
Standards Bundles (External: HIPAA, SOC2, CHAI, NIST)
↓ imports
Domain Bundle (The Company - e.g., Acme Health Corp)
↓ imports multiple
Concern Bundles (Functional Areas: Architecture, Security, Clinical, Data)
↓ imported by
Project Bundles (Individual Initiatives: Prior Auth App, Patient Portal)
See Bundle Types Guide for detailed explanations.
Import Resolution¶
When a bundle is materialized to the graph, all imports are recursively resolved:
Input: bundle:prior-auth:1.0.0
Output (resolved dependency graph):
1. bundle:meta:1.0.0 (Meta - foundation)
2. bundle:hipaa:1.0.0 (Standards)
3. bundle:chai:1.0.0 (Standards)
4. bundle:soc2:1.0.0 (Standards)
5. bundle:acme-architecture:1.0.0 (Concern)
6. bundle:acme-security:1.0.0 (Concern)
7. bundle:acme-clinical:1.0.0 (Concern)
8. bundle:acme-company-context:1.0.0 (Concern)
9. bundle:acme-health-corp:1.0.0 (Domain)
10. bundle:prior-auth:1.0.0 (Project)
All SCDs from all bundles are added as nodes with relationships preserved.
API Endpoints¶
Control Plane API (Port 8000)¶
Bundle Registry:
- POST /api/bundles - Create/publish bundle
- GET /api/bundles - List bundles
- GET /api/bundles/{id}/versions/{v} - Get specific version
- DELETE /api/bundles/{id}/versions/{v} - Deactivate bundle
Agent Registry:
- POST /api/agents - Register agent
- GET /api/agents - List agents
- GET /api/agents/{id} - Get agent details
- PUT /api/agents/{id} - Update agent
- POST /api/agents/{id}/api-keys - Generate API key
- DELETE /api/agents/{id}/api-keys/{key_id} - Revoke API key
Context (REST):
- POST /api/context - Request context (v0.3 intent-based)
- GET /api/context/health - Health check
Tags:
- POST /api/tags - Create tag
- PUT /api/tags/{tag} - Update tag
- GET /api/tags/{tag} - Resolve tag
Context Service (Port 8002 gRPC, Port 8003 Webhook)¶
gRPC Methods:
- Subscribe(tag, agent_id) - Subscribe to tag stream (v0.2)
- RequestContext(api_key, task_type, params) - Request context (v0.3)
Webhook:
- POST /webhook/tag-update - Receives tag update notifications
Rules Engine (Port 8001)¶
POST /api/rules/schemas- Create rule schemaPOST /api/rules/rule-sets- Create rule setPOST /api/rules/rule-sets/{id}/rules- Add ruleGET /api/rules/rule-sets- List rule sets
Database Schema¶
Index/Ledger Database¶
Core Tables:
- bundles - Bundle storage (id, version, type, manifest JSONB)
- tags - Tag → bundle mappings
- deployments - Multi-bundle deployments
- events - Lifecycle audit trail
Agent Registry Tables:
- agents - Agent registration (id, name, role_id, allowed_intents)
- agent_api_keys - API keys (key_id, key_hash, agent_id)
- agent_policy_overrides - Per-agent SCD overrides/restrictions
- agent_context_requests - Audit log of all context requests
Graph Database (Apache AGE)¶
Graph Name: scp_context
Vertex Labels:
- Bundle, SCD, Role, Agent
Edge Labels:
- CONTAINS, IMPORTS, APPLIES_TO, GOVERNED_BY, REFERENCES
- HAS_ROLE, HAS_OVERRIDE, HAS_RESTRICTION
v0.2 vs v0.3 Comparison¶
| Aspect | v0.2 (Tag-based) | v0.3 (Intent-based) |
|---|---|---|
| Flow | Subscribe to tag → get full bundle | Request for task → get relevant subset |
| Selection | Flatten entire bundle graph | Graph traversal based on role |
| Streaming | Continuous stream with updates | Request/response (can also stream) |
| Filtering | None (get everything) | Role-based + agent-specific policy |
| Use Case | Design-time (full context) | Runtime (minimal governance context) |
Both modes are supported. v0.2 Subscribe is ideal for dev agents that need full context. v0.3 RequestContext is ideal for production agents that need minimal governance context.
Security Model¶
Current Implementation¶
- ✅ Agent API key authentication (per-agent, expiry, revocation, lifecycle enforcement)
- ✅ Admin API key authentication (bundle management, agent registry, audit admin)
- ✅ Intent validation (agents restricted to their registered allowed task types)
- ✅ Role-based context access (different roles receive different SCDs)
- ✅ Tamper-evident audit log (hash chain, immutability trigger, RLS)
- ✅ TLS (Caddy reverse proxy, Postgres sslmode)
- ✅ Secrets management (no insecure defaults, startup validation)
- ✅ License key enforcement (RS256 JWT, agent cap)
Planned Enhancements¶
- OAuth2/OIDC for admin console SSO
- Multi-tenancy with organization isolation
- Fine-grained RBAC for bundle management
Deployment Architecture¶
Docker Compose (Pilot / Self-Hosted)¶
Caddy (ports 443, 8443) — TLS termination
│
├── API Server (port 8000, internal)
├── Context Service (ports 8002/8003, internal)
├── Rules Engine (port 8001, internal)
├── Telemetry Service (port 8004, internal)
├── PostgreSQL + Apache AGE (port 5432, internal)
└── Redis (port 6379, internal)
AWS (Production)¶
ALB (TLS) → EC2 instance running Docker Compose
├── All services (internal Docker network)
├── Secrets from SSM Parameter Store
└── Daily backups to S3
See AWS Setup Guide for the full CloudFormation deployment.
Related Documentation¶
- Bundle Types Guide - Understanding the 5 bundle types
- Getting Started - Installation and first bundle
- API Reference - Complete API documentation