Show HN: BoundFlow – an open-source control plane for AI agents BoundFlow, an open-source control plane for AI agents, enforces cost caps, approval gates, and self-healing policies on unattended LLM workflows. The backend is Apache-2.0 licensed and self-hostable, with a Python SDK available, and offers a managed cloud option in early access. The operational layer for the LLM agents and workflows you run unattended — cost caps, approval gates, and self-healing policy, enforced by a control plane. Important Public preview pre-1.0 . The engine is complete and covered by Go, mock-LLM, and live-LLM test suites, but it hasn't yet been run in production with external users. APIs — including the gRPC protobufs — may change before 1.0. We're looking for early adopters and design partners: reach out mailto:hello@boundflow.dev . BoundFlow runs long-running, stateful agent workflows and enforces the guardrails you'll want before running agents unattended: per-run cost caps , automatic model switching on cost/loop policies, human approval gates before sensitive actions, tool-call limits, retries, cooldowns, and versioned rollbacks. You write agents and workflows against a clean async SDK; the control plane schedules, dispatches, and governs them. Inference is bring-your-own — your agents call Claude with your own Anthropic key, running in your worker. The backend never sees it and never pays for tokens. Your keys, your data, and your token spend stay on your side of the wire. In practice: a support-triage workflow that may spend up to $0.25/run , must get a human's sign-off before issuing a refund, downgrades to Haiku when costs spike, and auto-rolls-back to the last good version if it starts failing — none of that logic living in your agent code. You declare it as policy; the control plane enforces it and keeps a durable, queryable audit log of every approval and policy decision. BoundFlow is not a prompt framework, an inference provider, or an agent-builder — it's the operational layer around the agents you build. Backend — open source Apache-2.0 , self-hostable as a container. Python SDK — open source MIT , pip install boundflow . Docs — concepts, governance, deployment, and API reference in. docs/ BoundFlow Cloud — prefer not to self-host? Managed hosting early access — see below hosted-boundflow-cloud . Agents that take real actions need a control plane that takes real action when they go wrong. Most tools watch your agents; BoundFlow intervenes — at both levels. On the agent : cap its spend, swap its model mid-run. On the workflow : gate a risky step for human sign-off, cool it down, roll it back to a known-good version, or pause it outright. It's workflow-aware, not just agent-aware — because it runs the whole workflow, not just the model call: scheduling each run, carrying state across steps, recovering from failures, and driving it through its lifecycle, with the agent as just one operation inside a durable, multi-step process it owns end to end. The moment agents run unattended you need answers to: What if it loops? What if it spends $50? What if it's about to do something irreversible? Which model should it use, and when should that change? BoundFlow makes those policies instead of code: | Concern | BoundFlow gives you | |---|---| | Runaway cost | A hard max cost usd cap that halts a run the moment its cost crosses budget | | Irreversible actions | Approval gates — the workflow parks for a human decision before it acts | | Loops & output blowups | Runtime limits: max llm calls , max tokens per call , per-tool call caps | | Wrong model for the job | Agent lifecycle policy — react to signals over the agent's entire life e.g. downgrade a costly model to a cheaper one past a certain budget | | Degrading or failing workflows | Self-healing lifecycle policy — cool down, pause, or auto-roll-back to a known-good version | | Flying blind | OpenTelemetry-native run traces shipped to your stack Jaeger, Tempo, Langfuse, … , plus a durable, queryable audit log of every approval and policy decision | | Your keys & token spend | Bring-your-own inference — agents call Claude with your key; the backend never sees it or pays for tokens cache-aware, per-tenant cost | Policies are evaluated server-side lifecycle and enforced SDK-side runtime , with per-invocation metrics — cost, tokens, LLM calls, per-tool counts/failures — collected on every run. The BoundFlow backend is the control plane — self-host it, or run it on BoundFlow Cloud. Either way, your worker connects to it over gRPC and runs the actual agents, with your Anthropic key, in your environment; the backend schedules, dispatches, governs, and audits, and never sees your key or your inference traffic. ┌─────────────────────┐ gRPC ┌────────────────────────┐ │ Your client / SDK │ ───────────────▶ │ │ └─────────────────────┘ invoke·approve │ BoundFlow backend │ ·query │ control plane │ ┌─────────────────────┐ gRPC stream │ │ │ Your worker │ ◀──────────────▶ │ schedules·dispatches │ │ runs agents+tools │ launch/result │ ·governs·audits │ │ with your API key │ └────────────────────────┘ └─────────────────────┘ Under the hood the backend runs as three process modes server , scheduler , worker off one binary sharing Postgres — see docs/concepts.md for the full breakdown and the lifecycle states. python 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 Bring your own provider via LangChain. Wrap any tool-calling LangChain chat model in LangChainLlmClient and the governance is identical — OpenAI, Google, Bedrock, and the rest of LangChain's ecosystem run under the same cost caps, model policies, and approval gates: python from langchain anthropic import ChatAnthropic or ChatOpenAI, ChatVertexAI, ... from boundflow.langchain client import LangChainLlmClient worker = BoundFlowWorker llm=LangChainLlmClient ChatAnthropic model="claude-haiku-4-5" Install with pip install "boundflow langchain " ; see boundflow.examples.langchain adapter /boundflow/boundflow/blob/main/sdk/python/boundflow/examples/langchain adapter.py for a runnable end-to-end example. Orchestrate with LangGraph, governed by BoundFlow. Build a LangGraph agent graph inside a workflow with its nodes calling ctx.run agent , so LangGraph owns the routing while BoundFlow governs every agent step and the workflow as a whole. See Integrations /boundflow/boundflow/blob/main/docs/integrations.md and the runnable boundflow.examples.langgraph workflow /boundflow/boundflow/blob/main/sdk/python/boundflow/examples/langgraph workflow.py . Workflows are multi-step and stateful : an operation can park for a human decision or chain into a follow-on operation, and the workflow resumes where it left off — nothing irreversible runs until the branch it's gated behind does. python from boundflow import AwaitApproval, Next, Complete @worker.workflow "refund", version=1 async def refund ctx : await ctx.run agent analyst step 1: reason about the request return AwaitApproval park — nothing irreversible yet on approve=Next "issue refund", ctx.context , on reject=Complete , justification="Approve the $5,000 refund?", @worker.operation "refund", "issue refund" step 2: runs only after a human approves async def issue refund ctx : ... the sensitive action, now sanctioned return Complete Governance is applied from the control plane — three layers, from a per-run cap to self-healing version rollback: python from boundflow import RuntimePolicy, AgentRule, AgentMetric, Op, SetModel, WorkflowRule, WorkflowMetric, SetVersion, 1. Runtime — a hard cap enforced during every run: await cp.set agent runtime policy wf.id, "analyst", RuntimePolicy max cost usd=0.25 2. Agent lifecycle — after runs, downgrade the model if cost trends high: await cp.set agent lifecycle policy wf.id, "analyst", AgentRule metric=AgentMetric.COST USD, op=Op.GT, threshold=0.20, window=5, action=SetModel value="claude-haiku-4-5" , 3. Workflow lifecycle — after repeated failures, roll the whole workflow back to a known-good version automatically: await cp.set workflow lifecycle policy wf.id, WorkflowRule metric=WorkflowMetric.NUM FAILURES, threshold=3, action=SetVersion target=1 , Workflow rules can also Pause a workflow or put it on Cooldown instead of rolling back. See sdk/python/boundflow/examples/ /boundflow/boundflow/blob/main/sdk/python/boundflow/examples for runnable examples. Get a governed agent running in a few minutes. Full walkthrough: QUICKSTART.md . 1. Set a database password any strong secret echo "BOUNDFLOW DB PASSWORD=$ openssl rand -hex 16 " .env 2. Start the backend Postgres + server + scheduler + worker docker compose -f docker-compose.dist.yml up -d 3. Provision an API key docker compose -f docker-compose.dist.yml run --rm server -mode=provision -name=me export BOUNDFLOW API KEY=