Concepts¶
Core objects¶
- Workflow — the managed entity. Belongs to a tenant, has a type + version,
and moves through lifecycle states (
active → scheduled → invoking → awaiting_approval → …). - Agent — a named LLM executor inside an operation handler: a model, system prompt, tool callbacks, and an output schema. Metrics are collected per run.
- Approval gate — a workflow can pause mid-execution for a human to approve or reject a proposed action before continuing.
- Runtime policy — hard limits enforced during a run (max LLM calls, max tokens/call, per-tool limits, max cost).
- Lifecycle policy — rules evaluated after runs, on aggregated metrics: switch model, cool down, roll back a version, pause.
Lifecycle states¶
A workflow's lifecycle_state is a projection of its in-flight run:
| State | Meaning |
|---|---|
active |
Idle — no run in flight. |
scheduled |
A run is queued, waiting for a worker to pick it up. |
blocked |
A queued run has sat unowned past the threshold — nobody picked it up. |
invoking |
A worker is actively executing the operation. |
awaiting_approval |
Parked at an approval gate for a human decision. |
interrupted |
A platform failure (e.g. a lost worker mid-operation) interrupted the run; the workflow is disabled until resolved. |
Customer-side failures (an uncaught exception in your handler, or an operation
timeout) are soft — they count against the workflow's failure metric but leave
it active. Only platform interruptions disable a workflow and require
resolve_interrupted_workflow.
Architecture¶
The control plane runs as three process modes off one binary, sharing a Postgres database. Your SDK worker connects over gRPC and runs the actual agents.
┌────────────────────┐ gRPC ┌──────────────────────┐
│ Your client │ ─────────────────▶ │ server :50051 │
│ (ControlPlane- │ │ workflow lifecycle, │
│ Client) │ │ approvals, pricing │
└────────────────────┘ └──────────┬───────────┘
│ Postgres
┌──────────▼───────────┐
│ scheduler │
│ polls due requests, │
│ writes jobs, │
│ evaluates lifecycle │
└──────────┬───────────┘
│ Postgres
┌────────────────────┐ gRPC stream ┌──────────▼───────────┐
│ Your worker │ ◀───────────────── │ worker :50052 │
│ (BoundFlowWorker) │ launch / result │ dispatches jobs to │
│ runs agents+tools │ │ connected SDK workers│
└────────────────────┘ └──────────────────────┘
| Mode | Responsibility |
|---|---|
server |
gRPC API: workflow/tenant lifecycle, approval flow, policy + pricing configuration. |
scheduler |
Partition-based scheduler. Polls due requests, writes jobs, runs lifecycle policy evaluation (cooldown, version rollback). |
worker |
Polls for pending jobs and dispatches them to connected SDK workers over a bidirectional gRPC stream. |
migrate / provision |
One-shot modes: apply schema migrations / mint a tenant group + API key. |
SDK at a glance¶
from boundflow import AgentDefinition, BoundFlowWorker, Complete, ControlPlaneClient, WorkflowConfig
from boundflow.anthropic_client import AnthropicLlmClient
worker = BoundFlowWorker(llm=AnthropicLlmClient(...)) # endpoints + key from env
@worker.workflow("triage", version=1)
async def triage(ctx):
ctx.add_context("ticket", "...")
await ctx.run_agent(AgentDefinition(
name="analyst", model="claude-haiku-4-5",
system_prompt="Diagnose the issue.", output_schema={"summary": {"type": "string"}},
))
return Complete()