← Vault Index
Source: frameworks/plugin-engagement-manager/advisory-sessions/skills/session-ledger/SKILL.md

name: session-ledger description: Turns an advisory session transcript into a gated ledger — every fact carrying a quote, a speaker, a timestamp, a modality tag and a date state. Produces the same JSON shape every time and fails closed on any claim without a quote. Use when a session transcript needs processing, when asked to build the ledger, or as the first step of any post-session run.


Session ledger

Read a transcript and produce ledger.json. Every later step reads this file and nothing else, so this is the only place the transcript is ever open. Get it right here or it is wrong everywhere.

Before anything

Read the engagement record at engagements//engagement.json. It carries the engagement type, the principals, the recap recipients, the client timezone, the document store, the scope fences, and the path to reference data. Do not infer an engagement from a folder name.

If it does not exist, stop — and stop loudly. This is the most common way a run fails, and a silent stop reads to Kathryn as the whole plugin being broken. Say, in these terms:

No engagement record found at engagements//engagement.json. Nothing downstream can run without it. The path is relative to the working directory — this run's working directory is , so a record that exists in another workspace (a Cowork session, another repo, a cloud container) is not visible here. Either point me at the right directory, or copy the template at reference/engagement-record.md and fill in slug, type, principals, recapRecipients and timezone. That takes about five minutes and it is a one-time cost per engagement.

Print the working directory. Never guess at a record, and never proceed on a partial one.

Then read reference data. Every proper noun in the ledger gets checked against it.

Get the transcript

From whichever the user has: a file they name, a transcript in the conversation, or their ~~transcription tool. If none exists, say so and stop. Never build a ledger from memory, from notes about the call, or from a prior recap.

Write the transcript to a file first, always. Pull it from the tool, save it into the session folder, then read the file. A ninety-minute session runs 80,000 to 100,000 characters and will not survive being passed through a conversation intact.

Three rules about the source

  1. Read it in full, cover to cover. If it does not fit one read, read it in ordered passes until you have read all of it. Never grep it. Never search it for the parts you expect to matter. Never sample it. What you are looking for is what you did not expect, and search only returns what you already thought of.
  2. Never read the tool's summary. Otter, Zoom, Fathom and the rest generate one. Do not open it, do not quote it, do not read it first to orient. It has already flattened hedges into statements, which is the exact error this ledger exists to prevent. Recorded evidence: Otter's summary of a 2026-08-12 succession session reported "Steven acquiring 30% by 2027 and Bev retaining 70%" as settled. The transcript says the gifting schedule is settled and the purchase is not, because the debt service had not been calculated.
  3. Read the meeting chat before the transcript. Where a chat export exists, anything typed is exact and the transcript of the same content is lossy. The chat wins on typed lists, links, targets, and documents shared. Reproduce typed content in full — never as a pointer to "the list from chat," because the chat panel disappears for the client and the recap is the durable record.

The claim gate

Every factual row carries a verbatim quote, a speaker, and a timestamp. A paraphrase in the quote field is a failure, not a shortcut — it is the most common way a wrong fact gets through, because a paraphrase reads like a quote once it is in a field named quote.

Run the gate before writing anything else:

py gateclaims.py /ledger.json # Windows python3 gateclaims.py /ledger.json # macOS / Linux / cloud

Exit 0 = clear. Exit 1 = blocked, with the failing rows. Fix the rows, not the gate.

Rows that are Kathryn's read rather than something said get modality: judgment and need no quote — but they must name the claim ids they are built on.

Modality — four values, and they survive to the end

ValueMeans
statedSomeone said this plainly and it landed
hedgedExplored, not settled. "I think," "probably," "I need to figure out," "we could"
advisor-confirmedKathryn confirmed it in conversation outside the transcript
judgmentKathryn's read on top of named facts. Never presented as something said

A hedged row may never appear as a flat statement in anything the client reads. This is the tag with the highest cost of failure — in a succession conversation between family members, most of the ownership talk is exploration, and flattening it manufactures agreement nobody gave.

Date state — three values, never converted silently

The transcript saysRecord
A real date or day — "Thursday," "the 14th"the date as stated, dateState: stated
A time frame with no date — "this week," "before the season"dateState: vague, words: [their exact phrase]
NothingdateState: none

Never turn a vague one into a date here. That conversion is a decision, it happens downstream, in the open, and it gets reported. Never derive an event date from another loose phrase — "two weeks before the boot camp" with no boot camp date gives you two unknowns, not one date.

Record whose ask produced a date. A date the client asked for is not a date Kathryn gave.

Outcomes — decided, shaping, open

Each outcome carries a status and, where the room named one, what it displaces.

A decision states what happened. An implication states what it changes. If the review page is thinner than the documents it gates, it approves a summary that omits the thing that mattered. For every decided row ask: what does this displace, unblock, or make obsolete? If the room named it, it belongs in the row.

Consent flags

Record any decision reached after a party left the call, or agreed with only one principal present — a time change, a scope change, a commitment. Include who was absent and what they had asked for. These are not fact errors and no gate catches them. They go to the top of the report.

Proper nouns

Three buckets, and only the first is usable.

Output

Write ledger.json into engagements//sessions//, using the date of the session, not today's. Follow schema.md exactly — every downstream skill and both scripts read it by field name.

Set sourceIntegrity honestly. transcriptReadInFull is false if you read part of it. toolSummaryUsed is false because you did not open it. If either is wrong, everything built on this ledger is wrong and nothing downstream can tell.

Then

Write run-plan.json (see the agent), then run session-digest. Stop there. Phase A ends at the digest.