Mental model
Three nouns cover almost everything in pkg/bb.
- A Flow runs one or more agents over an incoming chat, collects their replies, and hands the result to the next flow.
- Flows compose: a group of flows is itself a flow (
Select,All,One,Group), andNextchains them into a longer flow. - An Agent is build-time configuration (model, role, schema, handler). It cannot act on its own.
- A Turn and a ModelChat are the agent live on one message — the two handles an
OnMessagehandler receives.turnfaces the client (Reply/Stream/Call/Select);chatfaces the model (Add/Ask/Resolve). Neither can reconfigure the agent — the compiler enforces both splits, so an invalid state (a builder that asks, a running turn that changes its model) is unrepresentable.
The smallest brain
func main() {
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt)
defer stop()
bb.WithModel(bb.NewModel().WithName("gpt-4o-mini")).WithTag("chat")
agent := bb.NewAgent(). // no model: inherits the flow's / the default
WithRole(bb.Role("You are a terse assistant."))
flow := bb.NewFlow().WithModel(bb.NewModel("chat")).WithAgent(agent)
bb.Serve(ctx, flow) // OpenAI + Anthropic at :8080
}A default (no-OnMessage) agent just asks the model with the incoming chat and replies — forwarding the caller's tools and relaying the model's tool calls untouched, so it behaves exactly like the model behind it. That is the whole walking skeleton; everything else in these docs is what you add to it.
Two handles, two directions
An agent mediates two opposite conversations — the client that called your brain, and the model your brain calls — and the same nouns (a message, a tool call, a tool result) flow both ways. So they are kept as separate objects, and which one you touch says which direction you mean:
turn bb.Turn — the client side | chat bb.ModelChat — the model side | |
|---|---|---|
| read | Messages, Last(), Request(), ToolResults() | Messages() |
| write | Reply, Stream, Call | Add, WithTools, ForwardTools, WithToolChoice |
| act | Select | Ask, AskWith, Resolve |
chat.Ask asks the model; turn.Reply answers the client. chat.Add builds the prompt; turn.Call asks the client to run something. Neither can reconfigure the agent — there are no With… methods for that on either handle, so runtime self-modification stays impossible by construction.
This split is the single idea to hold onto before reading the rest of the concept pages — every API in pkg/bb is an instance of "which side of the conversation is this for."
Continue to Flows, agents & turns for the full API surface built on top of this model.