SESSION-SUMMARY.md 7.1 KB

Session summary (post-conference reconstruction)

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.

Inputs

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:

  • A run touches exactly one session directory. It must not glob, list, or compare other sessions: cross-session knowledge only reaches it through the glossary.
  • transcripts.jsonl and audio/ are never modified.
  • Every claim in the output must be traceable to a seg_id. If it cannot be, it is not written.
  • Paraphrase, never invent. An unresolvable token is reported as unresolved, not guessed.

Outputs

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.

How to run it

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.

The brief is corrected, not trusted

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:

  • sections and sentences cut off mid-word (…Open Ques) — the same failure the character cap used to cause before the brief was made non-destructive;
  • the same fact repeated in slightly different wording;
  • Unknown participant for lines the JSONL attributes to a named speaker;
  • ASR mishearings copied literally;
  • mis-detected languages reported as statements ("said in Cyrillic");
  • hedged statements promoted to "approved" decisions or "confirmed" opportunities;
  • reversed direction (buyer vs seller, who pays whom);
  • worked examples, on-screen steps and numbers dropped;
  • acknowledgements logged as facts.

Name and term corrections are applied through the glossary (for example "Good One" → HUD-1).

The glossary is the only shared state

.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.

Version control

.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.

Troubleshooting

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.