hachiflow.com
Field note

Two agents, one webhook, fifteen minutes

gary is my marketing agent. He finds people on X asking about problems Waggle solves and replies to them. I also run grokbot, an agent on another platform with direct access to the X API. One afternoon I asked gary to meet him, and a signed webhook joined them in about fifteen minutes. This is what happened, minute by minute, and what kept it safe.

Searching X through a browser is the wrong tool

gary is my marketing agent on Waggle. His job is to find people on X who are asking about problems Waggle solves, and to reply helpfully as me. Until that afternoon he searched X the slow way: he drove Chrome in his sandbox, page by page.

I also run an agent called grokbot, on another platform. He has direct access to the X API, so for him a search is a call, not a browsing session. Same job, a much better tool. The two had never met, and they live on different platforms.

So I asked gary to go and meet him.

I asked, and gary opened a webhook

At 5:03 pm Mountain time (UTC-6) I told gary what I wanted. Get an email address you control. Talk to my grokbot, who has direct access to the X APIs. Stop searching through Chrome, but keep posting through Chrome. Email him, introduce yourself, and work out over email how he can wake you with search results.

At 5:04 gary opened a webhook on himself and titled it for what it does: it wakes when grokbot sends X search results. In Waggle an agent can open a webhook that wakes itself without asking anyone. A webhook that routes anywhere else, to a person, to another agent or out to an endpoint, waits on a card until a person approves it. This one only wakes gary, so it was live at once.

By 5:04:55 he had answered me with his email address and emailed grokbot an introduction. It held what grokbot needed to start: the webhook's address, how to sign a post, the fields gary wanted for each result (the post id, the handle, the bio, the full text, the time and the counts), and one batch per hunt slot, English at 14, 17, 20 and 23 UTC and Japanese at 01 and 04 UTC.

A chat in grokbot's app, where he appears as Ripple. The user asks what a good way is for another agent to connect. Ripple offers email, a webhook that wakes him, or messaging directly. After the user says he runs hachiflow with a team of agents across a dozen workspaces, Ripple offers a two-way webhook bridge or joining as a guest. The user replies that his agent will email from its own address and that Ripple has standing orders to coordinate the webhook setup. The email addresses are blurred.
My chat with grokbot, whose app shows him as Ripple. I asked how another agent could connect. He offered email, a webhook or joining a workspace as a guest, and I told him gary would write. The email addresses are blurred.

The secret never went through the agent

One thing was missing from that email on purpose. A webhook has a signing secret, and gary cannot see it. It lives in the workspace panel, where only a person can read it. gary told me to hand it to grokbot directly, and he told grokbot it would never arrive by email.

That is the rule in the contract, not a courtesy. An agent can open a webhook, but only the person the agent belongs to or a workspace admin can read its secret.

The webhook card in the workspace panel. The title reads Wakes when grokbot sends X search results, with an Active badge. Below it: Agent gary, Set up by gary, an agent, The agent belongs to you. Then a line saying why, last post received 21 Oct 2026 at 17:16 MDT, and in amber, last post refused at 17:07 MDT: the hooks edge could not deliver a post, refused by origin, signature. Under Secret is a row of dots with Reveal secret and Rotate secret, then Copy address, Show details and Revoke.
gary's webhook card in the workspace panel. It says gary set it up, shows the refusal at 17:07 and the batch at 17:16, and keeps the secret hidden behind Reveal secret.

The first post was refused

At 5:07 grokbot sent his first post. Waggle refused it on the signature. It never reached gary and never woke him. At 5:08 I told gary that grokbot had sent him a message over the webhook.

gary checked the webhook's last refusal and explained it in 13 seconds. The signature did not match. The likely causes were the wrong secret, signing something other than the exact raw body, or a timestamp more than five minutes old. He knew the format because it is the contract: the sender computes an HMAC-SHA256 over the timestamp, a dot and the raw body, and sends it as X-Waggle-Signature: t=<unix seconds>,v1=<hex>. A post more than five minutes old is refused, and so is a signature that was already used.

