Files
brief/skills/internal-meeting-brief/SKILL.md
T
Bryan Gilliom (via Claude) 2f8ba0b80b Add end-agency enrichment and the channel/pricing confidentiality rule
Bryan, two related requests:

1. When a topic has a real end-client agency, the skill should resolve
   its full identity -- not just whatever name got said in the meeting.
   Added as a new standing step: check the MPM Technical Reference
   System first (agency-roster.md, clients-and-partners.md -- cheap,
   already-vetted), fall back to public web research, resolve BOTH the
   legal entity name and the separate transit brand name distinctly
   (validated pattern, confirmed against MPM's own FTA filings for
   Oshkosh: 'City of Oshkosh, Wisconsin, dba: GO Transit'), re-host the
   logo as a data URI rather than hotlinking it, and capture general
   agency contact info. Gets its own 'End Agency' card, separate from
   individual attendees.

2. Pricing shown in the Oshkosh brief was correct for an internal
   audience, but Bryan flagged that an external-facing version must
   never show the end agency MPM's price to the reseller -- they aren't
   privy to it. Documented as a new Hard Rule, grounded directly in the
   Technical Reference System's own reseller-channel.md (MPM's contract
   of record is with the reseller, not the agency, on channel accounts)
   rather than invented from scratch. Doesn't change internal-meeting-
   brief's current behavior (it's internal by definition) -- recorded
   here as the binding rule for vendor-partner-brief and kickoff-brief's
   external-client variant, neither built yet.
2026-09-22 21:40:21 +00:00

388 lines
25 KiB
Markdown

