---
name: event-sponsor-delivery-log
description: "Build a per sponsor delivery log from conference stage recordings with Vivu: when the host thanked each sponsor and when its name was on the big screen. Use after an event, before sponsor reports."
---Event sponsor delivery log from stage recordings
This skill takes the main stage recordings from a conference, the agenda and the sponsor package sheet, and returns one delivery log per sponsor for the sponsorship team to send: every time the host or a speaker thanked or introduced that sponsor on stage, and every time its name was written on the big screen behind the stage, with the recording, the time as MM:SS in the original session file, how many seconds it lasted, the line copied from captions, the screen text copied from a full frame, the frame, and an empty "sponsor confirmed" column. Claude cuts only the openings, closings and break loops the agenda points to, prices them against the user's Vivu plan, uploads them to a private Vivu project, runs two precise searches per sponsor, checks every window against the captions or the frames, sweeps the captions for every sponsor name, and writes the logs.
The value is in what only the recording shows. The run of show says "host thanks Gold sponsor" but not whether the host said it, said it for the right company, or skipped it when the session ran late; and break loop slides, sponsor walls and slide footers are in no transcript at all. Sponsors ask for exactly this proof, and a missed thank you is cheaper to find before they ask. The hard parts are the one sentence thank you that is easy to miss, a speaker who names a sponsor's product without thanking it, and small sponsor text on a far away screen. So every window Vivu returns stays a candidate until the captions show the thank you or a full frame shows the name, and the words in the log come from captions and frames, never from Vivu's reason text.
When to use
Use when an event or sponsorship lead asks "make the delivery log for each sponsor from the stage recordings", "did the host actually thank every Gold sponsor on stage?", "when was the Halcyra coffee break slide up, and for how long?", or "I need proof of every sponsor mention before we send the post event reports".
Not for these:
- One session and one question ("did we thank Quarrystone in the opening?"): open the recording or search Vivu directly.
- Recap emails to attendees (the personalized-event-recap-emails skill, https://vivu.ai/skills/personalized-event-recap-emails) or a recap video cut (the event-recap-selects-sheet skill, https://vivu.ai/skills/event-recap-selects-sheet).
- A creator's own sponsored episodes (the sponsor-read-proof-sheet skill, https://vivu.ai/skills/sponsor-read-proof-sheet).
- Valuing exposure, counting impressions, or recognizing sponsor logos. The log lists where a sponsor was thanked or named in writing; logo only slides are flagged for a person to check.
- Whole days of stage footage. Cut the openings, closings and break loops the agenda and package sheet point to; full days cost more index minutes than any plan holds.
Working principles
- Report measured numbers, not estimates. When a number is an estimate, say so.
- Nothing is verified until it has been checked against the recording. A spoken window is a candidate until the captions show the sponsor being thanked or introduced; a screen window is a candidate until a full frame shows the sponsor's name as text. Vivu's reason text paraphrases, so it never fills a cell.
- Stop and tell the user when a required capability or tool is missing. Do not guess around it.
- Ask the user before anything that is expensive to redo (the indexed minutes, before upload) and before anything that acts on their behalf (sending or drafting a message to a sponsor, writing to a shared folder). The skill writes local files only.
- Every sponsor gets the caption sweep, so a one sentence thank you the search did not return still gets a row. Screen items have no sweep that covers every second, so tell the user that the screen rows rest on the screen search plus the frames Claude checked.
What you need before starting
Check each item at the start of the run and tell the user plainly what is missing before doing anything else.
| Requirement | Why | How to check |
|---|---|---|
| Vivu connector with write access | create a private project, open its upload page, search | vivu_get_account shows can_create_projects: true (tool names may carry a server prefix). A write call failing with "has not granted vivu.write" means the user reconnects Vivu and allows write access |
| A shell with ffmpeg and ffprobe | cut segments, measure them, make contact sheets, extract frames | ffmpeg -version, ffprobe -version |
| The stage recordings as local files in one folder | Vivu indexes uploads, and frames are read from the user's copy | ls RECORDING_DIR shows the files |
| The agenda with session start times, and the sponsor package sheet (which sponsor bought which thank you or screen slot) | the cut list comes from the agenda, and each log row is matched to a package item | the user gives them as text, a spreadsheet or a PDF |
| Captions for each cut segment: the AV team's caption export, or a local speech to text tool such as whisper.cpp | quotes are copied from captions, and the caption sweep finds thank yous the search misses | an .srt or .vtt per segment, or whisper-cli --help |
| An upload path | move the segments into Vivu | vivu_open_upload_page plus the user's own browser, or a browser tool that can attach local files |
| The recording release | speakers and attendees on camera; frames go to sponsors | the user confirms the speaker agreements and recording notice allow sharing stills with sponsors |
This skill needs Claude Code on the user's computer (the terminal or the Code tab of Claude Desktop), because it reads local files and runs ffmpeg. It downloads nothing from YouTube or other sites, so no residential IP is needed. Nothing recurs, so no scheduler is involved; run it once after the event. The only connector it needs is Vivu.
Inputs to collect
Ask for anything missing, most important first.
- RECORDING_DIR: the folder with the stage recordings. Required.
- The sponsor package sheet: sponsor names as the host would say them, and each sponsor's stage items (verbal thank you, screen slide, break loop, footer). Required.
- The agenda with each session's start time in its recording. Required for the cut list.
- Which parts to cut. Default: the first 10 and last 10 minutes of each main stage session and every break loop, confirmed with the user in Step 2.
- WORK_NAME: a short name for the working folder and the Vivu project. Default: the event and year, for example fieldline-2026.
- Where the logs go. Default: local CSV files only; the sponsorship team sends them.
Files and state
Keep everything in one working folder:
sponsors-WORK_NAME/
config.json sponsors and package items, Vivu project id, query wording
segments.csv segment file, source recording, offset_s in the source, duration_s, video_id, captions file
segments/ the cut segments that get uploaded
captions/ one .srt or .vtt per segment
results/ one JSON per search, without the result page link
sheets/ half second contact sheets
frames/ full frames the screen text was read from
candidates.csv every window Vivu returned, with verdict and reason
delivery_SPONSOR.csv one log per sponsor
summary.csv one row per sponsor and package item: delivered, not found, or logo only
state.json steps done, segments uploaded, searches run with job ids, windows checked
Run every command from the folder that contains sponsors-WORK_NAME/. A rerun reads state.json first: an uploaded segment is not uploaded again, a search with a saved result is not run again, and a window with a verdict in candidates.csv is not checked again.
Step 1: Check the Vivu connector and the setup
Goal: confirm every requirement before spending anything.
- Call vivu_get_account. If the tool does not exist, tell the user to add the Vivu connector in Claude (
https://mcp.vivu.ai/mcp) and stop. If the account does not showcan_create_projects: true, or a later write call fails with "has not granted vivu.write", ask the user to reconnect Vivu and allow write access, then stop until they have. - Run
ffmpeg -versionandffprobe -version, and check that captions exist or that the speech to text tool runs. - Confirm the Compliance items with the user: these are recordings the organizer commissioned, the speaker agreements and recording notice allow sharing stills and quotes with sponsors, and no session is aimed at children.
Done when vivu_get_account shows can_create_projects: true, both ffmpeg commands print a version, captions or a speech to text tool are available, and the user has confirmed the recording release.
Step 2: Cut the segments and price the job
Goal: only the parts of the recordings where sponsor items happen, measured and priced, with the user's approval before upload.
- From the agenda and package sheet, list the cuts: for each session, the opening and closing minutes, and every break loop. Show the list and let the user correct it.
- Cut each segment, re-encoding so the cut lands exactly on the requested second:
ffmpeg -v error -ss START -to END -i RECORDING_DIR/SESSION.mp4 -c:v libx264 -c:a aac sponsors-WORK_NAME/segments/SEGNAME.mp4
START and END are seconds in the source recording, and SESSION is the source recording's file name without .mp4 (use the real extension if the recordings are .mov). SEGNAME uses only letters, digits, hyphens and underscores, so Vivu keeps the name as it is (Vivu rewrites spaces and punctuation). Write offset_s = START into segments.csv; every time in the logs is the segment time plus offset_s, so it points into the original recording. 3. Measure each segment and write duration_s into segments.csv:
ffprobe -v error -show_entries format=duration -of csv=p=0 sponsors-WORK_NAME/segments/SEGNAME.mp4
- Call vivu_get_usage and show one table:
| This event | Plan allowance | Remaining this month | |
|---|---|---|---|
| Index minutes | sum of duration_s / 60 | from vivu_get_usage | from vivu_get_usage |
| Search credits | two precise searches per sponsor, 10 credits each sponsor, plus 5 for each rewording (estimate) | from vivu_get_usage | from vivu_get_usage |
Plan facts: Free is $0 a month with 20 index minutes a month and 50 search credits a month; Premium is $30 a month with 180 index minutes and 500 search credits. A precise search uses 5 credits in total. For example, eight segments of 10 minutes are 80 index minutes, and four sponsors are 40 credits (estimate): more than Free holds, inside Premium.
- If the job does not fit, offer levers in this order: shorten each opening and closing cut, drop sessions where the package sheet promises no stage item, split the event across two months, and only then move to a larger plan. Never drop a sponsor's promised item without naming it.
In our test run the 3 segments measured 5.52 minutes. They were made already cut, so building the cut list from a real agenda was not exercised in our test run; the cut command itself was tried on a single segment. The account used in our test run returns no allowance figures, so the plan table and the user's approval were not exercised in our test run.
Done when every segment is in segments/ with offset_s and duration_s in segments.csv and the user has approved the minutes and credits.
Step 3: Upload and index
Goal: every segment indexed in a private Vivu project.
- Call vivu_list_projects and reuse a project named "Sponsor delivery WORK_NAME" if one exists. Otherwise call vivu_create_project with that name and visibility "private". The default visibility is organization, which shows the project to everyone in the user's Vivu organization.
- Call vivu_open_upload_page with the project ID immediately before uploading. The link expires in 180 seconds and works once, so never post or store it. Give it to the user to open in their own browser and select every file in segments/, or open it in a browser tool that can attach local files. Claude in Chrome accepts at most 10 MB per upload call, and a 10 minute 1080p segment is usually larger, so most users will open the link in their own browser or add the files in the Vivu web app. Never split or recompress a segment to fit.
- Poll vivu_list_videos about every 30 seconds until every segment shows ready. Match each listed file_name to segments.csv and record the video_id; when a name does not match, match by duration_ms against duration_s.
In our test run all 3 segments were ready 5.6 minutes after the upload started, most of it spent in a queue behind other videos. The files went through the upload page with an automated browser, so opening the link in the user's own browser was not exercised in our test run.
Done when every row of segments.csv has a video_id and every segment shows ready.
Step 4: Search
Goal: saved candidate windows for each sponsor's spoken thank yous and screen appearances.
Two precise searches per sponsor. fast is not used: it returns whole files with an empty reason, and the file list is already known. The chain: the spoken search finds thank yous and introductions, Step 5 sets their start and end from the captions and adds the ones the search missed, the screen search flips from what was said to what was shown, and Step 6 reads the name from frames and times how long it stayed up.
| Field | Query | Mode | maximum_results |
|---|---|---|---|
| verbal_SPONSOR | the host or a speaker on stage thanks SPONSOR as a sponsor of the event or introduces what SPONSOR does; a speaker who only mentions using SPONSOR's product, without thanking or introducing them as a sponsor, does not count | precise | 10 |
| screen_SPONSOR | the name SPONSOR written on the big projection screen behind the stage, for example on a sponsor thank you slide, a sponsor wall or a slide footer | precise | 10 |
SPONSOR is the sponsor's name as it appears in the package sheet. maximum_results 10 covers a sponsor with several items across six to eight segments plus extra windows; it is also the recall ceiling, so raise it for a sponsor with many items (the limit is 100).
Run vivu_search_videos (project_id, query, mode "precise", maximum_results) for each. It returns a job ID; call vivu_get_search_results until complete is true. Each status call can wait up to 45 seconds, so a pending search is not a stalled one. Save each result to results/FIELD.json without the result page link. Show the result page link only in the live reply: it expires after four hours, so it never goes into a log. Every search used the wording above unchanged.
Done when every sponsor has two saved result files and their job ids are in state.json.
Step 5: Check the spoken windows
Goal: each spoken window kept or rejected, with start, end and quote from the captions, and every thank you the search missed added.
- Read the caption lines between start_ms and end_ms (plus offset_s when comparing with the source). Kept: the host or a speaker thanks the sponsor or introduces what it does as a sponsor. Rejected: a speaker who names the sponsor's product for another reason, thanks to volunteers, crew or the speaker's own team, or another sponsor's thank you. Count rejected windows as false positives.
- Set start and end from the first and last caption line of the thank you, not from the window. Windows run wider than the sentence.
- Copy the line that names the sponsor into spoken_quote, word for word from the captions.
- Sweep every caption file for every sponsor name, so a one sentence thank you the search did not return still gets a row:
grep -n -i -E "SPONSOR_A|SPONSOR_B|SPONSOR_C|sponsor|thank" sponsors-WORK_NAME/captions/SEGNAME.srt
SPONSOR_A and the rest are the sponsor names (one short word from each name also helps, since speech to text can misspell company names). Read every matching line: a line that names a sponsor without thanking it stays out of the log. Mark rows found here as found_by "caption sweep".
- For a second signal, vivu_get_video_summary with include_segments, start_ms and end_ms around the window gives section summaries. Their boundaries are rough and they can misspell company names, so never take start, end or a quote from them.
Worked example from our test run
The test corpus was a synthetic conference stage we built: 3 cut segments (5.52 minutes in total, much shorter than real session cuts) with slides on a big screen behind a podium, a computer voice for the host and speakers, three fictional sponsors, and a fourth sponsor name that never appears. Each sponsor had a formal introduction and a one sentence thank you, and its name was written on sponsor slides, a sponsor wall or, for one sponsor, a small footer under a speaker's slide. A name was never spoken while it was on screen and never shown while it was spoken, so each search could only succeed through its own channel. Before searching we wrote down every item with its start and end.
The spoken searches (one per sponsor) returned 6 windows: 6 real, 0 false, and 0 missed out of 6 thank yous, including every one sentence thank you. A speaker who said she had tried one sponsor's dashboards, without thanking it, was not returned, and neither were the thanks to volunteers or to a speaker's own team. The screen searches returned 7 windows: 7 real, 0 false, and 0 missed out of 7 sponsor items on screen, including the small footer. A slide with the look-alike word "quarry", the agenda and next year's sponsorship slide were not returned. A logo only slide for one sponsor was not returned either: a text search cannot find a name that is not written, so logo slots in the package sheet need a person to check them. Both searches for the sponsor that never appears returned 0 results. The caption sweep found the same thank yous plus the same name mention, which reading the line rejected. This was clean computer graphics with no camera noise, projector glare or audience sound, on a few short segments, so busy real stages, far camera angles and recall across a full event are untested.
Done when every spoken window has a verdict in candidates.csv, every kept thank you has start, end and a quote from the captions, and every caption file has been swept for every sponsor name.
Step 6: Read the screen text from frames
Goal: each screen window kept or rejected, with the sponsor name copied from a full frame and the seconds it stayed up.
- For each screen window, make a contact sheet with one tile every half second:
ffmpeg -v error -y -ss START -t 32 -i sponsors-WORK_NAME/segments/SEGNAME.mp4 -vf "fps=2,scale=256:-1,tile=8x8" -frames:v 1 sponsors-WORK_NAME/sheets/SEGNAME_START_sheet.png
START is the window start in seconds (start_ms / 1000). Tile k is at START plus k/2 seconds, counting from 0 at the top left; one sheet covers 32 seconds, so a longer window needs a second sheet from START plus 32. 2. Find the first and last tile where the slide with the name is up; those give screen_start and screen_end. 3. Extract a full frame from the middle of that stretch and copy the text exactly as written:
ffmpeg -v error -y -ss SECONDS -i sponsors-WORK_NAME/segments/SEGNAME.mp4 -frames:v 1 -q:v 3 sponsors-WORK_NAME/frames/SEGNAME_SECONDS.png
SECONDS is the segment time in seconds at the middle of the stretch found on the contact sheet (screen_start plus screen_end, divided by 2). 4. Label the window. Kept: the sponsor's name readable as text on the screen. Rejected: another sponsor's slide only, an agenda, a speaker's own company, a look-alike word, or no text. A slide that shows only a graphic logo and no name goes in the log as "logo only, check by hand", never as delivered; the skill does not recognize logos. Text too small to read in the frame is marked UNCERTAIN; never complete it from the reason text. 5. Also extract one full frame from the middle of each kept spoken window. When a slide there names the sponsor, add it as a screen row with found_by "frame check".
In our test run every screen window started a little before the slide appeared and ended a little into the next slide, and the half second sheets placed each slide change to the half second. The small footer was readable in a full frame. The frame check of spoken windows added no row, because no name was on screen during any thank you in the test corpus.
Done when every screen window has a verdict in candidates.csv and each kept item has a frame and its text.
Step 7: Write the delivery logs and hand them over
Goal: one log per sponsor that the sponsorship team has checked and can send.
- Show the user one sample row and the field mapping, and wait for a yes before writing the rest:
sponsor,package_item,source_recording,segment,item,start,end,seconds,spoken_quote,screen_text,frame_path,found_by,sponsor_confirmed
Halcyra Analytics,coffee break slide,day1_break.mp4,day1_break_loop.mp4,screen,00:24,00:38,14,,"Coffee break sponsored by Halcyra Analytics",frames/day1_break_loop_31.png,search,
| Field | Source | If unavailable |
|---|---|---|
| sponsor, package_item | package sheet | package_item "not in package" when the sponsor got an item it did not buy |
| source_recording, segment | segments.csv | none |
| item | verbal or screen | none |
| start, end, seconds | captions (verbal) or the first and last half second tile (screen), plus offset_s | NOT VERIFIED without captions |
| spoken_quote | copied from the captions | NOT VERIFIED without captions |
| screen_text | copied from the full frame | "logo only, check by hand", or UNCERTAIN when illegible |
| frame_path | the frame the text was read from | blank |
| found_by | search, caption sweep or frame check | none |
| sponsor_confirmed | left empty for the sponsor | stays empty |
- Write delivery_SPONSOR.csv for each sponsor and summary.csv with one row per package item: delivered (with the rows that prove it), not found, or logo only. A package item with no row is "not found in the cut segments", which is weaker than "not delivered": say which recordings were not cut. Add one line per search with how many windows Vivu returned, how many were kept and how many were rejected as false positives, and show it to the user with the sample row.
- Times point to the user's own recordings. The Vivu result page link expires, so it never goes into a log.
- The sponsorship team sends the logs. If the user asks Claude to draft an email to a sponsor or put the logs in a shared folder, name the destination, show the full message or file, and wait for explicit approval; email goes to drafts unless the user asks to send.
In our test run each sponsor got a log with every thank you and screen item, plus the summary and a rendered email draft. The user's approval of the sample row and any destination were not exercised in our test run, and nothing was sent.
Done when every sponsor has a delivery_SPONSOR.csv, summary.csv has a row for every package item, the user has approved the sample row, and any destination outside the working folder has the user's explicit approval.
Compliance
- Use only recordings the organizer commissioned or has the rights to. Confirm this in Step 1.
- Speakers and attendees are on camera. Share frames and quotes with sponsors only when the speaker agreements and the event's recording notice allow it; crop or skip frames that show attendees' faces up close. The skill reads speech and screen text only and does not identify anyone by face or voice.
- If a session is aimed at children (a student program, a family day), leave it out unless the organizer holds guardian consent that covers storing it in a private Vivu project.
- The log lists where a sponsor was thanked or named in writing and for how long. It does not recognize logos, value exposure, or judge whether a package was fulfilled; the sponsorship team decides that.
- The segments stay in the user's Vivu project until the user deletes them. Create the project as private. Delete a project or video only when the user asks, and confirm first.
- Sending a log to a sponsor acts as the organizer; the skill leaves sending to the team or asks first (Step 7).
Known failure modes
| Symptom | Cause | Fix |
|---|---|---|
| (observed) a screen window starts on the slide before the sponsor slide and ends on the slide after it | Vivu returns a time range that contains the moment, not exact edges | time the slide from the half second contact sheet (Step 6) |
| (observed) a logo only sponsor slide is not returned by the screen search | the screen search looks for a written name, and the slide has none | mark logo slots from the package sheet as logo only and have a person check that stretch of the recording |
| (observed) the caption sweep matches a speaker who names a sponsor's product without thanking it | the sweep matches the name, not the meaning | read every matching line; a mention without thanks stays out of the log |
| (observed) a section summary says "introducing gold sponsor Quorustone Cloud" | summaries come from speech recognition and can misspell names | never take names or quotes from summaries; copy them from captions and frames |
| (observed) one summary section covers the volunteers, two sponsors and the sponsor wall | summary sections are rough | use summaries only as a second signal, never for start and end |
| (observed) the reason says a name is "displayed as a sponsor logo/box" when the box holds only text | the reason text paraphrases | copy screen text only from a full frame |
| a one sentence thank you is not returned | short mentions were missed by the spoken search on other footage | sweep every caption file for every sponsor name (Step 5) |
| captions misspell a sponsor's name and the sweep misses it | speech to text spells unfamiliar company names its own way | grep a short distinctive part of each name as well, and read nearby lines |
| a small or low contrast name on a far, glaring stage screen is missed or misread | small text on real stage footage is untested; on other footage small labels were missed | read frames at full size and mark UNCERTAIN when not legible |
| upload page asks to sign in or shows an error | the one time upload link expires after 180 seconds | request a new link right before opening it |
| a file is rejected by the browser upload tool | Claude in Chrome accepts at most 10 MB per upload call | the user opens the upload link in their own browser or adds the file in the Vivu web app |
| "has not granted vivu.write" | Vivu connected read only | the user reconnects Vivu with write access |