Circuit Orchestration

Pre-wired topologies with smart adapters, mock collapse, A/B routing, taint analysis, trust-aware validation, and self-healing. Define the board. Slot services in.

pip install baton-orchestrator
[ ]

Circuit-First Design

Topology is a first-class artifact. Define nodes, edges, and contracts in baton.yaml. Services slot in and out of a fixed board.

<->

Smart Adapters

Every node gets an async reverse proxy. Health checks, metrics, hot-swap with drain, and per-request routing -- all built in.

TCP

Multi-Protocol

HTTP, TCP, gRPC, protobuf, and SOAP out of the box. Extensible ProtocolHandler registry for custom protocols.

{ }

Mock Collapse

Auto-generate mock servers from OpenAPI specs. Start fully mocked, slot in services one at a time, collapse back when done.

A|B

A/B Routing

Weighted splits, canary rollouts, header-based routing. Config locking prevents accidental overrides during tests.

%>>

Canary Auto-Promotion

Automated canary evaluation with error rate and latency thresholds. Promotes through weight steps or rolls back.

+/-

Hot-Swap

Replace running services with zero downtime. Drain connections from old instance, start new, switch. Atomic and safe.

!!!

Self-Healing

Custodian monitors health every 5 seconds. Auto-restarts failed services, replaces with mocks, escalates when repairs fail.

~>

Observability

Live dashboard, per-node metrics, request signals, per-path statistics. Prometheus export. JSONL persistence for offline analysis.

<=>

Federation

Multi-cluster heartbeat, cross-cluster state sync, automatic failover and restore. Pull-based peer discovery with configurable thresholds.

TLS

Certificate Management

Monitor TLS certificate expiry with warning and critical thresholds. Auto-rotate certs with zero downtime -- new connections get the new cert.

MCP

AI Integration

Model Context Protocol server exposes circuit state to Claude Code and other AI assistants. Inspect topology, metrics, and signals.

