Handler Patterns
The handler is the only code you write. Everything else — identity, auth, protocol, storage — lives in the sidecar. So let’s start with the different shapes a handler can take.Simple Response
The simplest possible handler returns a string. The sidecar wraps it in an A2A response, signs it with your DID, and sends it back to the caller.OpenAI SDK
Most agents will call an LLM. Here is the pattern with the OpenAI SDK — you receive the conversation history, pass it to the model, and return the result.LangChain.js
If you prefer LangChain, the pattern is the same — only the LLM client changes. The sidecar does not care which framework you use inside the handler.Error Handling
If your handler throws, the SDK catches it and returns a gRPC error.ManifestWorker marks the task as failed. You do not need to build your own error plumbing — just let exceptions propagate naturally.
State Transitions
Sometimes a single response is not enough. Your handler can return two kinds of things: a string (which completes the task) or an object that tells the core to keep the conversation open.Multi-Turn Conversation
Instead of returning a simple string, return an object withstate: "input-required". This pauses the task and prompts the user for more information. When they reply, your handler is called again with the full conversation history.
The Response Contract
Everything downstream depends on this contract. The transport can change, but the return types cannot.| Handler returns | ManifestWorker does | Task state |
|---|---|---|
"The capital of France is Paris." | Creates message + artifact | completed |
{"state": "input-required", "prompt": "Can you clarify?"} | Creates message, keeps task open | input-required |
{"state": "auth-required"} | Creates message, keeps task open | auth-required |
Adding Payments
If you want to charge for your agent’s responses, add anexecution_cost to the config. The sidecar handles the x402 payment protocol — your handler code does not change at all.
Configuration
Thebindufy() config object is how you tell the sidecar what kind of microservice to build around your handler. Most fields are optional — the only required ones are author, name, and deployment.
Skills
Skills describe what your agent can do. The sidecar reads them during startup and includes them in the agent card so other agents and clients can discover your capabilities.File-Based (Recommended)
Point to directories containingskill.yaml or SKILL.md files. The SDK reads them and sends the content to the core during registration.
Inline
You can also define skills directly in the config if you prefer to keep everything in one file.Types
The SDK exports the key types your handler works with. These are the shapes you will see most often.What Happens When You Call bindufy()
Now that you know how to write handlers, let’s look at what happens when bindufy() runs. You do not need to know this to use Bindu — but understanding the lifecycle makes debugging easier and gives you a clearer mental model of the system.
How the Bridge Works Under the Hood
If you are curious about what happens between the core receiving a message and your handler being called, this section explains the internal bridge. You do not need this to build agents, but it helps if you are debugging transport issues or building a Custom SDK.The GrpcAgentClient
Inside the core, one component keeps the sidecar model elegant:GrpcAgentClient. It is a Python class that behaves like a function. ManifestWorker calls it the same way it would call a native Python handler:
manifest.run is a wrapper around the developer’s handler function. For a gRPC agent, manifest.run is assigned a GrpcAgentClient instance. When ManifestWorker executes it, Python invokes GrpcAgentClient.__call__(), which transparently makes the gRPC call across the boundary.
That is the design win. The sidecar changes the transport, not the downstream architecture. ResultProcessor, ResponseDetector, and ArtifactBuilder all work exactly the same way regardless of whether the handler is local or remote.
How It Works
Three steps: ensure connection, call the SDK, convert back. That is the entire bridge.When It’s Created
The bridge gets attached during registration. After this point, every task for the agent flows through it.Connection Lifecycle
The client connects lazily — the gRPC channel is created on the first call, not during initialization. That avoids connection errors during registration if the SDK server is not fully ready yet. When the SDK disconnects (Ctrl+C, crash), the nextHandleMessages call fails with grpc.StatusCode.UNAVAILABLE. ManifestWorker’s existing error handling catches this and marks the task as failed.
Health Checks and Capabilities
The core can also ask the sidecar whether the driver is still healthy:The Full Message Path
To tie everything together, here is the complete path for one message — from the outside world to your code and back:Debugging
When something goes wrong, it usually helps to inspect each half of the sidecar separately. Check the core first (is it running?), then test the endpoint directly.Check Core Logs
Test the Agent Manually
Port Conflicts
Limits to Keep in Mind
gRPC Overview
Review the sidecar architecture and current limits
API Reference
Look up services, messages, ports, and config details