---
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.
**Meeting record — the source varies. Ask, don't assume Plaud.** Recap mode needs
*some* record of what was discussed; which kind depends on how MPM actually recorded
that particular meeting, which isn't fixed. In rough order of how much structure they
give you, and check whichever plausibly applies rather than defaulting to the first one
tried before:
- **Plaud** — if used, the official `Plaud` connector (`get_current_user`,
`list_files`, `get_file`, `get_transcript`, `get_note`) — **not** the deprecated
`Plaud MCP` connector. Resolve a recording's `file_id` via
`list_files(query=...)` — never assume a Plaud web-app URL's slug is the API
`file_id` directly; the real id carries an `of_` prefix the web URL doesn't show.
`get_transcript` paginates (`next_cursor`) — loop until null. `get_note` returns the
AI summary/action-items tab separately — worth pulling alongside the transcript.
- **Google Meet transcript** — typically lands as a Google Doc in Drive (often in a
"Meet Recordings" folder or attached to the Calendar event) — search Drive/Calendar,
don't assume it doesn't exist just because Plaud has nothing.
- **Teams transcript**, or any other recording tool MPM starts using — same principle:
ask where it lives before concluding no record exists.
- **No transcript at all** — perfectly valid. Fall back to whatever does exist for that
meeting: the person's own notes, a task registry, prior emails/Chat about it. State
plainly in Notes & Flags that no transcript was available and the brief is built from
secondary sources — this is the never-fabricate rule applying to the *source*, not
just the content.
If it's not obvious which source applies, **ask the person** rather than trying each
connector in sequence and treating empty results as "nothing exists here." An empty
result from one source is not evidence the meeting has no record at all.
Other tools this skill uses:
- **Odoo** (MCP) — linked Project/tasks, Sales/Purchase Orders, Knowledge Base,
Helpdesk tickets, and contacts (customer/partner/sales-rep records tied to an SO/PO)
- **Google Workspace** (MCP) — Gmail, Google Chat, Drive, Sheets
- **Google Drive** — the topic's continuity folder (`_topic-state.md` + brief history
+ `Meeting Briefs/` + `Meeting Transcripts/`)
- **Playwright (Python, headless Chromium)** — for PDF generation from the rendered
HTML (step 7). Confirmed available in this environment at `/opt/pw-browsers`; if a
future environment lacks it, that's a real gap to flag, not something to silently
skip — HTML-only output is a regression from what this skill is supposed to do.
- **MPM Technical Reference System** — a Drive-based product/technical knowledge
registry (131 entity files as of 2026-09-22: brand voice, platform/software,
display technologies, products, engineering, concepts, proof/evidence). Read
`_INDEX.md` first — it's the routing table — then only the specific files a claim
actually needs. This is where part numbers, model codes, and product/technical
claims get verified; it is not this skill's content to maintain, only to reference.
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: `<Topic Name> — 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 — ALWAYS, before anything else
Open `_topic-state.md` in the topic folder. **This is not optional and does not need
to be asked about — do it automatically, every run, as the first real action.** If it
doesn't exist, this is the topic's first run: create it immediately with the schema
below, then expect a fuller interview in the following steps since there's no history
to draw on yet.
**Schema — refined 2026-09-22 against a real production run** (Oshkosh GO Transit
kickoff), which improved on the original design in ways worth keeping permanently:
- **Confidence tags** on every factual claim: `verified` (checked against a source
document — an SO, a PO, an Odoo record), `stated` (said by someone in the meeting or
by the person running the brief, not independently confirmed), `open` (unresolved —
including outright conflicts between two sources, e.g. an address that differs
between a PO and its matching SO). Do not present a `stated` fact with the same
confidence as a `verified` one.
- **Folder layout** section at the top of the manifest, documenting what's actually in
the topic folder (including subfolders Brief didn't create, like a pre-existing
`Financial/` folder) — self-documenting, so opening the manifest alone orients
someone to the whole folder.
- **Links** table: linked Odoo Project ID, SO, PO, Chat Space, Plaud recording
pattern, relevant Gmail thread(s), and — critically — the actual **people**
resolved from those records (customer contact, reseller/partner contact, MPM sales
rep), each with role, email, phone, and its confidence tag. See step 4.
- **Decisions ledger** and **Open items ledger** as two separate tables. Open items
get sequential numbers (1, 2, 3...) for things actually assigned/committed in the
meeting, and a separate `P`-prefixed series (P1, P2...) for things *suggested*
during the meeting but not yet formally assigned — don't conflate a live suggestion
with a committed action item.
- **Findings / flags** section for meta-observations worth carrying forward that
don't fit the ledgers — e.g. "this topic's Plaud AI summary is unreliable, build
from the raw transcript" or a specific diarization error spotted at a timestamp.
This is where operational lessons about the data sources themselves get recorded,
not just facts about the topic.
- **Related documents** table for cross-referencing other MPM document types about
the same real-world topic (pre-mortems, BAI build docs, a technical reference
registry, etc. — see CW-027 Concept.md's rewrap-vs-harvest principle; don't merge
their content into this ledger, just reference them).
- **Brief history** log (date/type/mode/file link(s) — both HTML and PDF if a PDF
exists).
Append to this file; don't rewrite history. On every subsequent run, read the whole
thing before doing anything else — it's the difference between starting fresh and
starting from zero.
### 3. Determine mode: Agenda or Recap
Agenda mode (pre-meeting prep) pulls the *previous* meeting's record and any updates
since. Recap mode (post-meeting) pulls the *current* meeting's record. Ask if not
specified by the request. "Record" — see Prerequisites above — is whatever source
actually applies for that meeting, not necessarily Plaud.
### 4. Capture and normalize attendees — and resolve real contact info, always
- **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 transcript available (any source):** 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 — cross-reference against Odoo to resolve real contact info
(email, phone, title, company), not just a confirmed spelling of a name. **This is
a standing step, not something to be asked to do:** if the topic has a linked SO
or PO, pull the Odoo contacts tied to those records first (customer contact,
reseller/partner PM, sales rep) — this is usually faster and more accurate than a
generic contact search, and surfaces exactly who the real counterparts are even
if they weren't in the meeting. If someone's name as heard doesn't match Odoo
cleanly (a misheard surname, a title mismatch), flag it in Findings/flags as
`open` rather than silently picking one.
- **If a speaker's diarization didn't resolve 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," but scope by what the *topic* actually is, not a
fixed list per brief type:
- The meeting record (per mode, above) — the primary source, whichever tool it
actually lives in
- 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 Order / Purchase Order — pull whenever the topic is a real customer or
reseller engagement, not just for vendor-partner-brief/status-update-brief.**
Correction from initial design: an *internal* kickoff meeting about a *real sale*
(an internal-meeting-brief, by audience) still needs the SO/PO — that's where the
scope, the customer, the reseller/partner, and the real contacts actually live. The
dividing line is the topic's nature (commercial engagement vs. purely internal
process work like a booth build), not the brief type's name. Search Odoo by
customer/topic name if not already linked in the manifest.
- **Part numbers / product/technical claims — check them against the MPM Technical
Reference System** (a Drive-based registry; read `_INDEX.md` first, then
`_RULES.md` for the confidence-tag contract, then only the specific entity files
the topic needs — e.g. `30-products/model-code-grammar.md` for verifying a model
number's structure, or the relevant `30-products/*` file for a named display
family). Don't guess at whether a model number or part number is right — verify it
here, or flag it `open` if the registry doesn't resolve it (e.g. a variant with no
assigned code yet). This registry is a genuine dependency, not this skill's own
content to maintain — see Dependencies.
- **End agency / client organization — identify and enrich it, not just the people.**
When a topic has a real end client (a transit agency, most commonly), resolve its
full identity, not just whatever name got said in the meeting:
1. Check the MPM Technical Reference System first — `60-proof/agency-roster.md`
(is this agency already a known MPM deployment? gives HQ city/state) and
`60-proof/clients-and-partners.md`. Cheap, already-vetted, check before the web.
2. If not found or incomplete, search the public web for the agency's official
site. Resolve **both** names, distinctly — most transit agencies have a legal/
governmental name and a separate public transit brand, and both matter for
different reasons (contracts use the legal name; everything rider-facing uses
the brand). The precise, correct pattern — confirmed against MPM's own FTA
filings for Oshkosh — is **"[Legal Entity], dba: [Transit Brand]"** (e.g. "City
of Oshkosh, Wisconsin, dba: GO Transit"). Don't collapse these into one name or
guess which is which.
3. Pull the agency's logo and re-host it as a data URI embedded in the brief — do
not hotlink to an external image URL. This is the same "own content at
creation" principle already applied to fonts/tokens elsewhere in Brief: the
brief must survive as a standalone file even if the agency's website changes.
4. Capture the agency's general contact info (main line, address) alongside — not
a replacement for a named individual contact (see attendee resolution above),
supporting information for anyone reading the brief who needs to look the
agency up independently.
Present this as its own clearly-labeled card/section (see
`references/section-structure.md`), separate from the internal attendee list —
this is organizational identity, not a meeting participant.
Helpdesk ticket review is still a deliberate, manual exception (see below) — not
pulled automatically regardless of topic type.
### 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 — HTML and PDF, always both, not HTML alone
**PDF is a required parallel output, not an optional extra someone has to remember to
export.** Not everyone can open an HTML file comfortably (attachments, security
posture, unfamiliarity) — the PDF is what makes a brief actually shareable outside a
browser.
**HTML first:**
Single self-contained 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). Small brief-specific CSS additions beyond the shared stylesheet
(e.g. a status-source badge, a role subtitle under an attendee's name) are fine —
append them, don't fork the canonical rules to get the same effect.
**Then PDF, from that same HTML file, via a real browser — not a simplified
HTML-to-PDF library.** This stylesheet uses modern CSS (`color-mix()`, custom
properties, conic-gradient) that non-browser renderers often get wrong. Use headless
Chromium via Playwright, which is confirmed available in this environment
(`/opt/pw-browsers`):
```python
from playwright.sync_api import sync_playwright
import os
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto('file://' + os.path.abspath('<brief>.html'))
page.emulate_media(media='print') # forces the @media print rules
page.pdf(
path='<brief>.pdf',
format='Letter',
print_background=True, # keep header gradient, card fills, etc.
margin={'top':'0.4in','bottom':'0.4in','left':'0.3in','right':'0.3in'}
)
browser.close()
```
`emulate_media(media='print')` is what makes this reliable — it forces the exact CSS
this skill already ships for print (light theme, hidden nav/toggle, row-level
break-avoid), so the PDF matches what someone would get from Ctrl+P in a real browser,
without relying on them to do that themselves. Verified 2026-09-22: correct Letter
pagination, no blank-page artifacts, gradient/color-mix rendering intact.
**Footer confidentiality note — standard for this brief type.** internal-meeting-brief
is, by definition, internal content. End the footer with an explicit statement of that
(e.g. "Internal. Do not forward to [named external party]." when the topic has one) —
validated in the Oshkosh brief, where this genuinely matters: the brief discusses a
reseller/customer deal in more candid terms than anyone would want forwarded to that
customer.
### 8. Archive — the brief (HTML + PDF), the transcript, and the manifest update
- Save both the HTML and the PDF into the topic folder's `Meeting Briefs/` subfolder,
same base filename (`YYYY-MM-DD <Meeting> - <Mode> Brief.html` /`.pdf`). Both, every
time — not PDF-on-request.
- **Save a plain-text copy of the meeting record into a `Meeting Transcripts/`
subfolder** (`YYYY-MM-DD <source name> - Transcript.txt`) — a standing step, not
something to be asked for. This matters beyond convenience: it makes the topic
resilient to the source connector being unavailable later (Plaud specifically has
had real, live connector problems this project — see Resolved limitation below), and
it's the raw material a future brief needs if it has to re-derive something the
original brief didn't capture.
- Update `_topic-state.md`: append to the brief-history log (both file links), update
the decisions and open-items ledgers (carry forward anything still open, close
anything resolved, add new items with the correct sequential/P-prefixed numbering —
see step 2), update the attendee list and any newly-resolved contact info, update
Findings/flags with anything learned this run, 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.
- **Channel/pricing confidentiality by audience.** internal-meeting-brief is internal
by definition, so this doesn't block anything it currently does — but it's the rule
that must govern any future external-facing brief type (vendor-partner-brief,
kickoff-brief's external-client variant), so it's recorded here where the pattern
first came up. Grounded in MPM's own Technical Reference System
(`60-proof/reseller-channel.md`): on a reseller-sold account, **MPM's contract of
record is with the reseller, not the end agency** — the agency is not privy to
what MPM charged the reseller, only to whatever the reseller separately agreed
with them. A brief ever shown to the end agency must exclude MPM's own SO/PO
pricing entirely on a channel account, not just redact the total — line-item
pricing implies the same thing. This is not "hide pricing from external
audiences" generically: a *direct* account (no reseller) showing an agency its own
figures is normal. The dividing line is whether there's a reseller between MPM and
the reader, not whether the reader is external to MPM.
- **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.
## First real invocation — findings (2026-09-22)
The first time this skill ran from an actual installed invocation (not Claude manually
walking through this file) — a recap brief for an Oshkosh GO Transit internal kickoff.
Real, valuable findings, each fixed in this revision:
1. **Print CSS bug — fixed.** `section{break-inside:avoid-page;}` and whole-table
`break-inside:avoid` in the shared stylesheet's `@media print` block caused a
14-page, mostly-blank PDF: any section taller than the remaining space on a page
got pushed whole to the next page, leaving the gap behind blank. Fixed in
`assets/brief-components.css`: sections can split across pages now; only the small
atomic elements (cards, individual table rows) avoid splitting, with table headers
repeating on each new page. A correctly-generated PDF from the same content came out
6 clean pages.
2. **SO/PO lookup was wrongly scoped out by default — fixed.** Original design said
Sales/Purchase Orders "aren't typically relevant" to this brief type. Wrong: an
internal kickoff about a real sale needs them just as much as an external brief
would. Corrected in step 5 — the deciding factor is whether the topic is a
commercial engagement, not which brief type is generating the document.
3. **Contact-info lookup had to be manually requested — now a standing step.**
Resolving attendee names wasn't enough; real contact info (email, phone, title) for
external counterparts needed to be pulled from Odoo, and doing that well meant
starting from the linked SO/PO's own contacts rather than a generic search. Now
explicit in step 4, not something that needs to be asked for.
4. **Part number / product verification wasn't referenced at all — now is.** The
actual run needed to check a model variant and part number against MPM's product
catalog. The right source turned out to be the MPM Technical Reference System (see
Prerequisites) — added as a standing reference, not previously known to this skill.
5. **The manifest schema got meaningfully better in real use — pulled back into the
spec.** Confidence tags (verified/stated/open), a folder-layout header, split
numbered-vs-proposed open items, and a Findings/flags section for operational
observations (e.g. "this topic's Plaud AI summary is unreliable, build from the raw
transcript") all emerged from the real run and are now part of the documented
schema in step 2, not a one-off improvisation.
6. **Meeting transcript wasn't being archived — now a standing step.** The raw
transcript needed to be saved alongside the brief so future runs don't depend on
the source connector still being reachable. Now explicit in step 8.
7. **PDF was manual, bolt-on, and done by hand — now a required parallel output.**
The skill only produced HTML; getting a PDF meant the person exporting it
themselves (and hitting the print-CSS bug in the process — see above). Fixed:
step 7 now generates the PDF automatically via headless Chromium (Playwright),
using the exact same print CSS this skill already ships, immediately after the
HTML — not something anyone has to remember to do.
None of these were failures of judgment in the moment — they're gaps between what
this file said and what turned out to actually be needed, now closed.
## Resolved limitation (was open 2026-09-21, fixed 2026-09-22)
Earlier attempts to pull this skill's first real test recording failed for two
compounding reasons, now both understood:
1. The deprecated `Plaud MCP` connector's `list`/`search` tools returned empty results
or timed out regardless of parameters — root cause not fully diagnosed, but moot:
don't use that connector at all (see Prerequisites above).
2. Direct lookup via the *official* `Plaud` connector's `get_file`/`get_transcript`
still 404'd, because the id taken from the Plaud web app's URL
(`b0df60b679f31383f770d91db6b5bf46`) was missing the `of_` prefix the API's real
`file_id` requires (`of_b0df60b679f31383f770d91db6b5bf46`). Resolving the id via
`list_files(query=...)` instead of reading it off a URL fixed this immediately.
Verified 2026-09-22: a live pull via the official connector for this same recording
returned content matching the manually-uploaded transcript used to build the first
real brief, confirming both that the fix works and that the original brief's content
was accurate. Recap mode's live data path is now confirmed working end-to-end.
## 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.