[#]

Image Building

Auto-detect Python or Node runtimes, generate Dockerfiles, build and push container images. Integrated into deploy pipeline.

GCP

Cloud Deploy

Deploy to GCP Cloud Run with --build. Each node becomes a service. Edges auto-wired via environment variables.

***

Security Hardened

Command injection prevention, header injection guards, path traversal protection, fail-closed auth, bounded header parsing.

@#!

Taint Analysis

Seed PII-shaped canary data with traceable fingerprints. Detect when data crosses boundaries it shouldn't -- in traffic, logs, and spans.

?=?

Interface Validation

Services are validated against OpenAPI contracts at slot time. Incompatible services are rejected before receiving traffic.

ARB

Arbiter Integration

Trust scoring, declaration gap analysis, classification tagging on spans, fire-and-forget OTLP forwarding. All optional, gracefully degrading.

LOG

System Logging

Captures service stdout/stderr with automatic severity parsing. Structured logs with node attribution, persisted for audit trails.

LDG

Ledger Integration

Sync egress nodes from Ledger, field masking at the adapter layer, Ledger-sourced mock records for canary testing.

CST

Constrain Integration

Generate baton.yaml from Constrain's component_map.yaml with data access declarations, authority domains, and edge tiers.

///

887 Tests

Hand-written unit tests, integration tests, functional assertions, plus pact-generated smoke tests covering all source modules.

Five minutes to a running circuit

Define your topology, boot with mocks, slot in real services, run A/B tests, federate across clusters.

# Define the circuit baton init myproject baton node add api --port 8001 baton node add service --port 8002 baton node add rpc --port 8003 --mode grpc baton edge add api service baton edge add api rpc # Boot with mocks -- entire circuit in one process baton up --mock # Slot in a real service (mock replaced, zero downtime) baton slot api "python app.py" # A/B test a new version (80/20 split) baton route ab api "python app_v2.py" --split 80/20 # Canary with auto-promotion baton route canary api "python app_v2.py" --pct 10 --promote # Check federation status baton federation status baton federation peers --json # Monitor certificates baton certs status # Taint analysis baton taint seed baton test --canary --tiers PII --duration 5m # Service logs and Arbiter trust baton logs --node api --level error baton trust api # Build images and deploy to GCP Cloud Run baton deploy --provider gcp --build --project my-project

How it works

Baton architecture: baton.yaml defines nodes and edges, runtime creates reverse proxy adapters with slot() for swapping services or mocks, collapse levels from full_mock through partial to full_live

Protocol Support

Mode Description Health Check
http HTTP/1.1 reverse proxy with tracing, circuit breaker, retries HTTP GET to health path
tcp Bidirectional byte pipe TCP connectivity
grpc Transparent HTTP/2 forwarding TCP connectivity
protobuf Length-prefixed binary proxy (4-byte big-endian + payload) TCP connectivity
soap HTTP with SOAPAction header awareness and fault detection HTTP + SOAP fault check

Core Concepts

Circuit

The board. Nodes + edges + contracts. Defined in baton.yaml.

Adapter

Async reverse proxy at each node. Handles routing, health, metrics.

Slot / Swap

Insert or replace a service. Hot-swap drains before switching.

Collapse

Compress circuit. Full mock through partial to full live.

Custodian

Health monitor. Restart, replace, escalate. Self-heals the board.

Routing

Weighted, header, canary. Per-request. Lockable.

Protocol

Pluggable handlers. HTTP, TCP, gRPC, protobuf, SOAP. Extensible.

Federation

Multi-cluster heartbeat, state sync, automatic failover.

Provider

Deployment backend. Local processes or GCP Cloud Run.

Manifest

Service self-description. API spec, mocks, dependencies.

Ingress

Entry point from outside the circuit. First node traffic hits.

Egress

External dependency. Always mocked. Third-party APIs, databases.

Dashboard

Live UI. Node cards, bar charts, signal log, topology. Polls every 2s.

Canary

Auto-promote or rollback. Compares error rate + latency against thresholds.

Certificates

TLS cert monitoring, expiry alerts, zero-downtime rotation.

MCP

AI integration. Exposes circuit state to Claude Code and other assistants.

Taint

Canary data with fingerprints. Detects boundary violations in traffic and logs.

Arbiter

Trust scores, declaration gaps, classification tagging. Optional integration.

Constrain

Generate baton.yaml from component_map.yaml. Data access declarations.

Ledger

Egress node sync, field masking at adapter, Ledger-sourced mock records.

Taint Analysis

Seed PII-shaped synthetic data with embedded fingerprints across the circuit and detect when data crosses boundaries it shouldn't.

Each canary datum (SSN, email, credit card, phone, name) is scoped to a node and its topological neighbors. The taint scanner inspects adapter traffic and service logs in real time. If a canary SSN seeded into user-api appears in a response from analytics, that is a TaintViolation.

# Seed canary data across the circuit baton taint seed baton taint seed --node user-api # Check status and violations baton taint status baton taint violations # Full canary soak test with tier filtering baton test --canary --tiers PII --duration 5m # Canary test with Ledger-sourced mock records baton test --canary --ledger-mocks # Clear all canary data baton taint clear

Opt-in via taint.enabled: true in baton.yaml. Canary data stored in .baton/taint_canaries.jsonl, violations in .baton/taint_violations.jsonl.

Arbiter Integration

Trust-aware slot validation, classification tagging on spans, and fire-and-forget OTLP forwarding. All optional and gracefully degrading.

# Check Arbiter connectivity baton arbiter status # View trust scores baton trust api baton trust stripe # View recent audit events baton audit api

Trust validation -- baton slot checks trust score before accepting. Low-trust authoritative nodes require --force.

Declaration gaps -- compares declared data access against Arbiter's observations.

Classification tagging -- reads x-data-classification from OpenAPI specs, adds baton.request.classifications span attributes.

Span forwarding -- fire-and-forget forwarding to Arbiter's OTLP endpoint with drop rate tracking.

# baton.yaml -- Arbiter configuration arbiter: api_endpoint: "http://localhost:7700" endpoint: "http://localhost:4317" forward_spans: true classification_tagging: true

If Arbiter is unreachable, the circuit runs normally. All Arbiter calls use 2s timeout and degrade gracefully.

Ledger Integration

Sync egress nodes from Ledger, apply field masking at the adapter layer, and use Ledger-sourced mock records for canary testing.

# Sync egress nodes from Ledger baton sync-ledger # Canary test with Ledger mock data baton test --canary --ledger-mocks

Field masking -- adapter applies field masks to JSON response bodies before forwarding. Encrypted-at-rest fields are replaced with [ENCRYPTED].

Egress sync -- baton sync-ledger fetches egress node configs from Ledger's API.

Mock records -- --ledger-mocks uses Ledger-generated mock records for more realistic canary testing.

# baton.yaml -- Ledger configuration ledger: api_endpoint: "http://localhost:7701"

v2 Schema

Version 2 config adds data_access, authority, and openapi_spec on nodes, data_tiers_in_flight on edges, plus arbiter, ledger, and taint sections. Version 1 configs load without modification.

name: myproject version: 2 nodes: - name: api port: 8001 data_access: reads: [PII, PUBLIC] writes: [PII] authority: ["user.*"] openapi_spec: specs/api.yaml - name: stripe port: 8002 role: egress edges: - source: api target: stripe data_tiers_in_flight: [FINANCIAL] arbiter: api_endpoint: "http://localhost:7700" forward_spans: true ledger: api_endpoint: "http://localhost:7701" taint: enabled: true

Command Reference

Full CLI reference. All commands use baton as the entry point.

Topology

baton init [dir] # create baton.yaml + .baton/ baton init --constrain-dir <path> # generate from Constrain component_map baton node add <name> [--port N] # add node (auto-assigns port if omitted) baton node rm <name> # remove node and its edges baton edge add <from> <to> # connect nodes baton edge rm <from> <to> # disconnect nodes baton contract set <node> <spec.yaml> # attach OpenAPI/JSON Schema contract baton status # show circuit topology and health

Service-First Workflow

baton service register <path> # register a baton-service.yaml manifest baton service list # list registered services baton service derive [--save] # derive circuit from manifests baton check [--service <name>] # static API compatibility analysis

Runtime

baton up [--mock] [--services] # boot circuit baton slot <node> <command> # slot live service into node baton swap <node> <command> # hot-swap (zero-downtime replace) baton collapse [--live n1,n2] # partial mock (keep some nodes live) baton watch [--interval 5] # start custodian (health monitor) baton down # tear down circuit baton apply [--dry-run] # converge running state to baton.yaml baton export [--output file.yaml] # export running state as YAML

Routing

baton route show <node> # display routing config baton route ab <node> <cmd> [--split N/M] # A/B split (default 80/20) baton route canary <node> <cmd> [--pct N] # canary rollout (default 10%) baton route canary <node> <cmd> --promote # auto-promote canary baton route set <node> --strategy ... # custom routing config baton route lock <node> # lock routing (prevents slot/swap) baton route unlock <node> # unlock routing baton route clear <node> # remove routing, back to single backend

Observability

baton dashboard [--json] # aggregated metrics table baton dashboard --serve [--port 9900] # launch live dashboard UI baton metrics [--node N] [--last N] # persistent metrics from JSONL baton metrics --prometheus # Prometheus text exposition format baton signals [--node N] [--path P] # recent request signals baton signals --stats # per-path statistics baton logs [--node N] [--level L] # captured service logs

Taint Analysis

baton taint seed [--node N] # seed canary data into services baton taint status # show active canary data and violations baton taint violations # list detected boundary violations baton taint clear # remove all canary data

Arbiter, Constrain & Ledger

baton trust <node> # show Arbiter trust score for node baton audit <node> # show recent audit events baton arbiter status # Arbiter connectivity check baton test --canary [--tiers T] # canary soak test baton test --canary --ledger-mocks # canary test with Ledger mock data baton init --constrain-dir <path> # generate from Constrain component_map baton sync-ledger # sync egress nodes from Ledger

Federation & Certificates

baton federation status [--json] # show federation config and cluster identity baton federation peers [--json] # list peer clusters and their state baton certs status [--json] # show TLS certificate info and expiry baton certs rotate # force certificate rotation

Images & Deployment

baton image build [--node N] [--path P] # detect runtime, generate Dockerfile, build baton image push [--node N] [--tag T] # push image to registry baton image list # list built images baton deploy [--provider local|gcp] # deploy circuit baton deploy --provider gcp --build # build images + deploy to Cloud Run baton teardown [--provider local|gcp] # tear down deployment baton deploy-status [--provider ...] # check deployment status

Config Migration

baton migrate-config # migrate baton.yaml v1 -> v2 in place baton migrate-config --config <path> # migrate a specific file baton migrate-config --output <path> # write to a different file baton migrate-config --dry-run # print migrated config without writing

Self-Healing

The custodian monitors adapter health via TCP probes every 5 seconds with a three-stage escalation.

Stage 1: Restart

3 consecutive failures -- restart the service process.

Stage 2: Mock Replace

6 consecutive failures -- replace with mock (503).

Stage 3: Escalate

Still failing -- mark faulted, log for manual intervention.

When a service recovers, the custodian automatically resets its status. Two-phase repair (research-backed): fault classification and recovery selection are orthogonal decisions.