How-To Guides
Events
While a turn runs, middleware and tools push events to env[:events] — a sink you can stack handlers onto for live progress. By default it’s a null sink that swallows everything; add the EventHandler middleware to route events somewhere.
Turning it on
Section titled “Turning it on”Brute.agent .use(Brute::Middleware::EventHandler, handler_class: Brute::Events::TerminalOutput) # ... rest of the stack ...EventHandler wraps env[:events] in your handler class on the way in, so everything downstream streams through it.
The events
Section titled “The events”Events are { type:, data: } hashes. The common types:
| Type | Emitted when | data |
|---|---|---|
:content |
assistant text streams/arrives | the text |
:reasoning |
thinking/reasoning text | the text |
:tool_call_start |
the model calls tools | array of { name, call_id, arguments } |
:tool_result |
a tool finishes | { name, content } |
:error |
a tool raises | { error, message } |
Writing a handler
Section titled “Writing a handler”Handlers are stackable: subclass Brute::Events::Handler, override <<, do your thing, then call super to pass the event down the stack (or don’t, to swallow it). Brute::Events::TerminalOutput dispatches each event to an on_<type> method:
class MyHandler < Brute::Events::Handler def <<(event) case event.to_h[:type] when :tool_call_start event.to_h[:data].each { |tc| warn "→ #{tc[:name]} #{tc[:arguments]}" } when :content print event.to_h[:data] end super # pass down to the inner handler endend
Brute.agent.use(Brute::Middleware::EventHandler, handler_class: MyHandler)Because handlers stack, you can layer several — say, terminal output plus a JSONL logger — by nesting EventHandler middleware. Each wraps the sink the previous one installed.
Terminal output
Section titled “Terminal output”Brute::Events::TerminalOutput is the batteries-included handler used by the examples: it streams assistant content to stdout, prints [tool] name - args when tools start and [tool] name - done when they finish, indents reasoning to stderr, and formats errors. It’s a good template to copy for a custom UI.