bonfire
Post episodes to the ZABAL Bonfire knowledge graph, or look up how Bonfire works. Bonfire is ZAO's knowledge-graph memory at zabal.bonfires.ai - meetings, decisions, captures flow in as natural-langua
SKILL.md.claude/skills/bonfire/SKILL.md
GitHub/bonfire - ZABAL Bonfire knowledge graph
Post natural-language episodes into the ZABAL Bonfire so the knowledge graph always has full context. Bonfire's auto-extraction turns each episode body into graph nodes + edges.
Design doc: research/agents/717-meeting-bonfire-posting-via-vps. Bonfire
deep-dive: research/agents/665-bonfires-deep-dive-zao-integration. Bridge
design: research/agents/680-meeting-skill-bonfire-bridge.
The key constraint - why this skill SSHes the VPS
The Bonfire API key (BONFIRE_API_KEY) is in TWO places as of 2026-05-24:
locally in ~/.zao/zao.env (mac) AND on the VPS in
/root/cowork-zaodevz/agent/.env. The on-mac copy was an intentional
ergonomics move so local skills can curl Bonfire directly (see doc 754
which reverses doc 717 decision #3).
This skill still SSHes the VPS because (a) it was the original architecture
(doc 717), (b) callers running ON the VPS itself (ZOE / Hermes) have the
VPS env naturally, and (c) the SSH transport keeps working. For posting
from the mac, the /meeting skill takes the simpler local path via
bonfire-episode.sh (doc 754 patch).
| Fact | Value |
|---|---|
| VPS | root@187.77.3.104 (override with BONFIRE_VPS) |
| Key env file (on VPS) | /root/cowork-zaodevz/agent/.env - has BONFIRE_API_KEY, BONFIRE_ID, BONFIRE_API_URL |
| Key env file (local mac, since 2026-05-24) | ~/.zao/zao.env - same vars; used by /meeting skill via bonfire-episode.sh (doc 754) |
| API base | https://tnt-v2.api.bonfires.ai |
| Write endpoint | POST /knowledge_graph/episode/create - works with the non-admin key |
| Read endpoint | POST /vector_store/search - works but returns [] until an admin runs labeling (doc 680) |
| ZAO's bonfire | zabal.bonfires.ai |
When to fire
- The user types
/bonfire - "push this to the knowledge graph", "post this to Bonfire", "add this to our Bonfire"
- "what is in our Bonfire", "how does Bonfire posting work"
- After a
/meetingrun, to post the meeting episodes (the/meetingskill also does this itself viabonfire-episode.sh)
Posting episodes
Step 1 - build an episodes JSON
Write /tmp/bonfire-episodes.json in this shape:
{
"episodes": [
{"name": "<stable unique id>", "body": "<self-contained natural-language prose>", "source_tag": "<short source label>"}
]
}
Rules for episode bodies:
- Self-contained prose. Each body must make sense alone - name the people, the date, the project. Bonfire auto-extraction reads prose, and a graph node must stand on its own. Good: "On 2026-05-19, Zaal and Arthur decided X." Bad: "decided X" (no context).
- One idea per episode. One decision, one action, one fact. Atomic episodes make a cleaner graph than one giant blob.
nameis stable + unique. A re-post with the samenameupdates rather than duplicates. Use a pattern likemeeting:2026-05-19:decision-1.
Step 2 - post via the VPS
bash ${CLAUDE_SKILL_DIR}/scripts/bonfire-post.sh /tmp/bonfire-episodes.json
bonfire-post.sh:
- Validates the JSON and secret-scans every body locally - aborts if any body contains a key-shaped string. Nothing leaves the machine until it is clean.
- SSHes to the VPS, ships the episodes + the remote poster to
/tmp/there. - Runs the POST on the VPS, where
/root/cowork-zaodevz/agent/.envsupplies the key. Cleans up the remote temp files. - Prints
Bonfire: N posted, M failed (of T).
Best-effort: a Bonfire failure prints FAIL per episode but never aborts a
larger workflow.
Reading / querying Bonfire
The read path (POST /vector_store/search) works but currently returns [] -
the ZABAL bonfire's episodes are not searchable until an admin runs labeling
(/labeling/hybrid is 403 for the non-admin key). This is a known gate (doc
680). Until then, Bonfire is write-mostly: episodes ingest and grow the graph,
but programmatic recall is not yet live. ZOE's bot/src/zoe/recall.ts
recall() already handles this gracefully (falls back to a manual relay).
When the read path opens up, querying is POST /vector_store/search with
{bonfire_ref: BONFIRE_ID, search_string: "<query>", limit: N} - run it on the
VPS the same way (the key constraint is identical).
Scripts
scripts/bonfire-post.sh- local: validate + secret-scan + ship to VPS + run + reportscripts/bonfire-remote-post.sh- runs ON the VPS: sources the env, curl-POSTs each episode
Guardrails
- Never read or print
BONFIRE_API_KEY. The skill only ever needs the file path, never the value. The key stays on the VPS. - Secret-scan every episode body before it leaves the machine. A meeting transcript or a pasted note could carry a key.
- Do not commit episodes JSON with secrets.
/tmp/only.