Plugins
A plugin extends or integrates with bread. Add plugins to config.plugins; bread runs their lifecycle and merges their contributions on start(). First-party plugins with their own doc pages: otel · ag-ui · MCP client · MCP server · auth.
Model providers are a config-level seam, not a plugin one — see agents.md#providers.
// bread.config.ts
import { otel } from '@breadai/otel'
import { agUi } from '@breadai/protocol-ag-ui'
export default defineConfig({
entrypoints: ['researcher'],
plugins: [otel(), agUi()],
})The BreadPlugin interface
interface BreadPlugin {
name: string
init?(bread: BreadInstanceRef): Promise<void>
close?(): Promise<void>
hooks?: Partial<BreadHooks> // global beforeRun/afterRun/onError/onSuspend
agents?: Record<string, AgentDefinition> // pre-built agents
tools?: ToolDefinition[] // global tools
resolveAgentTools?(agentId: string, cfg: AgentConfig): Promise<ToolDefinition[]> | ToolDefinition[]
middleware?: (app: unknown) => void // register server middleware
routes?: (app: unknown) => void // register HTTP routes
}Storage is configured directly via
storeinBreadConfig— see store.md — not through plugins.
What each field does
init/close— lifecycle.initreceives aBreadInstanceRefso the plugin canbread.on('crumb', …).closeruns onstop().hooks— the sameBreadHookseveryBreadConfig.hooksimplements (see agents.md#hooks), merged into the global tier of every scope's hook chain (agent, task, and tool runs alike) — plugins run after the scoped hook but beforeBreadConfig.hooks, inconfig.pluginsregistration order. This is the supported way for a plugin to observe or react to every run without the caller wiring anything — an observability plugin watching for failures, for instance, uses this instead ofbread.on('crumb', …).agents— pre-built agents the plugin contributes to the registry.tools— global, static tools. Collected onstart()and merged into every agent's tool set (alongside the agent's own tools and skills), so a plugin can expose a capability to all agents at once. See tools.md.resolveAgentTools— the dynamic counterpart totools: called once per agent during tool assembly, given that agent's full config, so a plugin can contribute tools driven by something the agent itself declared (rather than every agent getting the same static set). Core never inspects what an agent puts undercfg.plugins.<your-plugin-name>— that key is entirely yours to define and read back inside this hook. Returned tools get the sameplugin:<your-plugin-name>/<tool>provenance and permission treatment as statictools, including the collision check if a name clashes.@breadai/protocol-mcp-clientis the reference implementation — it readscfg.plugins.mcp_clientto resolve MCP servers a specific agent asked to connect to.middleware— register middleware on the server's Hono app, applied before any routes (this plugin's own or another plugin's) so it can wrap everything downstream regardless of plugin registration order. Typed asunknownfor the same reason asroutesbelow. Auth is the motivating case —@breadai/server'sauthPlugin()builds aBreadPluginwhosemiddlewaregates every request — but the mechanism is fully generic; any plugin can use it (rate limiting, CORS, request logging, …). See auth.md.routes— register extra HTTP routes on the server's Hono app (e.g.@breadai/protocol-mcp-server's HTTP exposure). Typed asunknownso core stays Hono-free; the CLI server passes the realHono. CallregisterHttpRoutefrom@breadai/corefor each one. A route left unnamed is403when auth is on. See auth.md.
Writing a plugin
import type { BreadPlugin } from '@breadai/core'
export function metrics(): BreadPlugin {
let count = 0
return {
name: 'metrics',
async init(bread) {
bread.on('crumb', (c) => {
if (c.type === 'agent:run:end') count++
})
},
async close() {
console.log(`[metrics] ${count} runs`)
},
}
}Protocols vs. extensions
First-party plugins are split across two workspace folders — a naming/discovery convention, not a second plugin mechanism; both implement the same BreadPlugin interface above:
protocols/(@breadai/protocol-ag-ui,@breadai/protocol-a2a-server,@breadai/protocol-mcp-client,@breadai/protocol-mcp-server) — adapters for a specific wire protocol (AG-UI, A2A, MCP).extensions/(@breadai/otel,@breadai/a2ui) — everything else that attaches as aBreadPlugin: observability, UI generation. (@breadai/auth-api-key/-jwt/-oauth2/-trustedalso live underextensions/but are standaloneBreadAuthStrategy/BreadSignerfactories, notBreadPlugins themselves — wrap one withauthPlugin()from@breadai/serverto attach it, see auth.md.)
See architecture.md for the full five-family package map.
Publishing
The whole project lives under the @breadai/ scope — the core runtime and tooling (@breadai/core, @breadai/server, @breadai/cli) alongside plugins (e.g. @breadai/foo). Export a factory function that returns a BreadPlugin.

