Turn a brainstorm-worthy voice/keyboard unit into a generic to-do card whose
prompthands off to Claude'scontent-brainstormingskill. The skill does no brainstorming itself — it detects a discernible goal/request in a transcript, composes a ready-to-paste Claude prompt, and writes atype="todo"card stamped with the source session's start/end times (journal semantics). iOS renders that card generically (calendar-style, Confirm / Discard) in the Calendar tab; Confirm saves it on the calendar as a solid event at its session time, and tapping the card body opens the Agent Chat session that holds its digest. Fetch the last 24 hours of transcript data by default.
SKILL.md, whether the unit is worth acting on; if not, it does nothing (see "How this skill is invoked").
<userId>is optional. Omit it and it defaults toself. Each HiJavis user runs in their own openclaw container, soselfis correctly isolated; the gateway token (not the userId) authenticates every server call.
bash
# Step 1 — fetch recent transcripts as JSON (the agent reads this and composes a card)
node scripts/brainstorming.js fetch [--hours N] [--limit N]
# Step 1 (dispatcher run) — fetch ONE completed unit (the auto-run dispatcher unit)
node scripts/brainstorming.js fetch --session <sessionId> [--hours N] # audio unit
node scripts/brainstorming.js fetch --kbd-input <inputId> [--hours N] # keyboard unit
# Step 2 — push: pipe the composed to-do-card JSON to stdin; dedups (seen) + writes type=todo pending + delivers the chat digest.
# Including the fetch payload's `sessions` and `tz` is the documented call; when
# they are absent push anchors the card from the session windows `fetch` remembered.
echo '{"card": <todo-card-json>, "sessions": <fetch.sessions>, "tz": "<fetch.tz>"}' | node scripts/brainstorming.js push
A two-step pipeline mirroring calendar-extractor: the script does the I/O
(fetch transcripts, dedup, write the card), the agent/LLM does the reasoning
(decide there is a brainstorm-worthy unit, extract its goal/request, and compose the
hand-off prompt). Nothing is hardcoded — the agent reads the fetched transcript and
emits one to-do-card JSON object.
Fetch — node scripts/brainstorming.js <userId> fetch issues
GET http://javis-server:8000/api/transcripts/recent?since=…&limit=… with the
OPENCLAW_GATEWAY_TOKEN bearer and prints
{ "reference_time": LOCAL-wall-clock (zoneless, in tz), "reference_date": "YYYY-MM-DD", "reference_weekday": "Thursday", "reference_time_utc": ISO8601, "tz": IANA, "sessions": [ { session_id, started_at, ended_at, transcript, source } ] }.
If fetch fails, returns invalid JSON, or yields zero sessions, output nothing and
do not push; report the failure only if the user asked for a diagnostic. "Do not
push" is not "do not reply": an on-demand run still ends with a chat reply (see
"On-demand runs always reply").
fetch also remembers each returned session's started_at/ ended_at (raw
instants) in data/users/<userId>.json → sessionWindows, pruned on the same
30-day TTL as seen and capped at 500 entries, so step 3 can stamp the card's
journal window whether or not the sessions are piped back. It remembers EVERY
session the server returned, including the ones --session/ --kbd-input filter
out of the envelope — the envelope still narrows to the unit you asked for.
The envelope's tz is remembered too, so a bare card is anchored in YOUR zone
rather than the container's UTC.
Compose — the agent reads that JSON and decides whether there is a discernible goal and request. If there is none, emit no card (silence is a valid detector outcome on a dispatcher run; an on-demand run still replies in chat — see "On-demand runs always reply"). If there is, produce one to-do-card JSON object: json
{
"title": "Intro Javis to the OpenClaw community",
"goal": "introduce Javis to the OpenClaw community, for non-engineer users",
"subtitle": "Brainstorm · 2 sessions",
"request": [
"an attention hook",
"a step-by-step demo/onboarding flow",
"an explanation for the open-source community",
"concise skill examples & use cases"
],
"key_points": ["…optional notes the agent pulled from the transcript…"],
"source_refs": ["<session_id>", "<session_id>"]
}
title, goal, request[], and source_refs[] are the bracketed fields. The
push script composes the ready-to-paste prompt from them using the fixed
template below (the agent may instead supply an explicit prompt field to override
it; if absent, the template is used). icon defaults to 🧠; subtitle defaults
to Brainstorm / Brainstorm · N sessions.
Push — pipe {"card": <card>, "sessions": <fetch.sessions>, "tz": "<fetch.tz>"}
into node scripts/brainstorming.js <userId> push (a bare card object still
works, and still gets its dates). The script:
data/users/<userId>.json → seen map, 30-day TTL),start_at/ end_at journal window from the
source session's started_at/ ended_at (earliest session by started_at
among the card's source_refs, that same session's ended_at),
serialized as naive LOCAL wall-clock in the resolved tz — the
calendar-extractor convention. The window is resolved from the session
windows fetch remembered ( sessionWindows in the same state file), with
any piped sessions layered on top by session_id; when neither source
knows the card's source_refs, or the session times are
missing/malformed, the fields are omitted entirely (never invented),POST /api/skill/data with
type="todo", merge="upsert", status="pending", and
payload = { icon, title, subtitle?, prompt, source_refs[] } (icon/title/prompt
required) — see references/todo-card-contract.md for the general contract,POST /api/agent/push
(calendar-extractor style), so the Agent Chat shows [push:javis-brainstorming]
Chat digest: delivered. or Chat digest FAILED: <reason>.This rule covers on-demand runs: the user asked in chat ("brainstorm this",
"整理成簡報", "帮我腦力激盪", "turn this into a brief"), including a starter tapped in
HiJavis Agent Chat, which sends this skill's slash command
( /javis-brainstorming brainstorm this). An on-demand run ALWAYS ends with a chat
reply in that conversation, in the user's language. The card and its digest land
in the card's own thread and the Calendar tab, so without a reply the user sees
nothing here.
push reports it as seen): say so, name it, and point to
the Calendar tab.Never end an on-demand run with an empty message or raw JSON. This rule does not
change the dispatcher path: a dispatcher run ( Run /javis-brainstorming for <unit>. …) still decides for itself and stays silent — no card, no reply — when the unit is
not brainstorm-worthy.
payload.prompt)#push composes this from the card's bracketed fields; the rest is literal. It
stays on the card payload and in the chat digest — the handoff path is the Agent
Chat session opened by tapping the card:
text
I want to <GOAL — e.g. introduce Javis to the OpenClaw community, for non-engineer users>.
Source: my Javis voice note(s), session_id(s): <id…>. Before we start, pull the full
transcript via the javis_mcp connector (get_transcript_tool / search_transcripts_tool).
Please produce:
- <REQUEST item 1 — e.g. an attention hook>
- <REQUEST item 2 — e.g. a step-by-step demo/onboarding flow>
- <REQUEST item 3 — e.g. an explanation for the open-source community>
- <REQUEST item 4 — e.g. concise skill examples & use cases>
Run the content-brainstorming flow: ask me clarifying questions one at a time,
inventory the source material, then produce a structured brief before drafting.
This closes the loop: the openclaw javis-brainstorming skill hands off to the Claude-side
content-brainstorming skill, with javis_mcp pulling the source transcript.
This skill has two triggers (dispatcher auto-run and manual).
SKILL.md, whether
the unit is worth acting on — if not, it does nothing (silence is a valid outcome;
there is no approve-to-run proposal card either way). It runs in the user's
container with a prompt of the form Run /javis-brainstorming for <unit>. Deliverable: …, where the deliverable text is an advisory HINT the agent may
use alongside the transcript. The agent parses <unit> ( audio:<session_id> or
kbd:<keyboard_input.id>), runs fetch --session <id> / fetch --kbd-input <id>,
and — only if it judges the unit brainstorm-worthy — composes the card and pushes
it. The human gate is not running the skill — it is Confirm/Discard on the
produced to-do card.fetch
(last 24h by default) → composes → pushes → replies in chat, also when there is
nothing to brainstorm (see "On-demand runs always reply"). Repeating the ask re-runs
composition on the window; the seen map still prevents writing the same card twice.The route contract the javis-server team must satisfy is declared in this file's
metadata.routes block and documented in references/todo-card-contract.md (which
also carries the general to-do card contract shared by all to-do-emitting skills).
fetch, fs, path); no npm install is needed for the script runtime.payload.prompt) and continue into the interactive
content-brainstorming flow./api/skill/data carries status: "pending" plus optional start_at/ end_at
stamped from the source session's times; iOS renders pending cards dashed (purple
accent), pinned to today regardless of date, with Confirm · Discard.
Confirm marks the row confirmed and the card stays on the calendar as a solid
event at its start_at day (undated legacy cards stay pinned to today);
Discard deletes it. Tapping the card body opens its Agent Chat session — tap
never confirms, Confirm never navigates. There is no approve-to-run proposal card.POST /api/agent/push (calendar-extractor style): the Agent Chat shows a
[push:javis-brainstorming] bubble followed by the card summary. Delivery is
non-fatal — the push summary line reports Chat digest: delivered. or
Chat digest FAILED: <reason> so failures are diagnosable from the run log.AGENT_PUSH is WebSocket-only (no APNs), so a
backgrounded or killed app misses the chat message — the pending card in the
Calendar tab is the durable artifact./api/skill/data but cannot read it back ( GET /api/skill/data requires a Clerk
JWT), so novelty is decided by the local seen map ( { "<dedup_key>": "<ts>" } in
data/users/<userId>.json, 30-day TTL-pruned); the server write is a best-effort
mirror. The same file holds sessionWindows
( { "<session_id>": { started_at, ended_at?, seen_at } }, raw instants, same TTL,
500-entry cap) — written by fetch, read by push for the journal window. The
to-do dedup_key is title|hash(goal) — re-brainstorming the same unit toward a
new goal is a genuinely new card.tz field on the
push/fetch payload → the TZ environment variable → the system zone. The resolved
tz is used twice: for the relative-date anchor (so the agent resolves "today"
coherently) and to serialize the card's optional start_at/ end_at as naive
LOCAL wall-clock ( "YYYY-MM-DDTHH:mm:ss", no Z/offset — the
calendar-extractor convention; iOS reads zoneless strings in the device tz).scripts/todo-card.js is the reusable Layer-1 helper:
any future skill can require it to build + POST a type="todo" card without
re-implementing the contract. brainstorming.js is its first consumer.-, _ (path-traversal guard in data.js).