@handlebar/core is the framework-agnostic foundation that all Handlebar adapters build on. If your agent framework doesn’t have a pre-built adapter, or you’ve built a custom agent loop, you can wire Handlebar in directly with a handful of function calls.
This guide covers the full integration - from initial setup through tool governance, LLM event logging, and per-user enforcement.
Installation
The client - initialise once
HandlebarClient is a long-lived object that manages agent registration, rule fetching, and audit event delivery. Create it once at application startup, not per-request.
Handlebar.init is async because it registers the agent with the Handlebar API and fetches its configured rules. Everything else waits on this internally - you can await hb.ready() if you need to be certain registration is complete before proceeding, but it is not normally required.
Init options
Runs - one per agent invocation
A run represents a single agent invocation from start to finish. It carries the run ID, tracks tool call history and token usage, and emits audit events throughout its lifetime. Create a run at the start of each request and end it when the agent finishes.run.end() flushes all pending audit events before returning, so the process can exit cleanly immediately after.
End statuses
Lifecycle hooks
Lifecycle hooks are the calls you make onrun as your agent progresses. They are the primary integration surface - each one corresponds to a phase of the agent loop.
Before a tool executes
Decision.
Decision shape:
BLOCK + CONTINUE means the tool should be skipped but the agent loop can continue - the blocked message is typically returned to the LLM so it can respond gracefully.
BLOCK + TERMINATE means the run should stop entirely. Throw an error that propagates up through your agent loop, catch it at the top level, and call run.end("interrupted").
After a tool returns
tool.after rules (e.g. inspecting output content or checking data exfiltration patterns).
afterTool also returns a Decision (evaluated at the tool.after phase). Most integrations do not need to act on it, but you can check decision.verdict if you want to apply post-execution governance.
Before an LLM call
message.raw.created audit events for each message, enabling full conversation logging on the platform.
beforeLlm is optional - skipping it means conversation content won’t appear in audit logs, but tool governance still works fully.
After an LLM call
llm.result event.
beforeLlm, this is optional but enables token-based budget enforcement and spend tracking on the platform.
Wiring it all together - a minimal agent loop
Passing the run through async contexts
If your tool implementations live in separate modules and can’t receiverun as a parameter, use withRun to bind the run to the current async context. Any code running inside the callback can then retrieve it with getCurrentRun().
@handlebar/langchain, @handlebar/ai-sdk-v5) work internally - they bind the run in withRun at the executor level, so tool wrappers don’t need an explicit reference.
Tool metadata - tags
Tool tags are string labels that describe a tool’s nature or capability class. You attach them to tools at registration time and pass them through on everybeforeTool / afterTool call.
Tags are what allow you to write rules that apply to groups of tools rather than individual ones - for example: “block any external-write tool after 11pm”, or “require human review for any pii-access tool when the user is on the free tier”.
Registering tools with tags
Declare tools and their tags at init time so the Handlebar platform knows about them:Passing tags on each call
Pass the same tags tobeforeTool and afterTool so the rule engine has full context at evaluation time:
Actor - per-user enforcement
The actor is the end user or system identity the agent is acting on behalf of during a run. Providing it enables Handlebar to enforce per-user rules - for example: rate limiting a single user’s tool usage, applying stricter data controls to users tagged"region:eu", or capping spend per user tier.
Pass the actor when starting the run:
Full actor schema
Using metadata for group-based rules
Metadata is where per-user and per-group rule conditions come from. For example, attaching{ tier: "free", region: "eu" } lets you write rules like “block pii-access tools for free-tier users” or “require human review for any write tool when region is eu”.