Skip to content

tulip agents · the agent framework where control is native

Agents that act. Safe by construction.

Tulip is a complete open-source agent framework — one Agent class, tools, durable memory, RAG, eight multi-agent shapes, streaming, typed events — with one hard rule: the model never holds the trigger. The agent decides to act — issue the refund, ship the deploy, change the account — and the action runs only after your policy clears it, in code the model can't reach.

The breadth is why the rule holds. You can only choose the shape, check the claim, and gate the action if you own the loop all three happen in — so Tulip ships the whole loop. See the framework surface.

pip install "tulip-agents[anthropic]"
from tulip import Agent, tool

@tool
def search_flights(
    origin: str, dest: str, date: str
) -> list[dict]:
    "Find flights between two cities."
    return flights.search(origin, dest, date)

# A model is a string; a tool is a function.
agent = Agent(
    model="anthropic:claude-sonnet-4-6",
    tools=[search_flights],
    system_prompt="You are a travel agent.",
)

print(agent.run_sync(
    "Cheapest flight Lisbon to Berlin Friday?"
).text)

Control in the core

A model can be brilliant and still be talked into the wrong action. That's a control problem, not an intelligence problem — so Tulip puts the control in code the model can't reach:

  • The agent loop is where the work happens — reason, act, observe, repeat — with reflexion, grounding, interrupts and budgets built in.
  • GSAR scores every claim against typed evidence — below threshold the agent regenerates or abstains, never guesses.
  • The admission gate clears every side-effecting call: admit() allows it, holds it for a human, or denies it — and records the decision either way, on a trail where editing any entry breaks verify().
from tulip.control import (
    Action, AuditTrail, ControlPolicy, admit, AdmissionError,
)

policy = ControlPolicy(require_human_for={"production"})
trail = AuditTrail()

async def safe_refund(order_id: str, usd: float):
    try:  # the gate runs before money moves
        return await admit(
            Action(name="refund", asset=order_id,
                   kind="payment", environment="production"),
            lambda: payments.refund(order_id, usd),
            policy=policy, trail=trail,
        )
    except AdmissionError:
        return "Held for a human — not run."

A prompt rule is advisory — the model can be argued out of it. The gate is structural — the wrong action isn't caught in a filter, it never runs. How this compares to prompt rules and guardrails →

What you get

  • A real agent framework


    One Agent class — tools, memory, RAG, streaming — over vendor-neutral backends. Swap models with a string.

  • Shapes as tools


    fan_out, debate, plan_and_verify, code_until_tests_pass — the loop calls them when it has a reason to, not before it starts.

  • Multi-agent workflows


    Sequential, parallel, loop, graph, orchestrator, swarm, handoff, and cross-process A2A — one Agent class, one event stream.

  • Grounded by construction


    ground_finding() emits a typed result only above the GSAR threshold — else an auditable Abstention, never a guess.

  • Gate + human-in-the-loop


    require_human_for pauses the actions that matter and resumes on a human's decision. Approvals survive restarts.

  • Audit trail by default


    Every call, verdict, and approval is a typed, hash-chained event — verify() fails on any edit. Replay any run.

Build it across any domain

Every example is a single self-contained file under examples/ with a matching docs page.

You're building… Start here
A support / ops agent that acts human-in-the-loop approvals · incident response
An agent on your own data (RAG) RAG basics · RAG agents
A multi-agent workflow swarm / war-room · supervisor + critic
An agent that acts on approval procurement approval · human-in-the-loop
A security / AI-safety agent GSAR grounding · injection guardrails

Full catalog → Notebooks index · Capabilities matrix · API reference

When Tulip is overkill

If your agent only reads and summarizes, you may not need an admission gate yet — the control layer earns its keep the moment an action can cost something.

Start building

pip install "tulip-agents[openai]"

Get started → Why Tulip →


The open-source agentic harness — control the action, prove what it did. Safe by construction. Apache-2.0.