The job: let someone who missed the interview see what was said, by whom, and when, without reading the transcript. Each theme is a row. Time runs left to right. Each card is one extract quoted word for word, and it links back to the line it came from.
Felt from the chair: "I can see where the pain clustered and where they contradicted themselves, and one click takes me to the exact line." Judge every write by that sentence.
Everything runs through cnotes. The cnotes skill documents every command
used here (flags, JSON shapes, operations, relationship mentions, canvas
layout, the humanizer). Consult it rather than guessing. This skill adds no
commands.
The model
| Concept | CreatorNotes shape |
|---|---|
| Source | One Transcript note holding a pasted Zoom transcript (HH:MM:SS or MM:SS stamps, speaker labels). Read it, never rewrite it |
| Extract | One note per extract, typed by its class (Observation, Claim, Problem, Idea, Requirement, Quote, Tension when the workspace has them). Body opens with the verbatim quote. Mapping and fallbacks in references/classification.md |
| Card | That note placed on the canvas at its timestamp. Shape in references/card-format.md |
| Theme | A section frame spanning the full timeline width, one per theme, 3 to 6 per interview |
| Canvas | <Interviewee or company> · Interview timeline, one per transcript |
| Banner | Four short lines above row one. The last is a bare Read left to right. |
Run
- Read the source.
cnotes notes get TRANSCRIPT-N --content-only. Note the first and last timestamps and the speakers. If the stamps are missing or not monotonic, stop and say so; a timeline without times is a guess. - Read the rubrics.
cnotes types list, thencnotes types show <Type>for every type you will write. Author each note to its rubric. Never create a type; fall back as classification.md says. - Extract. Walk the transcript once. Each extract is the shortest run of
the interviewee's own words that carries one point, with its start stamp
and speaker. Keep the words exactly, including "um" when it changes the
meaning; cut with
…only at the ends. Interviewer lines are context, not extracts. Aim for 15 to 40 extracts in a 30-minute call. - Classify, with guards. Score every candidate class from 0.0 to 1.0 per
references/classification.md. For each
extract record: the driving phrase (the exact words, copied from the
transcript, that tipped the label), the top class and its score, and a
one-line reason. If the top two scores are within 0.15 of each other, it is
a close call: do not pick. Keep both classes on the card, tag it
needs-label-choice, and let a person choose. Mark Contradiction only when two extracts from this call disagree, and keep both. Before writing, check every driving phrase is a verbatim substring of the transcript (grep -F); fix or drop any that is not. - Theme. Group extracts into 3 to 6 themes named in the interviewee's terms ("Month-end close", not "Process friction"). An extract sits in one theme only.
- Open a draft, then the run. Build inside a private draft by default so a
person reviews the board before it lands live:
cnotes draft open "<Interviewee> interview timeline" --intent "<what is missing now, in the reviewer's words>". The intent must name the problem, not the task, or the server rejects it. Thencnotes operations begin --prompt "Mapped <interview> onto a timeline". Only work live when the user asks for it. - Write the notes. One
cnotes notes create --notes '<json array>'with every extract, each body in the card format, each linking the source with[TRANSCRIPT-N: <title>](relationship:derived-from)and its timestamp. Contradictions also link each other withrelationship:contradicts. - Build the canvas. Each edit is its own command:
cnotes canvas create "<name>" --goal "Show what <who> said about <topic>, in order. Done when every extract sits in its theme row at its timestamp."- the banner:
cnotes canvas add-text <canvasId> --content-file banner.md --size medium --x 0 --y 0 - one
cnotes canvas add-section <canvasId> --name "<theme>" --x 0 --y <rowY> --width <w> --height <h>per row (add-section takes--x/--ydirectly; no follow-upupdate-sectionneeded) - one
cnotes canvas add-node <canvasId> --note <ID> --x <x> --y <y>per card, coordinates from references/layout.md - a contradiction pair gets
cnotes canvas add-edge <canvasId> --source <ID> --target <ID> --label "contradicts" --line-style dashed --arrow none(contradiction has no direction; the default arrow isend) Raw--x/--yis deliberate here: position carries meaning. Runcnotes canvas status <canvasId> --jsonafter the cards land and fix overlaps withcnotes canvas move-node <canvasId> --node <items[].id> --type <note|richtext|section> --x <x> --y <y>per layout.md (--nodeisitems[].idfrom that JSON; the table's REF is a display ID, which move-node rejects), nevercanvas placeorcanvas arrange, which would throw away the time axis.
- Check.
cnotes canvas read <canvasId>: every extract appears under its theme, every card links its source. Then the three completion tests from the cnotes skill. End the run withcnotes operations end(add--unsure "<call and alternative>"where a theme or class was a judgement call, and list every close call). Thencnotes draft status: zero blocking checks. Do not ask, accept or merge; runcnotes draft leaveso the shared CLI is not left checked out. - Report. The PROPOSAL ref and review link, the canvas ref and link, the count per theme, and any contradiction found. Nothing else.
Optional: resolve and delegate
Only when asked ("resolve these", "who owns what"). Run it before step 9's
operations end, inside the same draft.
- Group related extracts into 12 to 20 outcomes in the interviewee's own vocabulary: Opportunity, Need (a Requirement), Desire (an Idea, fallback Feedback), Pain point (a Problem, fallback Observation), Decision input (a Question), or Watch (a Risk). No tickets: those live in other systems. Read each type's rubric first; never create a type.
- One
notes createbatch. Each outcome states the outcome,## Owner(a role: Product, Finance-ops research, the user, or an agent),## Next action,## Driving quote(verbatim, from one source extract),## Confidence(score and reason, same guard as step 4), and## Derived fromwith a[ID: Title](relationship:derived-from)per source extract. Questions also carry what they gate, a lean, and what would flip it. - Six sections to the right of the rows, top to bottom: Opportunities,
Needs, Desires, Pain Points, Decision Inputs, Watch. One
cnotes canvas add-section <canvasId> --name "<section>" --notes <ids> --columns 3 --x <right of rows + 280> --y <below the previous section>each. - At least one
becomesedge into each Need, Desire and Pain Point card, three to five elsewhere:canvas add-edge ... --label "becomes"from a source extract to its outcome; pick short, non-crossing ones. Thencanvas status: no overlaps.
Writing rules
- Quotes stay verbatim. Never tidy grammar, merge two turns, or paraphrase inside the quote block. Your own words go in the title only.
- Titles say the point in the interviewee's direction: "Reconciling two ledgers eats the first Monday of every month".
- Name notes with display IDs as link text, always as a relationship mention. Never bare prose IDs.
- No caption or explainer slop. No "This card captures…", no "Key insight:", no recap text cards under rows. A row's frame name is its only label.
- The banner is four short lines: what happened (dated, named), what the
board is for, who acts on it, then
Read left to right.and nothing more. - Run the humanizer from the cnotes skill on every title and the banner.
- End-user PII stays out. Name the interviewee by role and company unless the transcript note already names them in its title.
Invariants
- The transcript note is never edited or tagged by this skill.
- Every card is a note with a verbatim quote, a verbatim driving phrase, a
confidence score with reason, and a
derived-fromlink to the source, carrying its timestamp. - A close call (top two within 0.15) is never resolved by the skill. Both
labels stay on the card, tagged
needs-label-choice, until a person picks. - x is a pure function of the timestamp, the same scale for every row.
- One theme per extract; one row per theme.
- Each canvas edit is its own command.
- Nothing is triaged, scheduled, or turned into an Attention card. That is attention-planner's job. The optional resolve step names owners and next actions only; it schedules nothing.
Card format
Each extract is one note. The canvas card is that note.
Shape
# <Point in the interviewee's terms, under 12 words>
> <verbatim quote>
**<Speaker role, Company>** · <HH:MM:SS>
Source: [TRANSCRIPT-N: <transcript title>](relationship:derived-from) at <HH:MM:SS>
Driving phrase: "<exact words from the quote that drove the label>"
## Class
<Class> · confidence <0.00-1.00>: <reason, under 15 words>
Close call (top two within 0.15), replacing the Class block:
## Class: needs your choice
- [ ] <Class A> · confidence <0.xx>: <reason>
- [ ] <Class B> · confidence <0.xx>: <reason>
- Driving phrase: verbatim substring of the quote, in straight double quotes.
- Confidence: two decimals, always with a reason.
- Close-call cards add the tag
needs-label-choice.
Outcome cards
# <Outcome in the interviewee's terms>
<Two or three sentences: what it is and why it matters.>
## Driving quote
> <verbatim, from one source extract> (<HH:MM:SS>)
## Confidence
<0.xx>: <reason> (or both labels with scores, as above, for a close call)
## Owner
<role>
## Next action
<one concrete step>
## Derived from
- [<ID>: <title>](relationship:derived-from)
- Title: your words, the point, no class prefix.
- Quote: exact words,
…only at the ends. - Contradiction cards add one line under Source:
Contradicts [OBSERVATION-M: <title>](relationship:contradicts). - Tags:
transcript-timeline, the theme slug.
Filled example
# Month-end close eats the first three days
> Honestly the close eats the first three days of every month, I basically don't see my kids.
**Finance lead, Harrowgate Bikes** · 00:06:42
Source: [TRANSCRIPT-31: Sample · Harrowgate Bikes interview](relationship:derived-from) at 00:06:42
Driving phrase: "eats the first three days"
## Class
Pain point · confidence 0.92: names a recurring cost in time
Classification
One class per extract. When torn between two, pick the one that names what the speaker would act on.
| Class | Definition | Tell-tale phrasing | Example | Note type (fallback) |
|---|---|---|---|---|
| Observation | Something the speaker saw or does, stated as fact about their world | "What we do is…", "Every month we…", "I noticed…" | "We export to Excel every Friday and fix the codes by hand." | Observation (Note) |
| Claim | An assertion about cause, value or the market that could be wrong | "The reason is…", "Nobody uses…", "It's always…" | "Honestly, nobody on the floor reads the dashboard." | Claim (Assumption) |
| Pain point | A cost they feel now: time, money, risk, embarrassment | "drives me mad", "we lose", "it takes forever", "I dread" | "Close eats the first three days of every month." | Problem (Observation) |
| Desire | Something they wish for, framed as a want, not a must | "I'd love…", "It'd be nice if…", "If I had a magic wand…" | "I'd love to see variance before the CFO does." | Idea (Feedback) |
| Need | A requirement without which they won't adopt or can't work | "We have to…", "It must…", "Without X we can't…", "Audit needs…" | "Anything we buy has to keep a full audit trail." | Requirement (Note) |
| Quote-worthy (optional) | A line worth repeating verbatim in a deck or pitch | Vivid, short, self-contained | "Spreadsheets are where our accuracy goes to die." | Quote (Note) |
| Contradiction (optional) | Two extracts from this call that cannot both be true | A later turn reverses an earlier one | "Nobody here touches Excel anymore." vs "We still export to Excel every Friday." | Tension (Insight); link the pair with relationship:contradicts |
Rules
- Check
cnotes types listbefore writing. Use the type in the last column if it exists, otherwise its fallback. Never create a type. - Read each type's rubric with
cnotes types show <Type>before authoring.
Guards
- Driving phrase. For each extract, name the shortest exact run of words
inside the quote that tipped the label (usually a tell-tale from the table).
It must be a verbatim substring of the transcript. Check with
grep -F "<phrase>"on the saved transcript; no match means fix or drop. - Confidence score, 0.0 to 1.0, for the top class, with a reason under
15 words.
- 0.85 to 1.0: the driving phrase alone carries the class.
- 0.6 to 0.84: the phrase points that way, context confirms it.
- below 0.6: you are reading between lines. Still goes on the board. Also score the runner-up class.
- Close call. If top minus runner-up is under 0.15, do not choose. The
card shows both classes with scores, gets the tag
needs-label-choice, and takes the note type of the higher one (ties: the one the speaker would act on). A person picks; the skill never resolves it later.
Outcome sections
Outcomes use the interviewee's vocabulary, not delivery-system words. Tickets belong to other systems and are not produced.
| Section | Note type (fallback) |
|---|---|
| Opportunities | Opportunity |
| Needs | Requirement (Note) |
| Desires | Idea (Feedback) |
| Pain Points | Problem (Observation) |
| Decision Inputs | Question |
| Watch | Risk |
Each outcome carries the same guards: a driving quote copied from one source extract, a confidence score with reason, and both labels when it is a close call.
- Interviewer lines are never extracts.
Layout
Position carries meaning, so cards use raw --x/--y from the math below.
Constants
| Name | Value | Why |
|---|---|---|
| CARD_W | 340 | default note card width |
| CARD_H | 130 | default note card height |
| PX_PER_MIN | 120 | a 30-minute call is 3,600px wide |
| LEFT | 80 | inset inside a row frame |
| ROW_GAP | 80 | between frames |
| BANNER_H | 400 | space reserved above row one (a four-line medium text renders about 375px tall) |
Timestamp to x
t = seconds since the first stamp in the transcript
x = LEFT + round(t / 60 * PX_PER_MIN)
W = LEFT * 2 + ceil(T_end / 60 * PX_PER_MIN) + CARD_W # every frame gets the same width
Calls over 60 minutes drop PX_PER_MIN to 60. One scale per canvas, all rows.
Rows
- Row order: the theme whose first extract comes earliest goes on top. Ties go to the theme with more extracts.
- Each row frame:
x = 0,y = BANNER_H + sum(previous row heights + ROW_GAP), widthW, heightlanes * (CARD_H + 20) + 60. - A card's y is
rowY + 40 + lane * (CARD_H + 20).
Dense clusters
Two cards collide when their x differ by less than CARD_W. Put the later one in the lowest lane whose last card ends at least CARD_W to its left (lane 0, 1, 2), at its true x. At four lanes, keep the x, stop stacking, and merge nothing: grow the row instead. Never nudge x to make room; a shifted card lies about when it was said.
Banner
A medium text element at x = 0, y = 0. Four short lines, no colour:
# <Interviewee role> at <Company> · <date>
<Interviewer> interviewed them about <topic> for <N> minutes.
Rows are themes; each card quotes them at the moment they said it.
Read left to right.
Line 3 may instead name who acts on the board. The last line is always the
bare Read left to right.
Optional time ruler
A small text element per 5 minutes above row one (00:05, 00:10) at the
matching x. Skip it for calls under 15 minutes.
Outcome sections (optional resolve step)
Right of the rows at x = W + 280, stacked top to bottom with ROW_GAP between:
Opportunities, Needs, Desires, Pain Points, Decision Inputs, Watch. Three
columns each (--columns 3). No Tickets section. Close-call cards render
taller (two Class lines); run canvas status and move overlaps down, never
sideways.