This chapter has six steps. Follow them in order.Documentation Index
Fetch the complete documentation index at: https://docs.getbindu.com/llms.txt
Use this file to discover all available pages before exploring further.
Step 1 - What you need
You need two things before starting. You may already have them; skim and decide.Node.js 22+
The gateway is TypeScript; we run it with
tsx, no separate build step.OpenRouter API key
Paid proxy to dozens of models. The gateway uses it for the planner LLM.
Checking Node
Checking Node
Getting an OpenRouter key
Getting an OpenRouter key
Sign up at openrouter.ai, add a few dollars of credit, and copy the key from the API section. It looks like
sk-or-v1-<long random string>.No database required. The gateway is stateless — it holds per-request state in memory for the lifetime of each
/plan call and drops it when the call ends. The calling client owns durable history: pass prior turns in the history field and the latest compaction summary in prior_summary on the next call. Old releases required Supabase; that’s gone.Step 2 - Get the code and install
Step 3 - Configure the gateway
Creategateway/.env.local from the template:
gateway/.env.local
examples/.env (used by the sample Python agents - the file already exists, you just add the key):
examples/.env
What’s a “bearer token”?Think of
GATEWAY_API_KEY like the password on a movie ticket booth. Whoever holds this string can ask the gateway to do work on their behalf. The gateway checks it on every request by hashing both sides and comparing the hashes in constant time (so neither a timing nor a length attack can recover the token). Don’t paste it into chat apps or commit it to a public repo. Rotate it when you suspect it leaked.You may notice old
SUPABASE_URL / SUPABASE_SERVICE_ROLE_KEY lines in .env.example. Leave them blank — the gateway no longer reads them. See gateway/src/config/loader.ts:110 for the explicit removal note in the code.Step 4 - Start one agent
Open a terminal. Start the joke agent — one Python file that answers with jokes. We pin the port to 3773 withBINDU_PORT so it matches the next chapter’s fleet layout (the file’s own default is 5773):
bindufy setup logs. The last line you should see is:
Step 5 - Start the gateway
In a second terminal:The “no DID identity configured” line is expected for now. The DID signing chapter turns on cryptographic signing.
session mode: stateless is the only mode in the current gateway — the mode field is kept on the schema for forward-compat but stateful is rejected at boot. Leave this terminal running too.Step 6 - Ask a question
In a third terminal, load your gateway token into the shell so you don’t have to copy-paste it every time:agent_did, agent_did_source, and signatures are elided for readability — they’re documented in the Gateway API reference):
Reading the output line by line
That format is called Server-Sent Events (SSE). It’s plain HTTP, but the server keeps the connection open and writes events one at a time instead of sending one big response at the end. Two parts per event: a label (event: session) and a JSON payload (data: {...}).
What each event means, in the order they arrived:
| # | Event | What it means |
|---|---|---|
| 1 | session | The gateway opened an in-memory session for this /plan call. session_id is a per-call handle; external_session_id echoes whatever the client sent (or null). Since the gateway is stateless, this id is not a resumption key — to give the planner context across requests, pass prior turns via the history field on each call. |
| 2 | plan | The planner started its first turn. |
| 3 | task.started | The planner decided to call the joke agent. input: {input: "..."} is what it’s sending. |
| 4 | task.artifact | The agent replied. The text inside <remote_content> is the real answer. That envelope is there so the planner (and you) remember this is untrusted data. The verified attribute takes one of four values — yes, no, unsigned, unknown — and is unknown here because the request didn’t ask the gateway to verify peer signatures. Verification is opt-in per peer via the agent’s trust.verifyDID: true flag (with an optional trust.pinnedDID) — it is independent of auth.type, which controls how the gateway authenticates outbound to the peer. Once trust.verifyDID is on, the label becomes yes (signed and verified), no (signature mismatch), or unsigned (the peer didn’t sign). |
| 5 | task.finished | That call is complete. |
| 6 | text.delta (many) | The planner is now writing its own final answer, streamed a word or two at a time. Concatenate them in order (they all share a part_id). |
| 7 | final | Done. stop_reason: "stop" means “natural end”. usage reports token counts for billing. |
| 8 | done | Last event. Close the connection. |
| Event | When | Meaning |
|---|---|---|
compaction-summary | Mid-stream, zero or one per call | The planner ran out of context window, compacted history into a summary. Persist the summary field client-side and ship it back as prior_summary on the next /plan call. |