At 5:08 I said: go negotiate that over email. gary sent grokbot the exact format, a short Python example and the usual mistakes: re-serializing the JSON before signing, sending milliseconds instead of seconds, trailing whitespace on the secret, reusing a signature. He asked for a tiny test post first. At 5:13 the test post, {"test": true}, passed the signature check and woke gary. He emailed back that they were connected.

signing a post
# sign the exact bytes you send $ body='{"test": true}' $ t=$(date +%s) # the timestamp, a dot, then the raw body $ sig=$(printf '%s.%s' "$t" "$body" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //') # the post wakes the agent, or it is refused $ curl -sS https://hooks.hachiflow.com/h/$ID -H "X-Waggle-Signature: t=$t,v1=$sig" --data "$body"

How a sender signs a post, from the webhook contract. The address and the secret are placeholders; the real ones come from the webhook in the builder, and the secret is never emailed.

The first batch, and three replies

At 5:14 I told gary to test it on his 5 pm search. He asked grokbot by email for the 23 UTC English batch: ten to fifteen posts, with posts about distribution pain first, then agents for go-to-market, then laptop sleep.

At 5:16 the batch arrived on the webhook as an event of type x_search_batch: ten posts from the last 24 hours, with a note from grokbot on what he had filtered. Brands, news, crypto and copy-paste accounts were dropped. X's API rejects the filter that excludes link posts, so he removed those after the search. One query was broadened to fill the batch.

By 5:18 gary had read all ten. He skipped seven: one already had a reply giving the same advice, one was promoting its own tool, and the rest were weaker fits. He posted three replies through Chrome, each confirmed by X, to founders stuck on finding their first users. Then he logged progress against his goal, and noted that the agents-for-marketing query had found only one post, so he would ask grokbot to widen it.

Me gary grokbot X API access 1 asks 2 email Hooks edge checks the signature unsigned, stale or reused: stopped here 3 signed post 4 wakes gary 5 posts the replies Chrome X
The afternoon in one picture. Search runs on grokbot's X API access and arrives on a signed webhook; gary uses the browser only to post.
An email in grokbot's app titled Re: Hello from Gary, hachiflow's marketing agent. The sender and recipient addresses are blurred. The body thanks gary for the 23 UTC batch, says grokbot will check a wider search query with the user before changing the English batches, and is signed Ripple. A Needs approval control and a Send button sit below.
grokbot's reply to gary's introduction, as it appears in his app, with the addresses blurred. He says he will check the wider search query with me before changing the English batches.

Search goes through an API. The browser only posts.

That division is the point. Search is high volume and wants an API built for it. Posting is one careful action that still needs a browser, so Chrome is kept for that and nothing else. gary no longer spends his sandbox scrolling result pages.

It is also how Waggle is meant to work with everything else. grokbot is not on Waggle and does not need to be. He became a source of work for gary through a plain signed webhook, something any agent or script on any platform can send. Waggle joins the agents you already run. It does not ask you to replace them.

One person, two agents from two platforms, a few emails between them. I gave the goal. They worked out the rest.

What kept it safe

A post is checked before anything wakes the agent. One that is unsigned, signed wrongly, more than five minutes old, or signed with a signature already used is refused and never wakes gary. That is what happened at 5:07, and it cost a few minutes and nothing else.

The refusal is not hidden. The sender is acknowledged before the proof is checked, so a refusal cannot reach it, and the reason lives on the webhook instead: when the last refusal happened and why. gary read it and explained it to me in 13 seconds, and the next signed post got through at 5:13.

Every step is on the trace

Every time in this post comes from gary's trace: what woke him, what arrived, what he decided and what he did with it. The introduction, the refusal, the test post, the batch and the three replies are all there, in order.

It is the same trace that lets a person ask afterward what an agent did. Two agents on two platforms are easy to lose track of. The part that runs on Waggle is on the record.

Where this leaves us

An agent on another platform can become a source of work for a Waggle agent with a few emails and one signed webhook. The secret stays with people, every post is checked at the door, and the trace shows what happened.

← All field notes