session-summary is an agent skill that turns a finished recording into the files you actually
share. It is the post-conference stage of the pipeline: the daemon and the assistant produce
evidence during the meeting, this skill reconstructs it afterwards.
It is not a daemon process, a console script, or a socket client. It runs inside an agent
session (OpenCode), driven by
.opencode/skills/session-summary/SKILL.md.
Everything comes from one session directory under transcripts/ (gitignored):
| Input | Role |
|---|---|
transcripts.jsonl |
The evidence. Read-only. seg_id, ts, lang, lang_prob, text, speaker, speaker_id, speaker_status, speaker_score |
audio/*.wav |
Optional corroboration (only written when [output].save_audio = true) |
brief.md |
Low-trust input. A list of possible leads, never a source of facts |
speakers/speakers.json |
Name mapping only (speakers.<id>.name); not an attendee list |
questions.json |
Not read by this skill |
Rules that shape every run:
transcripts.jsonl and audio/ are never modified.seg_id. If it cannot be, it is not written.Every run writes these files into the same session directory, and nothing elsewhere:
| File | What it is |
|---|---|
session-summary.svg |
One-page visual reconstruction, English |
session-summary.png |
Shareable export of the SVG (1680 px, 64-color, ~0.27 MB) |
session-summary.content.json |
The content the English SVG was rendered from |
session-summary.es.svg |
Spanish reconstruction — same topics, same order, same claims |
session-summary.es.png |
Shareable export of the Spanish SVG |
session-summary.es.content.json |
Spanish content JSON |
brief.md |
Rewritten in place, keeping the Summary: … Prior Details: layout |
The run is not complete until both SVGs and both PNGs exist and have passed verification. A PNG around 1 MB means the quantization step did not run.
The page layout is fixed by the renderer: header with computed stats, a main-point band, a sidebar (session focus, participants and roles, transcription quality), any number of topic cards, an Opportunities / Blockers-Risks / Open-questions block, optional next steps, and a footer of method notes.
Invoke the skill from an agent session and name the session directory, for example "summarize
transcripts/2026-10-30-13-07-19" or "fix the brief of that session". The skill drives the
whole flow: load the evidence, reconstruct, write the content JSONs, render, verify, correct the
brief, then update the glossary.
Rendering is a separate script; the skill calls it, and you can call it directly for a re-render after editing a content JSON:
S=transcripts/<session-id>
R=.opencode/skills/session-summary/scripts/render.py
uv run python $R $S $S/session-summary.content.json $S/session-summary.svg
uv run python $R $S $S/session-summary.es.content.json $S/session-summary.es.svg
| Flag | Meaning |
|---|---|
<session_dir> |
Directory holding transcripts.jsonl; stats are computed from it |
<content.json> |
Content produced by the run |
<out.svg> |
Destination; the matching .png is written beside it |
--no-png |
Skip the PNG. Draft re-renders only; a final render must not use it |
render.py writes the SVG, validates that it parses as XML, then exports the PNG with
Inkscape and quantizes it with ImageMagick (magick). Both must be on PATH; a missing
binary makes the run fail loudly instead of leaving a silent fallback. It prints
wrote <svg> and wrote <png> (<n> KB), and warns when the content JSON lacks an
opportunities or blockers key.
brief.md is written live by a small, fast model, so the skill treats it as unreliable and
rewrites it after reconstructing from the JSONL. The error classes it checks come from real
failures and map directly onto known live-mode behaviour:
…Open Ques) — the same failure the character cap
used to cause before the brief was made non-destructive;Unknown participant for lines the JSONL attributes to a named speaker;Name and term corrections are applied through the glossary (for example "Good One" → HUD-1).
.opencode/skills/session-summary/references/glossary.md is the sole file outside the session
directory a run may modify. It holds domain terms and known ASR mishearings, and every new row
cites its evidence as (<session-id>, seg <n>). That is deliberate: it is how knowledge
survives across sessions without a run ever reading another session's evidence.
It is gitignored private state, like questions.json: it accumulates client vocabulary from
real recordings, so it never enters the repository. A fresh clone has no glossary, and the first
run creates one from what it observes. Losing it costs accumulated corrections, not data.
.opencode/ is gitignored (it holds node_modules and local agent state). The skill directory
is the exception — it is tracked repo tooling, minus its glossary. The rule lives in
.gitignore as a progressive un-ignore, with the glossary re-ignored last:
.opencode/*
!.opencode/skills/
.opencode/skills/*
!.opencode/skills/session-summary/
.opencode/skills/session-summary/references/glossary.md
Two things stay untracked: the glossary (private client vocabulary, see above) and everything the
skill writes. The outputs — the session directory and its SVG/PNG/JSON — are gitignored with
transcripts/, and the corrected brief.md lives inside that directory. Nothing this skill
writes is ever committed.
| Symptom | Cause |
|---|---|
error: inkscape not found / magick missing |
Install both; the PNG step has no fallback |
PNG is ~1 MB |
Quantization skipped; re-run without --no-png |
no 'opportunities' key warning |
The content JSON is missing a required block; add it and re-render |
| SVG opens clipped or overlapping | Do not hand-write the SVG; fix the content JSON and re-render |
| Run reports unresolved tokens | Expected when the audio is genuinely ambiguous; they belong in the glossary |
See also OUTPUT.md for the JSONL fields the reconstruction depends on, and
TRIAGE.md for how brief.md is produced live.