Fulcrum: System Context Document
Version: 1.1.0
Date: 2026-01-03 (Updated from December 10, 2025 original)
Purpose: Implementation guide bridging architecture decisions to service implementation
Audience: Implementation teams (Claude Code, Cursor, engineers)
Document Structure
- System Overview
- Service Catalog
- Data Flows
- API Contracts
- Error Handling
- Security Model
- Phase 1 Scope
System Overview
Architecture Philosophy
Fulcrum is a governance layer, not an orchestration framework. It wraps existing agent orchestrators (LangGraph, Microsoft Agent Framework, CrewAI) with:
- Cost governance - Budget limits, token tracking, circuit breakers
- Policy enforcement - Pre/mid/post-execution authorization
- Unified observability - Cross-framework telemetry and audit trails
Core Abstraction
The Execution Envelope is Fulcrum's unit of governance. Every agent execution—regardless of framework—is wrapped in an Envelope that captures:
Execution Envelope
├── Identification (tenant_id, envelope_id, execution_id)
├── Governance Context (budget_id, policy_set, token_limit, cost_limit)
├── Framework Context (adapter_type, native_ref, checkpoint_id)
├── Lifecycle State (PENDING → AUTHORIZED → RUNNING → COMPLETED)
└── Cost Summary (tokens_used, cost_usd, llm_calls, tool_calls)
High-Level Architecture
┌─────────────────────────────────────────────────────────────────────┐
│ CONTROL PLANE │
├─────────────────────────────────────────────────────────────────────┤
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ Gateway │ │ Admin UI │ │ CLI │ │
│ │ (HTTP/gRPC) │ │ (React) │ │ (Go) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ │ │ │ │
│ └─────────────────┼─────────────────┘ │
│ ▼ │
│ ┌────────────────────────────────────────────────────────────────┐ │
│ │ SERVICE MESH │ │
│ ├────────────┬────────────┬────────────┬────────────────────────┤ │
│ │ Envelope │ Policy │ Budget │ Event Processor │ │
│ │ Service │ Service │ Service │ │ │
│ └─────┬──────┴─────┬──────┴─────┬──────┴──────────┬─────────────┘ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌──────────────────────────────────────────────────────────────┐ │
│ │ DATA LAYER │ │
│ │ PostgreSQL (Envelopes, Policies, Budgets, Tenants) │ │
│ │ TimescaleDB (Cost time-series, Token metrics) │ │
│ │ Redis (Policy cache, Budget cache, Rate limits) │ │
│ │ NATS JetStream (Event bus, Durable queues) │ │
│ └──────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────┘
│
┌───────────────┼───────────────┐
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ LangGraph│ │ Microsoft│ │ A2A │
│ Adapter │ │ Adapter │ │ Proxy │
└────┬─────┘ └────┬─────┘ └────┬─────┘
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ LangGraph│ │ MS Agent │ │ External │
│ Runtime │ │ Framework│ │ Agents │
└──────────┘ └──────────┘ └──────────┘
Service Catalog
Phase 1 Services
| Service | Responsibility | Port | Protocol |
|---|---|---|---|
| Gateway | API routing, auth, rate limiting | 8080 | HTTP/gRPC |
| Envelope Service | Envelope lifecycle management | 8081 | gRPC |
| Policy Service | Policy evaluation, authorization | 8082 | gRPC |
| Budget Service | Budget CRUD, enforcement | 8083 | gRPC |
| Event Processor | Event ingestion, cost aggregation | - | NATS consumer |
Service Dependencies
Gateway
├── depends: Envelope Service (sync)
├── depends: Policy Service (sync)
├── depends: Budget Service (sync)
└── depends: Redis (auth cache)
Envelope Service
├── depends: PostgreSQL (envelope storage)
├── depends: Policy Service (authorization check)
├── depends: Budget Service (budget validation)
└── publishes: NATS (envelope events)
Policy Service
├── depends: PostgreSQL (policy definitions)
├── depends: Redis (policy cache)
└── publishes: NATS (policy violation events)
Budget Service
├── depends: PostgreSQL (budget definitions)
├── depends: TimescaleDB (cost aggregates)
├── depends: Redis (budget cache)
└── publishes: NATS (budget alerts)
Event Processor
├── subscribes: NATS (all events)
├── depends: PostgreSQL (event storage)
├── depends: TimescaleDB (cost writes)
└── depends: Budget Service (real-time enforcement)
Data Flows
Flow 1: Execution Start (Happy Path)
SDK/Adapter Gateway Envelope Policy Budget
│ │ │ │ │
│──POST /envelopes────────▶ │ │ │
│ │──CreateEnvelope───▶ │ │
│ │ │──CheckPolicy─────▶ │
│ │ │◀─────ALLOW───────│ │
│ │ │──ValidateBudget──────────────────▶│
│ │ │◀─────VALID────────────────────────│
│ │ │ │ │
│ │ │──[Store Envelope]│ │
│ │ │──[Publish Event]─┼────────────────▶ NATS
│ │◀─Envelope(AUTHORIZED) │ │
│◀──201 Created───────────│ │ │ │
Flow 2: Mid-Execution Budget Check
Adapter Event Processor Budget Envelope
│ │ │ │
│──[LLM Call Complete]────▶ │ │
│──Event(tokens=500)──────▶ │ │
│ │──UpdateUsage───────▶ │
│ │ │ │
│ │ [Budget at 80%] │ │
│ │◀─WARNING───────────│ │
│ │──PublishAlert──────┼─────────────────▶ NATS
│ │ │ │
│ [Budget at 100%] │ │
│ │──EXCEEDED──────────▶ │
│ │ │──TerminateEnvelope─▶
│◀─────TerminateSignal────│ │ │
Flow 3: Policy Violation
Adapter Gateway Policy Envelope
│ │ │ │
│──ToolInvocation─────▶ │ │
│ (tool=browser) │──CheckPolicy──────▶ │
│ │ │ │
│ │ [Policy: DENY browser] │
│ │◀─DENY(reason)─────│ │
│ │ │──LogViolation────▶
│ │ │──[Publish Event]─▶ NATS
│◀─403 PolicyViolation─│ │ │
Flow 4: Checkpoint and Resume
Adapter Envelope Checkpoint Store
│ │ │
│──CaptureCheckpoint──▶ │
│ │──StoreState──────────▶
│ │◀─checkpoint_id───────│
│◀─CheckpointRef──────│ │
│ │ │
│ [Later...] │ │
│ │ │
│──RestoreCheckpoint──▶ │
│ (checkpoint_id) │──LoadState───────────▶
│ │◀─state───────────────│
│◀─ResumedExecution───│ │
API Contracts
Envelope API (OpenAPI 3.1)
openapi: 3.1.0
info:
title: Fulcrum Envelope API
version: 1.0.0
description: Execution Envelope lifecycle management
paths:
/v1/envelopes:
post:
operationId: createEnvelope
summary: Create a new Execution Envelope
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateEnvelopeRequest'
responses:
'201':
description: Envelope created and authorized
content:
application/json:
schema:
$ref: '#/components/schemas/Envelope'
'403':
description: Policy denied execution
content:
application/json:
schema:
$ref: '#/components/schemas/PolicyViolation'
'422':
description: Budget exhausted or invalid
content:
application/json:
schema:
$ref: '#/components/schemas/BudgetError'
/v1/envelopes/{envelope_id}:
get:
operationId: getEnvelope
summary: Get envelope by ID
parameters:
- name: envelope_id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Envelope found
content:
application/json:
schema:
$ref: '#/components/schemas/Envelope'
'404':
description: Envelope not found
/v1/envelopes/{envelope_id}/events:
post:
operationId: recordEvent
summary: Record an event against an envelope
parameters:
- name: envelope_id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/EventRecord'
responses:
'202':
description: Event accepted
'409':
description: Envelope terminated or completed
/v1/envelopes/{envelope_id}/terminate:
post:
operationId: terminateEnvelope
summary: Force terminate an execution
parameters:
- name: envelope_id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/TerminateRequest'
responses:
'200':
description: Envelope terminated
'409':
description: Already completed or terminated
components:
schemas:
CreateEnvelopeRequest:
type: object
required:
- tenant_id
- budget_id
- adapter_type
properties:
tenant_id:
type: string
format: uuid
budget_id:
type: string
format: uuid
adapter_type:
type: string
enum: [langgraph, microsoft, crewai, a2a_proxy, custom]
policy_set:
type: array
items:
type: string
metadata:
type: object
additionalProperties: true
Envelope:
type: object
properties:
envelope_id:
type: string
format: uuid
tenant_id:
type: string
format: uuid
budget_id:
type: string
format: uuid
execution_id:
type: string
adapter_type:
type: string
state:
type: string
enum: [PENDING, AUTHORIZED, RUNNING, PAUSED, COMPLETED, FAILED, TERMINATED]
governance_context:
$ref: '#/components/schemas/GovernanceContext'
cost_summary:
$ref: '#/components/schemas/CostSummary'
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
GovernanceContext:
type: object
properties:
token_limit:
type: integer
cost_limit_usd:
type: number
format: double
timeout_seconds:
type: integer
policy_set:
type: array
items:
type: string
CostSummary:
type: object
properties:
tokens_input:
type: integer
tokens_output:
type: integer
tokens_total:
type: integer
cost_usd:
type: number
format: double
llm_calls:
type: integer
tool_calls:
type: integer
EventRecord:
type: object
required:
- event_type
- timestamp
properties:
event_type:
type: string
timestamp:
type: string
format: date-time
tokens:
type: object
properties:
input:
type: integer
output:
type: integer
model:
type: string
cost_usd:
type: number
payload:
type: object
TerminateRequest:
type: object
properties:
reason:
type: string
force:
type: boolean
default: false
PolicyViolation:
type: object
properties:
code:
type: string
policy_id:
type: string
message:
type: string
denied_action:
type: string
BudgetError:
type: object
properties:
code:
type: string
budget_id:
type: string
current_usage:
type: number
limit:
type: number
message:
type: string
Budget API (OpenAPI 3.1)
openapi: 3.1.0
info:
title: Fulcrum Budget API
version: 1.0.0
description: Budget management and enforcement
paths:
/v1/budgets:
post:
operationId: createBudget
summary: Create a new budget
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreateBudgetRequest'
responses:
'201':
description: Budget created
content:
application/json:
schema:
$ref: '#/components/schemas/Budget'
get:
operationId: listBudgets
summary: List budgets for tenant
parameters:
- name: tenant_id
in: query
required: true
schema:
type: string
format: uuid
- name: status
in: query
schema:
type: string
enum: [active, exhausted, expired, all]
responses:
'200':
description: Budget list
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Budget'
/v1/budgets/{budget_id}:
get:
operationId: getBudget
summary: Get budget by ID
parameters:
- name: budget_id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Budget found
content:
application/json:
schema:
$ref: '#/components/schemas/Budget'
/v1/budgets/{budget_id}/usage:
get:
operationId: getBudgetUsage
summary: Get real-time budget usage
parameters:
- name: budget_id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Current usage
content:
application/json:
schema:
$ref: '#/components/schemas/BudgetUsage'
/v1/budgets/{budget_id}/check:
post:
operationId: checkBudget
summary: Check if budget allows execution
description: Returns whether the proposed execution fits within budget constraints
parameters:
- name: budget_id
in: path
required: true
schema:
type: string
format: uuid
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/BudgetCheckRequest'
responses:
'200':
description: Budget check result
content:
application/json:
schema:
$ref: '#/components/schemas/BudgetCheckResult'
components:
schemas:
CreateBudgetRequest:
type: object
required:
- tenant_id
- name
- type
properties:
tenant_id:
type: string
format: uuid
name:
type: string
type:
type: string
enum: [token, cost, hybrid]
limits:
$ref: '#/components/schemas/BudgetLimits'
alerts:
type: array
items:
$ref: '#/components/schemas/AlertThreshold'
period:
type: string
enum: [hourly, daily, weekly, monthly, total]
expires_at:
type: string
format: date-time
Budget:
type: object
properties:
budget_id:
type: string
format: uuid
tenant_id:
type: string
format: uuid
name:
type: string
type:
type: string
status:
type: string
enum: [active, exhausted, expired]
limits:
$ref: '#/components/schemas/BudgetLimits'
usage:
$ref: '#/components/schemas/BudgetUsage'
alerts:
type: array
items:
$ref: '#/components/schemas/AlertThreshold'
created_at:
type: string
format: date-time
BudgetLimits:
type: object
properties:
max_tokens:
type: integer
description: Maximum tokens per period (null = unlimited)
max_cost_usd:
type: number
format: double
description: Maximum cost in USD per period (null = unlimited)
max_executions:
type: integer
description: Maximum envelope count per period
BudgetUsage:
type: object
properties:
tokens_used:
type: integer
cost_usd:
type: number
format: double
executions:
type: integer
percent_tokens:
type: number
percent_cost:
type: number
period_start:
type: string
format: date-time
period_end:
type: string
format: date-time
AlertThreshold:
type: object
properties:
percent:
type: integer
minimum: 1
maximum: 100
action:
type: string
enum: [notify, warn, terminate]
webhook_url:
type: string
format: uri
BudgetCheckRequest:
type: object
properties:
estimated_tokens:
type: integer
estimated_cost_usd:
type: number
BudgetCheckResult:
type: object
properties:
allowed:
type: boolean
reason:
type: string
remaining_tokens:
type: integer
remaining_cost_usd:
type: number
warnings:
type: array
items:
type: string
Policy API (OpenAPI 3.1)
openapi: 3.1.0
info:
title: Fulcrum Policy API
version: 1.0.0
description: Policy definition and evaluation
paths:
/v1/policies:
post:
operationId: createPolicy
summary: Create a new policy
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/CreatePolicyRequest'
responses:
'201':
description: Policy created
content:
application/json:
schema:
$ref: '#/components/schemas/Policy'
get:
operationId: listPolicies
summary: List policies for tenant
parameters:
- name: tenant_id
in: query
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Policy list
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Policy'
/v1/policies/{policy_id}:
get:
operationId: getPolicy
summary: Get policy by ID
parameters:
- name: policy_id
in: path
required: true
schema:
type: string
format: uuid
responses:
'200':
description: Policy found
content:
application/json:
schema:
$ref: '#/components/schemas/Policy'
/v1/policies/evaluate:
post:
operationId: evaluatePolicy
summary: Evaluate policies against an action
description: Check if an action is allowed by the applicable policy set
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/PolicyEvaluationRequest'
responses:
'200':
description: Evaluation result
content:
application/json:
schema:
$ref: '#/components/schemas/PolicyEvaluationResult'
components:
schemas:
CreatePolicyRequest:
type: object
required:
- tenant_id
- name
- rules
properties:
tenant_id:
type: string
format: uuid
name:
type: string
description:
type: string
rules:
type: array
items:
$ref: '#/components/schemas/PolicyRule'
priority:
type: integer
description: Higher priority policies evaluate first
Policy:
type: object
properties:
policy_id:
type: string
format: uuid
tenant_id:
type: string
format: uuid
name:
type: string
description:
type: string
rules:
type: array
items:
$ref: '#/components/schemas/PolicyRule'
priority:
type: integer
enabled:
type: boolean
created_at:
type: string
format: date-time
updated_at:
type: string
format: date-time
PolicyRule:
type: object
required:
- action
- effect
properties:
action:
type: string
description: 'Action pattern (e.g., "tool:*", "llm:gpt-4*", "execution:start")'
effect:
type: string
enum: [allow, deny]
conditions:
type: array
items:
$ref: '#/components/schemas/PolicyCondition'
PolicyCondition:
type: object
properties:
field:
type: string
description: 'Context field to check (e.g., "request.model", "budget.percent_used")'
operator:
type: string
enum: [eq, neq, gt, gte, lt, lte, in, not_in, matches]
value:
description: Value to compare against
PolicyEvaluationRequest:
type: object
required:
- tenant_id
- action
properties:
tenant_id:
type: string
format: uuid
envelope_id:
type: string
format: uuid
policy_set:
type: array
items:
type: string
description: Specific policies to evaluate (empty = all tenant policies)
action:
type: string
description: Action being requested
context:
type: object
additionalProperties: true
description: Additional context for condition evaluation
PolicyEvaluationResult:
type: object
properties:
allowed:
type: boolean
effect:
type: string
enum: [allow, deny, no_match]
matched_policy:
type: string
matched_rule:
type: string
reason:
type: string
evaluation_time_ms:
type: number
Error Handling
Error Code Taxonomy
All Fulcrum errors follow a structured code format: FULCRUM-{DOMAIN}-{CODE}
| Domain | Code Range | Description |
|---|---|---|
| ENV | 1000-1999 | Envelope errors |
| POL | 2000-2999 | Policy errors |
| BUD | 3000-3999 | Budget errors |
| EVT | 4000-4999 | Event errors |
| ADP | 5000-5999 | Adapter errors |
| SYS | 9000-9999 | System errors |
Standard Error Response
{
"error": {
"code": "FULCRUM-BUD-3001",
"message": "Budget exhausted",
"details": {
"budget_id": "uuid",
"limit": 10000,
"current": 10234
},
"request_id": "req-uuid",
"timestamp": "2025-12-10T14:30:00Z",
"documentation_url": "https://docs.fulcrum.io/errors/BUD-3001"
}
}
Recoverable vs Terminal Errors
| Error Type | Behavior | Client Action |
|---|---|---|
| Recoverable | Execution can continue | Retry with backoff |
| Terminal | Execution must stop | Complete envelope as FAILED |
Recoverable Errors:
- FULCRUM-SYS-9001: Service temporarily unavailable (retry)
- FULCRUM-ADP-5002: Checkpoint store timeout (retry)
- FULCRUM-EVT-4001: Event delivery failed (buffered retry)
Terminal Errors:
- FULCRUM-POL-2001: Policy denied (no retry, requires policy change)
- FULCRUM-BUD-3001: Budget exhausted (no retry, requires budget top-up)
- FULCRUM-ENV-1003: Envelope already terminated (no retry)
Circuit Breaker Pattern
Services implement circuit breakers for downstream dependencies:
States: CLOSED → OPEN → HALF_OPEN → CLOSED
CLOSED: Normal operation, track failure rate
OPEN: All requests fail-fast (no downstream calls)
HALF_OPEN: Allow probe requests, success → CLOSED, failure → OPEN
Thresholds:
- Open after: 5 failures in 10 seconds
- Half-open after: 30 seconds in OPEN
- Close after: 3 consecutive successes in HALF_OPEN
Graceful Degradation
| Dependency Failure | Degradation Strategy |
|---|---|
| Policy Service down | Fail-closed (deny all) or cached policy |
| Budget Service down | Fail-open with soft limits from cache |
| Event Processor down | Buffer events locally, replay on recovery |
| Checkpoint Store down | Disable checkpointing, continue execution |
Security Model
Authentication
Service-to-Service: mTLS with certificate rotation (Cert-Manager)
Client-to-Gateway: API keys or JWT tokens
Authorization Layers
┌───────────────────────────────────────────────┐
│ Layer 1: API Gateway │
│ - Rate limiting (per API key) │
│ - JWT validation │
│ - Tenant isolation │
├───────────────────────────────────────────────┤
│ Layer 2: Service Authorization │
│ - RBAC for admin operations │
│ - Resource ownership validation │
├───────────────────────────────────────────────┤
│ Layer 3: Policy Engine │
│ - Execution-time policy evaluation │
│ - Tool/LLM access controls │
└───────────────────────────────────────────────┘
Tenant Isolation
Database: Row-level security with tenant_id on all tables
CREATE POLICY tenant_isolation ON envelopes
USING (tenant_id = current_setting('app.tenant_id')::uuid);
NATS: Subject namespacing fulcrum.{tenant_id}.events.*
Redis: Key prefixing {tenant_id}:policy:{policy_id}
Secrets Management
| Secret Type | Storage | Rotation |
|---|---|---|
| Database credentials | Kubernetes Secrets / Vault | 30 days |
| API keys | PostgreSQL (hashed) | On demand |
| JWT signing keys | Kubernetes Secrets | 90 days |
| LLM API keys | Vault | On demand |
Audit Trail
All governance actions logged to immutable audit log:
{
"audit_id": "uuid",
"timestamp": "2025-12-10T14:30:00Z",
"tenant_id": "uuid",
"actor": {
"type": "api_key",
"id": "key-uuid"
},
"action": "policy.evaluate",
"resource": {
"type": "envelope",
"id": "env-uuid"
},
"result": "allow",
"metadata": {}
}
Phase 1 Scope
In Scope
| Component | Deliverable | Acceptance Criteria |
|---|---|---|
| Envelope Service | Full CRUD + lifecycle | Create, read, update state, terminate |
| Budget Service | CRUD + real-time enforcement | Budget checks complete <10ms p99 |
| Policy Service | CRUD + evaluation | Policy eval complete <5ms p99 |
| Event Processor | Event ingestion + cost aggregation | Process 10k events/sec |
| Gateway | HTTP API + auth | <50ms p99 latency |
| LangGraph Adapter | Embedded middleware | All 14 interface methods |
| SDK (TypeScript) | Client library | Typed API for all endpoints |
Out of Scope (Phase 2+)
- Admin UI (Phase 2)
- Microsoft Agent Framework adapter (Phase 2)
- A2A Protocol Proxy (Phase 3)
- Multi-region deployment (Phase 4)
- CLI tool (Phase 5)
- Additional framework adapters (Phase 4+)
Phase 1 Architecture Constraints
- Single region - No cross-region replication
- Single PostgreSQL - No read replicas
- Synchronous policy checks - Async optimization in Phase 2
- LangGraph only - One adapter proves the pattern
Success Metrics
| Metric | Target | Measurement |
|---|---|---|
| Envelope creation latency | <100ms p99 | Gateway logs |
| Policy evaluation latency | <10ms p99 | Service metrics |
| Budget check latency | <10ms p99 | Service metrics |
| Event processing throughput | 10k/sec | NATS consumer lag |
| System availability | 99.9% | Uptime monitoring |
Implementation Notes
Database Schema (PostgreSQL)
-- Core tables
CREATE TABLE tenants (
tenant_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(255) NOT NULL,
settings JSONB DEFAULT '{}',
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE budgets (
budget_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES tenants(tenant_id),
name VARCHAR(255) NOT NULL,
type VARCHAR(50) NOT NULL,
limits JSONB NOT NULL,
alerts JSONB DEFAULT '[]',
period VARCHAR(50),
status VARCHAR(50) DEFAULT 'active',
expires_at TIMESTAMPTZ,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE policies (
policy_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES tenants(tenant_id),
name VARCHAR(255) NOT NULL,
rules JSONB NOT NULL,
priority INTEGER DEFAULT 0,
enabled BOOLEAN DEFAULT true,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE envelopes (
envelope_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id UUID REFERENCES tenants(tenant_id),
budget_id UUID REFERENCES budgets(budget_id),
execution_id VARCHAR(255),
adapter_type VARCHAR(50) NOT NULL,
state VARCHAR(50) DEFAULT 'PENDING',
governance_context JSONB NOT NULL,
framework_context JSONB DEFAULT '{}',
cost_summary JSONB DEFAULT '{"tokens_input":0,"tokens_output":0,"cost_usd":0}',
checkpoint_id UUID,
created_at TIMESTAMPTZ DEFAULT NOW(),
updated_at TIMESTAMPTZ DEFAULT NOW(),
completed_at TIMESTAMPTZ
);
CREATE TABLE events (
event_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
envelope_id UUID REFERENCES envelopes(envelope_id),
tenant_id UUID REFERENCES tenants(tenant_id),
event_type VARCHAR(100) NOT NULL,
tokens JSONB,
payload JSONB,
created_at TIMESTAMPTZ DEFAULT NOW()
);
CREATE TABLE checkpoints (
checkpoint_id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
envelope_id UUID REFERENCES envelopes(envelope_id),
state_hash VARCHAR(64) NOT NULL,
state_data BYTEA NOT NULL,
size_bytes INTEGER NOT NULL,
created_at TIMESTAMPTZ DEFAULT NOW()
);
-- Indexes
CREATE INDEX idx_envelopes_tenant ON envelopes(tenant_id);
CREATE INDEX idx_envelopes_state ON envelopes(state) WHERE state IN ('RUNNING', 'PENDING');
CREATE INDEX idx_events_envelope ON events(envelope_id);
CREATE INDEX idx_budgets_tenant ON budgets(tenant_id);
CREATE INDEX idx_policies_tenant ON policies(tenant_id);
NATS Subject Hierarchy
fulcrum.
├── {tenant_id}.
│ ├── envelopes.
│ │ ├── created
│ │ ├── started
│ │ ├── completed
│ │ ├── failed
│ │ └── terminated
│ ├── events.
│ │ ├── llm.*
│ │ ├── tool.*
│ │ └── checkpoint.*
│ ├── budgets.
│ │ ├── warning
│ │ └── exceeded
│ └── policies.
│ └── violation
└── system.
├── health
└── metrics
Service Configuration
# config.yaml (all services)
server:
port: 8081
grpc_port: 9081
shutdown_timeout: 30s
database:
host: ${DB_HOST}
port: 5432
name: fulcrum
pool_size: 20
ssl_mode: require
redis:
host: ${REDIS_HOST}
port: 6379
pool_size: 10
nats:
url: ${NATS_URL}
cluster_id: fulcrum
client_id: ${SERVICE_NAME}
observability:
otel_endpoint: ${OTEL_ENDPOINT}
metrics_port: 9090
log_level: info
log_format: json
This document provides the implementation bridge between architectural decisions and service code. Refer to ADRs for decision rationale, protobufs for data contracts, and this document for operational guidance.