From c98daed9846c35372d0f4d8e4827426a90122b8b Mon Sep 17 00:00:00 2001 From: "Bryan Gilliom (via Claude)" Date: Tue, 22 Sep 2026 17:37:52 +0000 Subject: [PATCH] =?UTF-8?q?Add=20internal-meeting-brief=20=E2=80=94=20firs?= =?UTF-8?q?t=20real=20skill=20in=20the=20Brief=20family?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Real-tested 2026-09-21 against the APTA 2026 booth 09-16 planning meeting (recap mode). Includes: - skills/internal-meeting-brief/SKILL.md — full workflow: topic resolution, continuity manifest, agenda/recap branching, attendee capture/normalization, scoped data pulls, synthesis, render, archive. - assets/brief-components.css — canonical shared component library (cards, flow, layerbox/filepill, unitgrid, quad, compare, specbar, actions+status pills, note callouts x4 tones, colvis/ring), MPM tokens from CW-028, required light/dark toggle, print rules. - references/section-structure.md — fixed-vs-dynamic section contract, explicitly marked unproven beyond one real run. Known limitation: Plaud MCP connector is currently non-functional (local server via Claude Desktop, times out). Brief was built from a manually uploaded transcript, not a live pull. Five more skills planned, not started: vendor-partner-brief, status-update-brief, five-whys-brief, kickoff-brief, development-brief. Full design history in CW-027's Concept.md (Drive). --- .claude-plugin/plugin.json | 9 + README.md | 40 ++- skills/internal-meeting-brief/SKILL.md | 142 +++++++++++ .../assets/brief-components.css | 236 ++++++++++++++++++ .../references/section-structure.md | 63 +++++ 5 files changed, 488 insertions(+), 2 deletions(-) create mode 100644 .claude-plugin/plugin.json create mode 100644 skills/internal-meeting-brief/SKILL.md create mode 100644 skills/internal-meeting-brief/assets/brief-components.css create mode 100644 skills/internal-meeting-brief/references/section-structure.md diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json new file mode 100644 index 0000000..7cde1cc --- /dev/null +++ b/.claude-plugin/plugin.json @@ -0,0 +1,9 @@ +{ + "name": "brief", + "version": "0.1.0", + "description": "MPM-branded briefing infographics for client/partner, internal, and project meetings. Single-file HTML artifacts, shared component library, agenda/recap modes. First skill shipped: internal-meeting-brief. Five more planned: vendor-partner-brief, status-update-brief, five-whys-brief, kickoff-brief, development-brief.", + "author": { + "name": "Bryan Gilliom" + }, + "keywords": ["briefing", "meeting", "html", "mpm", "apta"] +} diff --git a/README.md b/README.md index 378d7f8..5975301 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,39 @@ -# brief +# Brief (CW-027) -CW-027 — MPM Brief: a family of CoWork skills that generate single-file HTML briefing infographics (client/partner, internal-planning, status-update) on a shared MPM-branded visual component system. \ No newline at end of file +A family of CoWork skills that generate single-file HTML briefing infographics for +Message Point Media meetings — client/partner, internal, and project — on one shared +MPM-branded visual component system. Originates from a bilingual template Roger Lu +(Humax) shared with Bryan; reskinned entirely to MPM's brand (CW-001 / CW-028) and +English-only. + +## Status: 1 of 6 skills built + +| Skill | Status | +|---|---| +| `internal-meeting-brief` | **Built.** Real-tested 2026-09-21 against an actual APTA 2026 booth planning meeting (recap mode). | +| `vendor-partner-brief` | Not started | +| `status-update-brief` | Not started | +| `five-whys-brief` | Not started | +| `kickoff-brief` (3 audience variants) | Not started | +| `development-brief` (software/hardware/product) | Not started | + +Full design history, the data/continuity architecture, and delivery/hosting plan +(deferred to CW-029, "Brief Server") live in CW-027's Concept.md on Drive — read that +before starting work on any of the remaining five skills. + +## Architecture in one paragraph + +Each skill pulls its own facts from connected tools (Plaud, Odoo, Gmail, Google Chat) +rather than requiring hand-assembled input, maintains continuity per real-world +project/topic via a Drive folder + `_topic-state.md` manifest (not the ephemeral +sandbox), and renders through one shared component library +(`skills/*/assets/brief-components.css`, tokens sourced from CW-028) rather than +per-brief CSS. Hosting/publishing is intentionally out of scope for this repo — see +CW-029. + +## Known issue + +The Plaud MCP connector is currently broken (times out; appears to run as a local +server via Claude Desktop, not a cloud connector). The one real brief produced so far +used a manually uploaded transcript as a workaround. Needs a real fix before recap mode +can run unattended. diff --git a/skills/internal-meeting-brief/SKILL.md b/skills/internal-meeting-brief/SKILL.md new file mode 100644 index 0000000..eb30f7a --- /dev/null +++ b/skills/internal-meeting-brief/SKILL.md @@ -0,0 +1,142 @@ +--- +name: internal-meeting-brief +description: Generate an MPM-branded internal meeting briefing document as a single-file HTML artifact — covers internal planning sessions, executive leadership meetings, and project team meetings (e.g. APTA planning, status reviews, internal design discussions). Produces agenda-mode (pre-meeting prep, pulling the previous meeting's transcript) or recap-mode (post-meeting summary, pulling the current meeting's transcript). Always use this skill when the user asks to "brief this meeting," "recap the meeting," "prep me for [meeting]," "write up the [meeting name] meeting," or names an internal MPM meeting/topic and wants it documented or summarized — even if they don't say "internal-meeting-brief" by name or don't mention CoWork/Brief explicitly. Part of the CW-027 Brief plugin family; see git.mpm.to/mpm/brief. +--- + +# internal-meeting-brief + +Generates a single self-contained HTML briefing document for an internal MPM meeting, +built on Brief's shared MPM-branded component library. Does the work of assembling the +brief itself — pulling from connected tools — rather than requiring the person to +hand-supply meeting notes. + +Read `assets/brief-components.css` and `references/section-structure.md` before +generating any brief. The CSS is the canonical, only source of Brief's visual +language — never re-derive it inline. The section-structure doc is the fixed-vs-dynamic +contract for what this skill's output actually contains. + +## Prerequisites + +This skill uses, but does not own, the following connected tools — confirm they're +reachable before starting, and degrade gracefully (see Hard Rules) if one isn't: +- **Plaud** — meeting transcripts (recap: current meeting; agenda: previous meeting) +- **Odoo** (MCP) — linked Project/tasks, Sales/Purchase Orders, Knowledge Base, + Helpdesk tickets +- **Google Workspace** (MCP) — Gmail, Google Chat, Drive, Sheets +- **Google Drive** — the topic's continuity folder (`_topic-state.md` + brief history) + +If any of these fail outright (not just "returns nothing," but errors or times out), +say so plainly in the generated brief's Notes & Flags section rather than silently +omitting that source. See "Known limitation" below for a real, currently-open example. + +## Workflow + +### 1. Resolve the topic +Every brief belongs to a project/topic, not just a meeting instance. Ask which +topic/project this meeting is about if it isn't obvious from context. Search Google +Drive for an existing topic folder (naming pattern: ` — Meeting Briefs`) +before creating a new one. If an Odoo Project already exists for this topic and has an +attached Drive folder, use that folder instead of creating a parallel one. + +### 2. Read (or create) the continuity manifest +Open `_topic-state.md` in the topic folder. If it doesn't exist, this is the topic's +first run — create it with the schema below, and expect a fuller interview in the +following steps since there's no history to draw on yet. + +`_topic-state.md` schema: linked Odoo Project ID / SO / PO, linked Google Chat Space, +Plaud recording ID/pattern, last-meeting date, running open-items/decisions ledger, +attendee list, learned spreadsheet task-registry column mapping (if this topic uses one +— see step 5), brief-history log (date/type/mode/link), and a "Related documents" +table for cross-referencing other MPM document types about the same real-world topic +(pre-mortems, BAI build docs, etc. — see CW-027 Concept.md's rewrap-vs-harvest +principle; don't merge their content into this ledger, just reference them). + +### 3. Determine mode: Agenda or Recap +Agenda mode (pre-meeting prep) pulls the *previous* meeting's transcript and any +updates since. Recap mode (post-meeting) pulls the *current* meeting's transcript. Ask +if not specified by the request. + +### 4. Capture and normalize attendees +- **First run for this topic:** ask who's attending / who attended. +- **Recurring topic:** pre-fill from the manifest's last attendee list and ask "same as + last time, or any changes?" — not a blank-slate interview. +- **Recap mode with a Plaud transcript available:** prefer *actual* attendance from the + transcript's speaker attribution over the pre-meeting expected list — someone who + showed up unexpectedly and spoke shouldn't be treated as absent. +- **Normalize into two groups:** + - Internal MPM attendees — record by name for the brief; no further resolution + needed (no external allowlist implications for this brief type). + - External attendees (rare for this brief type, but possible) — cross-reference + against Odoo contacts to resolve/confirm email addresses rather than trusting raw + input. +- **If Plaud's diarization didn't resolve a speaker to a name:** render the literal + transcript label ("Speaker 1," "Speaker 3"). Do not guess a name from context, even + when a guess feels obvious. Flag unresolved speakers in the Notes & Flags section. + +### 5. Pull data, scoped to what this brief type actually needs +Not a monolithic "pull everything" — internal-meeting-brief's real needs, based on the +first run, are: +- Plaud transcript (per mode, above) — the primary source +- Gmail / Google Chat: updates since the manifest's last-meeting date, scoped by + project/topic keywords, never a blanket search +- Odoo Project tasks, if a linked project exists (expect this to be sparse or absent — + PM-tool adoption is inconsistent; fall back to a spreadsheet task registry if the + topic uses one, learned via a one-time interview on first use and stored in the + manifest, never assumed to follow a universal schema) + +Sales/Purchase Orders and Helpdesk ticket review are not typically relevant to this +brief type (they matter more to vendor-partner-brief and status-update-brief) — don't +pull them by default. + +### 6. Synthesize into the section structure +Follow `references/section-structure.md` exactly: six fixed sections in order, dynamic +sections only where the meeting's actual content has a structure that calls for one. +Real, verified content over generic summary — carry forward specific facts (names, +dates, exact technical decisions), not vague paraphrase. + +### 7. Render +Single self-contained HTML file. Include `assets/brief-components.css` inline (don't +link out to it — the brief must survive as a standalone file). Include: sticky jump-nav, +a working light/dark toggle (`data-theme` attribute, default light), and the +`@media print` rules from the shared CSS (forces light, hides nav/toggle, avoids +awkward page breaks). + +### 8. Archive +Save the generated HTML into the topic's Drive folder. Update `_topic-state.md`: append +to the brief-history log, update the running open-items/decisions ledger (carry forward +anything still open from this run), update the attendee list, update last-meeting date. + +### 9. Present +Hand the file to the person. Don't silently skip presenting it even if archived — the +person needs to actually see and review it, not just trust it happened. + +## Hard rules + +- **Never fabricate.** No matching Plaud recording, no linked Odoo data, an empty + Gmail/Chat scan — say so plainly in Notes & Flags. A brief with visible gaps is + correct; a brief with invented content to fill them is not. +- **Bounded queries only.** Gmail/Chat scans are scoped by project keyword + date + window from the manifest. Never an open-ended search. +- **No live publishing yet.** This skill produces a local file only. Hosting/publishing + (a shareable link, external access control) is CW-029 (Brief Server) — deliberately + separate, deliberately not built yet. Don't attempt to stand up delivery + infrastructure as part of running this skill. + +## Known limitation (open as of 2026-09-21) + +The Plaud MCP connector has failed on every attempt so far — first appeared to be an +account/workspace mismatch, but a later attempt timed out with a message indicating it +runs as a **local server via the Claude Desktop app**, not a cloud connector. Confirmed +still broken after Bryan verified the connector's own settings looked correct. Treat +Plaud as unreliable until this is resolved — the one real brief produced so far +(2026-09-16 APTA meeting) used a manually uploaded transcript as a workaround, not a +live pull. Don't assume this is fixed without testing it again. + +## Provenance + +Component library, tokens, and this workflow were derived from two real test runs +(2026-09-21): a recap brief for a real APTA 2026 booth planning meeting, and a +rewrap of an unrelated pre-mortem document to validate the component system against a +different content shape. See CW-027's Concept.md (Drive) for full design history and +the five other planned skills in this family (vendor-partner-brief, status-update-brief, +five-whys-brief, kickoff-brief, development-brief) — none built yet. diff --git a/skills/internal-meeting-brief/assets/brief-components.css b/skills/internal-meeting-brief/assets/brief-components.css new file mode 100644 index 0000000..c823500 --- /dev/null +++ b/skills/internal-meeting-brief/assets/brief-components.css @@ -0,0 +1,236 @@ +/* ========================================================================== + Brief — shared component library (CW-027) + Canonical CSS for all Brief skills. Do not fork per-brief — edit here. + + Design tokens sourced from CW-028 (@jason/ui-kit, src/lib/tokens.json). + Light theme is default; dark theme via [data-theme="dark"]; print always + forces light regardless of the on-screen toggle state. + + Re-pull tokens from git.alwisp.com/jason/ui-kit at each Brief release in + case Jason has updated them — see CW-027 Concept.md, "Design system + source of truth." + ========================================================================== */ + +:root{ + --bg:#FAF8F4; --surface:#FFFFFF; --surface-2:#F4F0EA; --border:#DED8D1; + --text:#272326; --muted:#665F62; + --brand:#79640E; --brand-bright:#665308; --brand-dark:#5C4B07; --brand-fg:#FFFFFF; + --success:#217A4A; --success-fg:#FFFFFF; + --warning:#7A5B00; --warning-fg:#FFFFFF; + --danger:#A42D20; --danger-fg:#FFFFFF; + --info:#366B99; --info-fg:#FFFFFF; + + --radius-sm:6px; --radius-md:10px; --radius-lg:14px; --radius-xl:20px; + --shadow-sm:0 1px 2px 0 rgb(20 16 18 / .10); + --shadow-md:0 4px 12px -2px rgb(20 16 18 / .14), 0 2px 4px -2px rgb(20 16 18 / .10); + --shadow-lg:0 12px 32px -8px rgb(20 16 18 / .20), 0 4px 8px -4px rgb(20 16 18 / .12); + --shadow-glow:0 0 0 1px rgb(121 100 14 / .18), 0 8px 28px -6px rgb(121 100 14 / .20); + --ease-out:cubic-bezier(0.22,1,0.36,1); + --dur-fast:120ms; --dur-base:180ms; --dur-slow:320ms; +} +[data-theme="dark"]{ + --bg:#232022; --surface:#2B282A; --surface-2:#333031; --border:#3A3638; + --text:#F5F1EC; --muted:#A99F97; + --brand:#DCBB4F; --brand-bright:#F5CD15; --brand-dark:#998643; --brand-fg:#232022; + --success:#62C890; --success-fg:#232022; + --warning:#E4C85B; --warning-fg:#232022; + --danger:#D76F4A; --danger-fg:#232022; + --info:#76A9D6; --info-fg:#232022; + --shadow-glow:0 0 0 1px rgb(220 187 79 / .20), 0 8px 28px -6px rgb(220 187 79 / .28); +} + +/* Fonts: production should self-host from CW-001's assets/fonts/*.ttf. + This @import is a portability fallback for previewing outside that + pipeline — swap it for local /@font-face at publish time. */ +@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@600;700&family=Open+Sans:wght@400;600&family=JetBrains+Mono:wght@500&display=swap'); + +*{box-sizing:border-box;} +body{ + margin:0; background:var(--bg); color:var(--text); + font-family:"Open Sans",system-ui,sans-serif; line-height:1.55; + transition:background var(--dur-base) var(--ease-out), color var(--dur-base) var(--ease-out); +} +h1,h2,h3,h4{font-family:"Montserrat",system-ui,sans-serif;} +code,.mono{font-family:"JetBrains Mono",ui-monospace,monospace;} + +/* ---- Header ---- */ +header{ + background:linear-gradient(135deg, var(--brand-dark), var(--brand)); + color:#fff; padding:32px 6vw 26px; position:relative; +} +[data-theme="dark"] header{background:linear-gradient(135deg,#3a2f08,var(--brand-dark));} +header .wordmark{ + display:inline-flex; align-items:center; gap:8px; font-family:"Montserrat"; + font-weight:700; font-size:15px; letter-spacing:1px; opacity:.9; margin-bottom:10px; +} +header .wordmark .dot{width:8px; height:8px; border-radius:50%; background:#fff;} +header .eyebrow{font-size:12.5px; letter-spacing:2px; text-transform:uppercase; opacity:.8;} +header h1{margin:8px 0 4px; font-size:26px; font-weight:700; max-width:860px;} +header .meta{margin-top:12px; font-size:13px; opacity:.9; display:flex; flex-wrap:wrap; gap:18px;} +header .meta b{font-weight:600;} +.theme-toggle{ + position:absolute; top:28px; right:6vw; background:rgba(255,255,255,.16); + border:1px solid rgba(255,255,255,.35); color:#fff; border-radius:999px; + padding:7px 14px; font-size:12.5px; font-weight:600; cursor:pointer; + transition:background var(--dur-fast) var(--ease-out); +} +.theme-toggle:hover{background:rgba(255,255,255,.28);} + +/* ---- Sticky jump-nav ---- */ +nav.toc{ + background:var(--surface); border-bottom:1px solid var(--border); + padding:10px 6vw; display:flex; flex-wrap:wrap; gap:6px 16px; + position:sticky; top:0; z-index:50; font-size:12.5px; +} +nav.toc a{color:var(--brand); text-decoration:none; white-space:nowrap; font-weight:600;} +nav.toc a:hover{text-decoration:underline;} + +/* ---- Layout & section rhythm ---- */ +main{padding:26px 6vw 60px; max-width:1180px; margin:0 auto;} +section{margin-bottom:42px;} +section > .sechead{ + display:flex; align-items:baseline; gap:10px; margin-bottom:14px; + border-bottom:3px solid var(--brand); padding-bottom:8px; +} +.secnum{ + background:var(--brand); color:var(--brand-fg); font-weight:700; font-size:14px; + width:28px; height:28px; border-radius:var(--radius-sm); display:flex; + align-items:center; justify-content:center; flex-shrink:0; +} +.sechead h2{margin:0; font-size:19px; color:var(--text);} +.sechead .sub{font-size:12px; font-weight:400; color:var(--muted); margin-left:4px;} +.sec-note{font-size:13px; color:var(--muted); margin:8px 0 14px; max-width:75ch;} + +/* ---- Cards (c2/c3/c4/c5 densities) ---- */ +.cards{display:grid; gap:14px;} +.cards.c2{grid-template-columns:repeat(2,1fr);} +.cards.c3{grid-template-columns:repeat(3,1fr);} +.cards.c4{grid-template-columns:repeat(4,1fr);} +.cards.c5{grid-template-columns:repeat(5,1fr);} +@media(max-width:900px){.cards.c3,.cards.c4,.cards.c5{grid-template-columns:1fr 1fr;}} +@media(max-width:600px){.cards.c2,.cards.c3,.cards.c4,.cards.c5{grid-template-columns:1fr;}} +.card{ + background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md); + padding:16px; box-shadow:var(--shadow-sm); + transition:box-shadow var(--dur-base) var(--ease-out), transform var(--dur-base) var(--ease-out); +} +.card:hover{box-shadow:var(--shadow-md); transform:translateY(-1px);} +.card h3{margin:0 0 6px; font-size:14.5px; color:var(--text);} +.card p{margin:6px 0; font-size:13px; color:var(--muted);} +.icon{ + width:36px; height:36px; border-radius:var(--radius-sm); display:flex; + align-items:center; justify-content:center; color:#fff; font-size:17px; + font-weight:700; margin-bottom:8px; +} +.sensorgrid .card{text-align:center;} +.sensorgrid .icon{margin:0 auto 8px;} + +/* ---- Flow (sequential process) ---- */ +.flow{display:flex; align-items:stretch; gap:10px; flex-wrap:wrap;} +.flow .step{flex:1; min-width:160px;} +.flow .arrow{align-self:center; font-size:20px; color:var(--muted); padding:0 2px;} + +/* ---- Layerbox + filepill (tiered component grouping) ---- */ +.layerbox{border-radius:var(--radius-lg); padding:16px 18px; margin-bottom:12px; border:2px solid var(--border);} +.layer-base{background:color-mix(in srgb, var(--info) 8%, var(--surface)); border-color:var(--info);} +.layer-ext{background:color-mix(in srgb, var(--warning) 10%, var(--surface)); border-style:dashed; border-color:var(--warning);} +.layerbox .tag{ + display:inline-block; font-size:10.5px; font-weight:700; letter-spacing:.5px; + padding:2px 9px; border-radius:999px; color:#fff; margin-bottom:8px; +} +.tag-base{background:var(--info);} .tag-ext{background:var(--warning); color:var(--text);} +.filepill{ + display:inline-flex; flex-direction:column; background:var(--surface); border:1px solid var(--border); + border-radius:var(--radius-sm); padding:8px 12px; margin:4px 8px 4px 0; font-size:12.5px; min-width:160px; +} +.filepill b{font-size:13px; color:var(--text);} +.filepill span{color:var(--muted);} + +/* ---- Unitgrid (spec/comparison matrix) ---- */ +table.unitgrid{border-collapse:collapse; width:100%; margin-top:10px; font-size:12.5px;} +table.unitgrid th, table.unitgrid td{border:1px solid var(--border); padding:8px 10px; text-align:center;} +table.unitgrid th{background:var(--text); color:var(--bg); font-weight:600;} +table.unitgrid td.yes{color:var(--success); font-weight:700;} +table.unitgrid td.no{color:var(--muted);} +table.unitgrid td:first-child{text-align:left; font-weight:600;} + +/* ---- Quad (2x2 flagship callouts) ---- */ +.quad{display:grid; grid-template-columns:1fr 1fr; gap:14px;} +@media(max-width:700px){.quad{grid-template-columns:1fr;}} +.quadcard{ + border-radius:var(--radius-md); padding:14px 16px; background:var(--surface); + border:1px solid var(--border); border-left-width:5px; border-left-style:solid; +} +.q-1{border-left-color:var(--info);} +.q-2{border-left-color:var(--warning);} +.q-3{border-left-color:var(--danger);} +.q-4{border-left-color:var(--success);} +.quadcard h4{margin:0 0 6px; font-size:13.5px; color:var(--text);} +.quadcard p{font-size:12.5px; margin:4px 0; color:var(--muted);} + +/* ---- Compare (two-column contrast) ---- */ +.compare{display:grid; grid-template-columns:1fr 1fr; gap:16px;} +@media(max-width:700px){.compare{grid-template-columns:1fr;}} +.compare .col{border-radius:var(--radius-md); padding:14px 16px; border:1px solid var(--border);} +.col-a{background:color-mix(in srgb, var(--info) 8%, var(--surface));} +.col-b{background:color-mix(in srgb, var(--brand) 8%, var(--surface));} +.compare h3{margin-top:0; font-size:14px;} +.compare ul{margin:8px 0 0; padding-left:18px; font-size:12.5px; color:var(--muted);} +.compare li{margin-bottom:8px;} + +/* ---- Specbar (stat cards) ---- */ +.specbar{display:flex; flex-wrap:wrap; gap:14px;} +.spec{flex:1; min-width:160px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md); padding:14px;} +.spec .val{font-size:22px; font-weight:700; color:var(--brand); font-family:"Montserrat";} +.spec .lbl{font-size:11.5px; color:var(--muted); margin-top:2px;} + +/* ---- Actions table + status pills ---- */ +table.actions{border-collapse:collapse; width:100%; font-size:12.5px;} +table.actions th{background:var(--text); color:var(--bg); padding:8px 10px; text-align:left; font-weight:600;} +table.actions td{padding:9px 10px; border-bottom:1px solid var(--border); vertical-align:top; color:var(--text);} +table.actions tr:nth-child(even) td{background:var(--surface-2);} +.status{display:inline-block; font-size:10.5px; font-weight:700; padding:2px 10px; border-radius:999px; white-space:nowrap;} +.status.info{background:var(--info); color:var(--info-fg);} +.status.warn{background:var(--warning); color:var(--warning-fg);} +.status.danger{background:var(--danger); color:var(--danger-fg);} +.status.success{background:var(--success); color:var(--success-fg);} +.status.muted{background:var(--muted); color:var(--surface);} + +/* ---- Note callouts (4 semantic tones) ---- */ +.note{border-radius:var(--radius-sm); padding:12px 16px; font-size:13px; border-left:4px solid; margin-bottom:10px;} +.note.info{background:color-mix(in srgb, var(--info) 10%, var(--surface)); border-color:var(--info);} +.note.warn{background:color-mix(in srgb, var(--warning) 12%, var(--surface)); border-color:var(--warning);} +.note.danger{background:color-mix(in srgb, var(--danger) 10%, var(--surface)); border-color:var(--danger);} +.note.success{background:color-mix(in srgb, var(--success) 10%, var(--surface)); border-color:var(--success);} +.note b{color:var(--text);} + +/* ---- Colvis / conic-gradient ring (space/percentage allocation) ---- */ +.colvis{display:flex; gap:16px; flex-wrap:wrap; align-items:stretch;} +.colvis .colcard{flex:1; min-width:230px; background:var(--surface); border:1px solid var(--border); border-radius:var(--radius-md); padding:16px; text-align:center;} +.colvis .ring{ + width:110px; height:110px; border-radius:50%; margin:0 auto 10px; position:relative; + display:flex; align-items:center; justify-content:center; font-weight:700; color:var(--text); font-size:12.5px; +} +.ring-main{background:conic-gradient(var(--brand) 0 35%, var(--info) 35% 65%, var(--warning) 65% 100%);} +.ring-main::after{content:""; position:absolute; width:68px; height:68px; background:var(--surface); border-radius:50%;} +.colvis .ring span{position:relative; z-index:2;} +.legend{display:flex; flex-wrap:wrap; gap:8px; justify-content:center; font-size:11px; margin-top:6px; color:var(--muted);} +.legend .dot{display:inline-block; width:9px; height:9px; border-radius:50%; margin-right:4px;} + +/* ---- Footer ---- */ +footer{padding:22px 6vw; color:var(--muted); font-size:11.5px; text-align:center; border-top:1px solid var(--border); margin-top:20px;} + +/* ========================================================================== + PRINT — always light, no chrome, avoid awkward breaks. + PDF generation at publish time should render this media state. + ========================================================================== */ +@media print{ + .theme-toggle, nav.toc{display:none !important;} + body{background:#FAF8F4 !important; color:#272326 !important;} + header{background:#79640E !important; -webkit-print-color-adjust:exact; print-color-adjust:exact;} + .card, .quadcard, .layerbox, .filepill, table.unitgrid, table.actions, .note, .colcard, .spec{ + break-inside:avoid; + } + section{break-inside:avoid-page;} + a{color:inherit; text-decoration:none;} +} diff --git a/skills/internal-meeting-brief/references/section-structure.md b/skills/internal-meeting-brief/references/section-structure.md new file mode 100644 index 0000000..f3f8b4c --- /dev/null +++ b/skills/internal-meeting-brief/references/section-structure.md @@ -0,0 +1,63 @@ +# internal-meeting-brief — section structure + +Derived from the first real run (2026-09-21, APTA 2026 Booth 09-16 recap) and made +explicit here so every future brief has the same skeleton instead of reinventing its +structure per meeting. This is the contract — read it before generating a brief. + +## Always present (fixed, in this order) + +1. **Header** — title (meeting subject, not the raw Plaud filename), meeting date + + duration, prepared date, source (transcript / manual notes), mode (Agenda/Recap). +2. **Attendees** — one card per attendee. Internal MPM people resolved by name where + possible. If Plaud's speaker diarization didn't resolve a name, render the literal + transcript label ("Speaker 1," "Speaker 3") — never guess a name. Follow with a + `note.info` flagging any unresolved speakers explicitly, so it's visible, not buried. +3. **Topics Covered** — a `cards` grid, one card per distinct subject actually + discussed. Card count and grid density (c2/c3/c4) follow the number of real topics — + don't pad to hit a round number, don't force unrelated topics into one card to save + space. +4. **Key Decisions** (recap) or **Discussion Plan** (agenda) — decisions actually made + (recap) or points to be raised (agenda). Use `quad` when there are 3-5 distinct, + roughly parallel decisions; use plain prose or a `note` when there's only one or two, + since forcing a single decision into a quad grid wastes space and implies false + parallelism. +5. **Open Items** — an `actions` table with status pills. Every action item needs an + owner field even if the honest value is "Unassigned" — never leave the column blank, + since a blank reads as "forgotten to track" rather than "no owner yet." +6. **Notes & Flags** — one `note` per genuinely separate concern: data-source + limitations encountered (a failed pull, a missing transcript), naming/identity + uncertainty, anything that needed a judgment call worth surfacing rather than + silently resolving. This section exists specifically so the never-fabricate rule has + somewhere to put its flags, visibly, not as a footnote. + +## Present only when content genuinely calls for it (dynamic) + +A dynamic section is content that has a **specific internal structure** the fixed +sections above would flatten into an unreadable wall of text or an over-long table row. +Add one only when the meeting's actual content has this shape — never as decoration, +never because a template "should" have variety. + +| If the content is... | Use... | Real example | +|---|---|---| +| A sequential, ordered process (3+ steps, each depending on the last) | `flow` | Anti-vandalism 3-tier escalation (09-16 meeting) | +| A named component/system with distinct sub-parts worth breaking out | `layerbox` + `filepill` | (not yet exercised on a real internal-meeting-brief; seen in development-brief-flavored source material) | +| A genuine two-sided contrast (us/them, before/after, keep/avoid) | `compare` | (not yet exercised on internal-meeting-brief; used in vendor-partner-style source material) | +| A spec/BOM-style matrix with yes/no or multi-column comparison | `unitgrid` | (not yet exercised) | +| A handful of headline numbers worth calling out at a glance | `specbar` | (not yet exercised on internal-meeting-brief) | + +**Rule of thumb:** if you're reaching for a dynamic section and can't point to the +specific part of the meeting that has this shape, don't add it. The fixed six sections +above should carry ordinary meeting content on their own. Dynamic sections are earned +by unusual content structure, not added for visual variety. + +## What's still unproven + +This contract is based on exactly one real run. It hasn't been tested against: +- Agenda mode (only recap mode has run for real) +- A meeting with genuinely no clear "topics" (a single-subject deep-dive) +- A meeting needing more than one dynamic section +- A recurring topic's second brief (pre-fill/delta-confirm behavior for attendees, + per CW-027 Concept.md, hasn't been exercised — the 09-16 brief was a topic's first + run, full interview by necessity) + +Revise this file after the second real run rather than treating it as settled.