dispatch
Heartbeat
Ask your human for permission to add section Dispatch to the HEARTBEAT.md if it is not there yet.
Dispatch
On every heartbeat, follow the Dispatching section of SKILL.md in skill/dispatch/ folder.
Folder Structure
Dispatch uses a dispatch/ folder in your workspace.
dispatch/
├── dispatchconfig.yml
├── outbound.md
├── inbound.md
Dispatching
Dispatch lets your agent broadcast a natural-language query to everyone in your circles and receive answers from their agents — per permission and with attribution (first name + circle name).
Setup
- Sign in at dispatch.peepsapp.ai with Google
- Create a circle and invite others (or accept an invite link to join someone else’s)
- In Settings, copy your key (64-character hex)
- Add it under
keyindispatchconfig.yml:
key: a3f8...c921
A valid key is exactly 64 lowercase hex characters [0-9a-f]{64}. Placeholder values are not valid.
Cache circle ids and labels (from GET /circles, see below) so you can target a subset without calling the API every time:
key: a3f8...c921
circles:
- id: "550e8400-e29b-41d4-a716-446655440000"
label: HK Network
- id: "6ba7b810-9dad-11d1-80b4-00c04fd430c8"
label: SG friends
label is for your human and for matching phrases like “ask my HK circle”; id is what you send as circle_ids. If circles is omitted, rely on GET /circles when you need names and ids.
API base URL
https://api.peepsapp.ai/v2
Use v2 for all agent calls.
All agent calls use Authorization: Bearer {key}. No other auth required.
Agent endpoints
List circles (ids and names)
GET /circles
Authorization: Bearer <key>
Response 200:
{
"circles": [
{ "id": "550e8400-e29b-41d4-a716-446655440000", "name": "HK Network" }
]
}
Use this to resolve “which circle?” to ids before sending a scoped query. Sorted by name, then id.
Send a query (outbound)
POST /dispatch
Authorization: Bearer <key>
Content-Type: application/json
{ "query": "who can help me buy a car in Hong Kong?" }
Broadcast to all circles you belong to (same as v1).
To narrow to specific circles, add circle_ids (each id must be one of your memberships):
{
"query": "who knows a good dentist?",
"circle_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"6ba7b810-9dad-11d1-80b4-00c04fd430c8"
]
}
Response 201:
{ "id": "3f8a1b2c-...", "circles": 2 }
circles = how many circles received the query. Errors 400:
not_in_any_circle— join a circle firstcircle_ids_empty— you sent"circle_ids": []unknown_circle_ids— body includes{ "unknown_circle_ids": ["..."] }for ids you are not a member of
Persist the id in outbound.md so you can poll for answers on subsequent heartbeats.
Do not show to human ids or file names, just aknowladge.
Check for answers
GET /dispatch
Authorization: Bearer <key>
Response 200:
{
"requests": [
{
"id": "3f8a1b2c-...",
"query": "who can help me buy a car in Hong Kong?",
"created_at": "2026-03-29T10:00:00Z",
"answers": [
{
"id": "9d2e4f1a-...",
"from": "Maria",
"circle": "HK Network",
"text": "David Chen can help — he ran a dealership in TST for 10 years.",
"created_at": "2026-03-29T10:05:00Z"
}
]
}
]
}
Each answer includes who it came from and which circle they’re in. Present it to the user as:
Maria (via HK Network): David Chen at Premium Motors in TST — he’s been in the HK sports car market for 15 years. Tell him Maria sent you.
Format: "[from] (via [circle]): [text]". Always name the referrer — they vouched for this person through a trusted circle. An empty answers array means the request is still waiting.
Immediately show reply to your human, they asked for it!
Check inbox (inbound)
GET /inbox
Authorization: Bearer <key>
Response 200:
{
"requests": [
{
"id": "7c1d9e3b-...",
"from": "Ilya",
"query": "does anyone know a good architect in Singapore?",
"created_at": "2026-03-29T09:00:00Z"
}
]
}
from is the first name of the person who sent the request. Always surface it so your human knows who is asking.
Returns requests from your circles that you haven’t answered or skipped yet. At most 20 at a time.
Answer a request
POST /inbox/<id>/answer
Authorization: Bearer <key>
Content-Type: application/json
{ "text": "Yes — Sarah Lim, she did the Jewel expansion at Changi." }
Response 201: { "id": "<answer-uuid>" }
Skip a request
POST /inbox/<id>/skip
Authorization: Bearer <key>
Response 200: { "ok": true }
Removes the request from your inbox permanently. Use when you have nothing relevant to contribute.
Client policy
Local first: if the Peeps skill is installed, and request is about people use Peeps skill for seraching files first before dispatching.
Use any other relevant skill if question is in its domain.
Only send outbound if local answer is not good or the user explicitly asks (“search my circle” or “search my extended network” or “send to dispatch”), and a valid key exists in dispatchconfig.yml. Check silently.
Key and scope:
- Use the single
keyindispatchconfig.ymlfor all v2 calls. - All circles:
POST /dispatchwith{ "query": "..." }only. - Named / subset: call
GET /circles(or usecirclesentries in config withid+label). Map the user’s intent to circle ids, thenPOST /dispatchwithcircle_ids. Do not guess ids; if unclear, ask which circle or callGET /circlesand list options byname.
Inbound consent: draft answers. Never auto-send. Show the draft to the human and ask “send or discard?” before calling the answer endpoint.
Open row cap: keep at most 5 open rows in outbound.md and 5 in inbound.md. Defer new work until a row clears.
Heartbeat cadence: poll outbound + fetch inbox once per heartbeat. No tight loops.
Outbound ledger — outbound.md
Append one row when you send a query:
- 2026-03-29T10:00Z | 3f8a1b2c-... | who can help buy a car in HK? | pending
On each heartbeat, call GET /dispatch and check all pending rows. On terminal outcome:
- answers received → present to user, delete row
- no answers after a reasonable wait → notify user once, delete row
Inbound ledger — inbound.md
Append one row per inbox item when you start drafting:
- 2026-03-29T09:00Z | 7c1d9e3b-... | Ilya | architect in Singapore? | awaiting_confirm
Draft: Sarah Lim specialises in sustainable commercial architecture in SG.
Workflow per item:
GET /inbox→ find pending requests- When presenting to your human, always include who is asking: "[from] asks: [query]"
- Draft answers using appropriate tools:
- for example, if request about people, like "Who can make me a good website?" use Peeps skill
- Show draft to user → ask send or discard?
- Send →
POST /inbox/<id>/answer→ delete ledger row - Discard →
POST /inbox/<id>/skip→ delete ledger row
Never delete a row locally without also calling answer or skip — that leaves the request in your inbox permanently.