[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"skill:01M6N0F3J1TPXWMDZ90ZJ69S42":3,"skill-same:01M6N0F3J1TPXWMDZ90ZJ69S42":89},{"skillNo":4,"name":5,"nameZh":6,"description":7,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":16,"categories":17,"keywords":23,"publishedAt":44,"linkOnly":45,"markdownContent":46,"markdownBody":47,"frontMatter":48,"refName":61,"commitSha":62,"skillDirectory":63,"forksCount":64,"repositoryHtmlUrl":65,"repositoryHomepageUrl":6,"ownerHtmlUrl":66,"ownerBlogUrl":67,"ownerDescription":68,"updatedAt":69,"install":70,"resources":82},"01M6N0F3J1TPXWMDZ90ZJ69S42","voice-post-call",null,"Post-call handling for a voice session — turn the transcript into a brain page, post the summary to the operator's messaging surface, archive the audio. The pipeline is the contract; the firing paths are operator-wired (see \"Two firing paths\" below for what ships today).","garrytan\u002Fgbrain","garrytan","https:\u002F\u002Favatars.githubusercontent.com\u002Fu\u002F19957?v=4","01M6DJCCDDG53MTYYRTXAXFG17","Garry Tan","01M6MZQZCEN3RRMD33E1X9ZZR9",32847,"MIT","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Frecipes\u002Fagent-voice\u002Fskills\u002Fvoice-post-call\u002FSKILL.md",[18],{"categoryNo":19,"categoryName":20,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000037","律师与法务","PROFESSION","适用职业",[24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43],"call","voice post call","post","voice","Audio","pipeline","archive","page","meetings","session","voice call","brain","contract","call summary","paths","messaging","calls","true","for","transcript","2026-11-10 10:12:30",false,"---\nname: voice-post-call\nversion: 0.1.0\ndescription: Post-call handling for a voice session — turn the transcript into a brain page, post the summary to the operator's messaging surface, archive the audio. The pipeline is the contract; the firing paths are operator-wired (see \"Two firing paths\" below for what ships today).\ntriggers:\n  - \"after the call\"\n  - \"call ended\"\n  - \"summarize the call\"\n  - \"call transcript\"\n  - \"voice call summary\"\n  - \"post call summary\"\nmutating: true\nwrites_pages: true\nwrites_to:\n  - meetings\u002F\n  - voice-calls\u002F\n---\n\n# voice-post-call — Post-session transcript + summary handling\n\n> **Convention:** see gbrain's `skills\u002Fconventions\u002Fquality.md` for citation rules + back-link enforcement, and `skills\u002F_brain-filing-rules.md` for the filing decision protocol. (These are not copied by the install; the relative paths resolve only if your host repo mirrors gbrain's skills layout.)\n\n## Iron Law\n\n**Every call gets processed, even on tool-call failure.** The voice persona MAY log mid-session via an opted-in write tool, OR the call may end without that tool firing (model forgot, WebRTC dropped, browser crashed). A call-end handler should post a structured signal regardless so the brain still gets the transcript + audio reference — see \"Two firing paths\" below for which of these ships today and which the operator implements.\n\nIf both paths fire (the tool call AND the call-end handler), the second one is idempotent — it sees the brain page already exists and updates instead of duplicating.\n\n## The pipeline\n\n```\n1. CAPTURE  → MediaRecorder on the host repo's voice-agent service captures\n              the full call audio (webm\u002Fopus) to \u002Ftmp\u002Fcalls\u002F\u003Cts>-\u003Cpersona>.webm.\n              The browser client at \u002Fcall?test=1 also captures via WebAudio-tee\n              for E2E asserts; production \u002Fcall uses server-side capture only.\n2. TRANSCRIBE → Whisper (via gbrain transcription) processes the audio. Output:\n              full transcript (timestamped) + speaker labels where possible.\n3. SUMMARIZE  → A separate LLM call produces a 3-5 sentence summary covering\n              key topics, decisions, and unresolved items.\n4. WRITE      → Create or update meetings\u002FYYYY-MM-DD-call-\u003Cpersona>.md with:\n              - frontmatter (date, persona, duration, ratings)\n              - full transcript in a \"Transcript\" block-quote section\n              - summary in a \"Summary\" section\n              - audio link (file:\u002F\u002F, or signed URL if uploaded to storage)\n              - any entity cross-links (people, companies mentioned)\n5. CROSS-LINK → For each entity in the transcript (person, company), append a\n              timeline entry to people\u002F\u003Cslug>.md or companies\u002F\u003Cslug>.md pointing\n              back to this call page. Iron Law: per conventions\u002Fquality.md.\n6. POST       → Send the summary to the operator's messaging surface (Telegram,\n              Slack, Discord — whichever is wired in $TARGET_REPO\u002F.env).\n```\n\n## Two firing paths (both operator-wired today)\n\n**Path A — Persona-initiated mid-call (opt-in):**\nThe voice persona calls `log_to_brain` via the WebRTC data channel; the host-repo `\u002Ftool` endpoint dispatches through `tools.mjs`. `log_to_brain` is in `OPTIONAL_OPS`, not `READ_ONLY_OPS`, so this only works if the operator's `tools-allowlist.local.json` opts in (there is no `log_call_summary` tool — the override can only enable ops listed in `OPTIONAL_OPS`).\n\n**Path B — Call-end handler (not yet shipped):**\nThe shipped `server.mjs` has **no automatic call-end handler** — nothing fires when the WebSocket \u002F WebRTC connection closes. To get the safety-net behavior, implement a post-call handler in your host repo that reads the captured audio + transcript on connection close and runs the pipeline above. Until you do, Path A (opt-in) is the only firing path, and calls where the persona never logs are NOT processed.\n\n## Brain page format\n\n```markdown\n---\ntype: meeting\nsubtype: voice-call\npersona: venus\ndate: 2026-05-17\nduration_sec: 124\ncaller: operator\nrating: 7\nissues: []\naudio_url: \"file:\u002F\u002F\u002Ftmp\u002Fcalls\u002F2026-05-17-1029-venus.webm\"\ncreated: 2026-05-17\n---\n\n# Voice call: 2026-05-17 with Venus\n\n> Brief 3-5 sentence summary of what was discussed and any decisions made.\n\n## Summary\n[Agent-authored 3-5 sentence summary covering topics, decisions, action items.]\n\n## Transcript\n\n> [Verbatim per-turn transcript with speaker labels and timestamps. Pure quote\n> — do not paraphrase. Block-quoted because the exact wording matters more\n> than a cleaned-up version.]\n\n? [Audio](file:\u002F\u002F\u002Ftmp\u002Fcalls\u002F2026-05-17-1029-venus.webm)\n\n## Entities mentioned\n- [Person](people\u002F\u003Cslug>.md)\n- [Company](companies\u002F\u003Cslug>.md)\n\n## Timeline\n\n- **2026-05-17 10:29 PT** | voice call with Venus, 124s, rating 7 — [topic]\n```\n\n## Citation format\n\n```\n[Source: voice call with \u003Cpersona>, YYYY-MM-DD HH:MM PT]\n```\n\n## Anti-patterns\n\n- ❌ Paraphrasing the transcript. The verbatim text IS the signal; the summary is the agent's interpretation.\n- ❌ Skipping the audio archive step. Every call has a recoverable audio file.\n- ❌ Skipping entity cross-links when people\u002Fcompanies are mentioned. Iron Law fail.\n- ❌ Posting to messaging WITHOUT writing the brain page first. The messaging summary is a notification, not the canonical record.\n- ❌ Letting Path A's success suppress Path B. They MAY both fire; the second one is idempotent and serves as a redundant safety net.\n\n## Related skills\n\nShips with this bundle (sibling directories after install):\n\n- [voice-persona-mars](..\u002Fvoice-persona-mars\u002FSKILL.md) — the persona that may invoke this\n- [voice-persona-venus](..\u002Fvoice-persona-venus\u002FSKILL.md) — the other persona that may invoke this\n\nLives in gbrain's `skills\u002F` (present on the host only if your repo mirrors gbrain's skills layout):\n\n- `meeting-ingestion` — analogous flow for multi-party meeting transcripts (different in that voice-call is typically 1:1)\n- `media-ingest` — for recorded one-way voice memos (different from live voice calls)\n\n## Contract\n\nThis skill guarantees:\n\n- Routing matches the canonical triggers in the frontmatter.\n- The post-call pipeline runs idempotently — second invocations update rather than duplicate.\n- Output written under `meetings\u002F` or `voice-calls\u002F` (consistent with `_brain-filing-rules.md`).\n- Conventions referenced (`quality.md`, `_brain-filing-rules.md`) are followed.\n- Privacy contract preserved: no real names in any committed sample; the operator's actual call transcripts contain whatever they say, which is the operator's data and not gbrain's concern.\n\n## Output Format\n\n```markdown\n---\ntype: meeting\nsubtype: voice-call\npersona: \u003Cmars|venus>\ndate: YYYY-MM-DD\nduration_sec: N\ncaller: \u003Cidentity>\nrating: 0-10\naudio_url: \"\u003Cfile:\u002F\u002F or signed URL>\"\n---\n\n# Voice call: \u003Cdate> with \u003Cpersona>\n\n> \u003CSummary>\n\n## Summary\n\u003Cbody>\n\n## Transcript\n\n> \u003Cverbatim>\n\n? [Audio](\u003Curl>)\n\n## Timeline\n\n- **\u003Cdate> \u003Ctime> \u003Ctz>** | voice call with \u003Cpersona>, \u003Cduration>s — \u003Ctopic>\n```\n","# voice-post-call — Post-session transcript + summary handling\n\n> **Convention:** see gbrain's `skills\u002Fconventions\u002Fquality.md` for citation rules + back-link enforcement, and `skills\u002F_brain-filing-rules.md` for the filing decision protocol. (These are not copied by the install; the relative paths resolve only if your host repo mirrors gbrain's skills layout.)\n\n## Iron Law\n\n**Every call gets processed, even on tool-call failure.** The voice persona MAY log mid-session via an opted-in write tool, OR the call may end without that tool firing (model forgot, WebRTC dropped, browser crashed). A call-end handler should post a structured signal regardless so the brain still gets the transcript + audio reference — see \"Two firing paths\" below for which of these ships today and which the operator implements.\n\nIf both paths fire (the tool call AND the call-end handler), the second one is idempotent — it sees the brain page already exists and updates instead of duplicating.\n\n## The pipeline\n\n```\n1. CAPTURE  → MediaRecorder on the host repo's voice-agent service captures\n              the full call audio (webm\u002Fopus) to \u002Ftmp\u002Fcalls\u002F\u003Cts>-\u003Cpersona>.webm.\n              The browser client at \u002Fcall?test=1 also captures via WebAudio-tee\n              for E2E asserts; production \u002Fcall uses server-side capture only.\n2. TRANSCRIBE → Whisper (via gbrain transcription) processes the audio. Output:\n              full transcript (timestamped) + speaker labels where possible.\n3. SUMMARIZE  → A separate LLM call produces a 3-5 sentence summary covering\n              key topics, decisions, and unresolved items.\n4. WRITE      → Create or update meetings\u002FYYYY-MM-DD-call-\u003Cpersona>.md with:\n              - frontmatter (date, persona, duration, ratings)\n              - full transcript in a \"Transcript\" block-quote section\n              - summary in a \"Summary\" section\n              - audio link (file:\u002F\u002F, or signed URL if uploaded to storage)\n              - any entity cross-links (people, companies mentioned)\n5. CROSS-LINK → For each entity in the transcript (person, company), append a\n              timeline entry to people\u002F\u003Cslug>.md or companies\u002F\u003Cslug>.md pointing\n              back to this call page. Iron Law: per conventions\u002Fquality.md.\n6. POST       → Send the summary to the operator's messaging surface (Telegram,\n              Slack, Discord — whichever is wired in $TARGET_REPO\u002F.env).\n```\n\n## Two firing paths (both operator-wired today)\n\n**Path A — Persona-initiated mid-call (opt-in):**\nThe voice persona calls `log_to_brain` via the WebRTC data channel; the host-repo `\u002Ftool` endpoint dispatches through `tools.mjs`. `log_to_brain` is in `OPTIONAL_OPS`, not `READ_ONLY_OPS`, so this only works if the operator's `tools-allowlist.local.json` opts in (there is no `log_call_summary` tool — the override can only enable ops listed in `OPTIONAL_OPS`).\n\n**Path B — Call-end handler (not yet shipped):**\nThe shipped `server.mjs` has **no automatic call-end handler** — nothing fires when the WebSocket \u002F WebRTC connection closes. To get the safety-net behavior, implement a post-call handler in your host repo that reads the captured audio + transcript on connection close and runs the pipeline above. Until you do, Path A (opt-in) is the only firing path, and calls where the persona never logs are NOT processed.\n\n## Brain page format\n\n```markdown\n---\ntype: meeting\nsubtype: voice-call\npersona: venus\ndate: 2026-05-17\nduration_sec: 124\ncaller: operator\nrating: 7\nissues: []\naudio_url: \"file:\u002F\u002F\u002Ftmp\u002Fcalls\u002F2026-05-17-1029-venus.webm\"\ncreated: 2026-05-17\n---\n\n# Voice call: 2026-05-17 with Venus\n\n> Brief 3-5 sentence summary of what was discussed and any decisions made.\n\n## Summary\n[Agent-authored 3-5 sentence summary covering topics, decisions, action items.]\n\n## Transcript\n\n> [Verbatim per-turn transcript with speaker labels and timestamps. Pure quote\n> — do not paraphrase. Block-quoted because the exact wording matters more\n> than a cleaned-up version.]\n\n? [Audio](file:\u002F\u002F\u002Ftmp\u002Fcalls\u002F2026-05-17-1029-venus.webm)\n\n## Entities mentioned\n- [Person](people\u002F\u003Cslug>.md)\n- [Company](companies\u002F\u003Cslug>.md)\n\n## Timeline\n\n- **2026-05-17 10:29 PT** | voice call with Venus, 124s, rating 7 — [topic]\n```\n\n## Citation format\n\n```\n[Source: voice call with \u003Cpersona>, YYYY-MM-DD HH:MM PT]\n```\n\n## Anti-patterns\n\n- ❌ Paraphrasing the transcript. The verbatim text IS the signal; the summary is the agent's interpretation.\n- ❌ Skipping the audio archive step. Every call has a recoverable audio file.\n- ❌ Skipping entity cross-links when people\u002Fcompanies are mentioned. Iron Law fail.\n- ❌ Posting to messaging WITHOUT writing the brain page first. The messaging summary is a notification, not the canonical record.\n- ❌ Letting Path A's success suppress Path B. They MAY both fire; the second one is idempotent and serves as a redundant safety net.\n\n## Related skills\n\nShips with this bundle (sibling directories after install):\n\n- [voice-persona-mars](..\u002Fvoice-persona-mars\u002FSKILL.md) — the persona that may invoke this\n- [voice-persona-venus](..\u002Fvoice-persona-venus\u002FSKILL.md) — the other persona that may invoke this\n\nLives in gbrain's `skills\u002F` (present on the host only if your repo mirrors gbrain's skills layout):\n\n- `meeting-ingestion` — analogous flow for multi-party meeting transcripts (different in that voice-call is typically 1:1)\n- `media-ingest` — for recorded one-way voice memos (different from live voice calls)\n\n## Contract\n\nThis skill guarantees:\n\n- Routing matches the canonical triggers in the frontmatter.\n- The post-call pipeline runs idempotently — second invocations update rather than duplicate.\n- Output written under `meetings\u002F` or `voice-calls\u002F` (consistent with `_brain-filing-rules.md`).\n- Conventions referenced (`quality.md`, `_brain-filing-rules.md`) are followed.\n- Privacy contract preserved: no real names in any committed sample; the operator's actual call transcripts contain whatever they say, which is the operator's data and not gbrain's concern.\n\n## Output Format\n\n```markdown\n---\ntype: meeting\nsubtype: voice-call\npersona: \u003Cmars|venus>\ndate: YYYY-MM-DD\nduration_sec: N\ncaller: \u003Cidentity>\nrating: 0-10\naudio_url: \"\u003Cfile:\u002F\u002F or signed URL>\"\n---\n\n# Voice call: \u003Cdate> with \u003Cpersona>\n\n> \u003CSummary>\n\n## Summary\n\u003Cbody>\n\n## Transcript\n\n> \u003Cverbatim>\n\n? [Audio](\u003Curl>)\n\n## Timeline\n\n- **\u003Cdate> \u003Ctime> \u003Ctz>** | voice call with \u003Cpersona>, \u003Cduration>s — \u003Ctopic>\n```\n",{"name":5,"version":49,"mutating":50,"triggers":51,"writes_to":58,"description":7,"writes_pages":50},"0.1.0",true,[52,53,54,55,56,57],"after the call","call ended","summarize the call","call transcript","voice call summary","post call summary",[59,60],"meetings\u002F","voice-calls\u002F","master","074ec301549ded4930f04d2c3b22d709a6c095cc","recipes\u002Fagent-voice\u002Fskills\u002Fvoice-post-call",4902,"https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain","https:\u002F\u002Fgithub.com\u002Fgarrytan","https:\u002F\u002Fblog.garrytan.com","Writes software, dreams. ","2026-11-14 04:11:30",{"source":8,"skillName":5,"commands":71,"prompt":81,"zipAvailable":50},[72,75,78],{"tool":73,"command":74},"npx","npx skills add garrytan\u002Fgbrain --skill voice-post-call",{"tool":76,"command":77},"bunx","bunx skills add garrytan\u002Fgbrain --skill voice-post-call",{"tool":79,"command":80},"pnpm","pnpm dlx skills add garrytan\u002Fgbrain --skill voice-post-call","安装技能，技能地址：https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Frecipes\u002Fagent-voice\u002Fskills\u002Fvoice-post-call\u002FSKILL.md",[83],{"path":84,"resourceType":85,"resourceTypeDesc":86,"sizeBytes":87,"sourceHtmlUrl":88},"routing-eval.jsonl","OTHER","其他",591,"https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Frecipes\u002Fagent-voice\u002Fskills\u002Fvoice-post-call\u002Frouting-eval.jsonl",[90,102,108,129,153,167],{"skillNo":91,"name":92,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":93,"categories":94,"keywords":95,"publishedAt":44},"01M6N109FNGH1PK49T734PZXGB","query-helper","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog\u002Fskills\u002Fquery-helper\u002FSKILL.md",[],[96,97,98,99,31,100,101],"query helper","helper","query","search","find","false",{"skillNo":103,"name":104,"nameZh":6,"description":6,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":105,"categories":106,"keywords":107,"publishedAt":44},"01M6N108A23GW6NGQEQ0E7GV0A","broken","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog\u002Fskills\u002Fbroken\u002FSKILL.md",[],[104],{"skillNo":109,"name":110,"nameZh":6,"description":111,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":112,"categories":113,"keywords":114,"publishedAt":44},"01M6N105E88C5K2H03H0CC79G1","brain-ops","Read, enrich, and write brain pages with source attribution.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog\u002Fskills\u002Fbrain-ops\u002FSKILL.md",[],[115,35,116,41,117,31,118,119,120,121,98,122,123,124,125,126,127,128,99],"brain ops","ops","attribution","read","write","up","look","pages","people","with","enrich","web","path","source",{"skillNo":130,"name":131,"nameZh":6,"description":132,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":133,"categories":134,"keywords":138,"publishedAt":44},"01M6N102GRMF22TVCNT6RK5MRD","meeting-prep","Build a briefing before you meet someone, from their recent threads, open loops and what they care about.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog-query\u002Fskills\u002Fmeeting-prep\u002FSKILL.md",[135],{"categoryNo":136,"categoryName":137,"taxonomyType":21,"taxonomyTypeDesc":22},"01JBSEEDCAT000000000000034","行政与办公人员",[139,140,141,142,143,99,144,145,146,98,101,147,148,149,150,151,42,152],"meeting","prep","meeting prep","me","prepare","brief","open","build","loops","about","you","briefing","threads","Meet",{"skillNo":154,"name":155,"nameZh":6,"description":156,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":157,"categories":158,"keywords":159,"publishedAt":44},"01M6N1005QK7REHX5KGMNR5PF0","inbox-zero","Triage the inbox into replies, delegations and archives.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog-query\u002Fskills\u002Finbox-zero\u002FSKILL.md",[],[160,161,162,99,163,101,164,165,166],"inbox zero","ZeRO","inbox","clear","replies","my","triage",{"skillNo":168,"name":169,"nameZh":6,"description":170,"descriptionZh":6,"repositoryFullName":8,"ownerLogin":9,"ownerAvatarUrl":10,"ownerAccountNo":11,"ownerDisplayName":12,"repositoryNo":13,"starsCount":14,"licenseSpdxId":15,"licenseFileUrl":6,"sourceHtmlUrl":171,"categories":172,"keywords":173,"publishedAt":44},"01M6N0ZXQ8RRRW71PNV61T57GP","deal-memo","Draft an investment memo from the deal pages and the founder history already in the brain.","https:\u002F\u002Fgithub.com\u002Fgarrytan\u002Fgbrain\u002Fblob\u002Fmaster\u002Ftest\u002Ffixtures\u002Fskill-catalog-query\u002Fskills\u002Fdeal-memo\u002FSKILL.md",[],[174,175,176,122,35,177,178,119,179,41,99,180],"deal memo","deal","memo","draft","investment","history","founder"]