---
name: trip-rushes-shot-pull-list
description: "Turn your own trip footage and a script outline into a shot pull list with Vivu: which clip covers each script beat, with timecodes and other takes. Use before editing a travel video."
---Shot pull list from your own trip rushes with Vivu
This skill takes a creator's own trip footage (camera, phone and action camera files named only by a camera counter, such as MVI_0421.MP4 or GOPR0063.MP4) and the script or edit outline for the video, and returns a pull list: for every script beat, the clips that cover it, where in each clip the matching picture is, one frame per pick, and the other takes of the same scene. Claude measures the footage, prices it against the user's Vivu plan, indexes it in a private Vivu project, reads Vivu's description of each clip into a clip table, runs one search per script beat, checks every result against frames from the user's own file, and writes pull_list.csv. The creator opens the originals in their own editor and cuts. The skill does not edit, trim or render anything.
The value is in what only the picture shows. Camera files have no names worth reading and B-roll has no dialogue, so no transcript tool can say which clip is the skyline at noon and which is the same skyline at dusk, which beach clip has the storm rolling in, or how many takes of the welcome sign exist. Vivu looks at the whole clip. Every row of the pull list says whether Claude checked it in frames, so nothing unverified reaches the edit as a sure thing.
When to use
Use when a creator says "I have my script, find the shots for each part", "which of my clips show the sunset at the marina", "make me a shot list from my trip footage", or "pull selects for my travel vlog from my own rushes". It fits one trip's worth of short clips (10 seconds to a few minutes each) from cameras, phones and action cameras.
Not for:
- One quick question about one clip. Open it, or search the Vivu project directly.
- Finding shots on stock sites. This skill only searches footage the user shot; for script beats it cannot cover, it says so and the user decides whether to use stock.
- Finding what someone said to the camera. That search was not exercised in our test run (the test footage has no talking to camera clips); see Step 6.
- Identifying people or faces, or cutting the video. The skill finds shots; the editor cuts.
Working principles
- Report measured numbers, not estimates. When a number is an estimate, say so.
- A search result is a candidate until Claude has looked at frames from the user's own file inside the result window. Only checked rows are marked as checked.
- 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 clip list and the cost (before upload), and the script beats with the search wording (before searching).
- Describe shots by subject, place, time of day and weather. Do not search for shot size, camera movement or speed effects (time-lapse, slow motion); searches that ask for movement have produced reasons that invent it, and the summaries get shot size and camera movement wrong.
- The Vivu result page link expires after four hours, so it only appears in the live reply. pull_list.csv refers to clips by the user's own file names and timecodes.
What you need before starting
The skill runs in Claude Code on the computer that holds the footage (a terminal or the Code tab of Claude Desktop), because it reads local files and runs ffmpeg. Nothing is downloaded, so no particular network or residential IP is needed. It runs once per video project; nothing is scheduled and nothing is posted anywhere. Check each item at the start and tell the user plainly what is missing before doing anything else.
| Requirement | Why | How to check |
|---|---|---|
| Vivu connector with write access | create a project, open its upload page, read summaries, search | vivu_get_account shows can_create_projects: true (tool names may carry a server prefix). "has not granted vivu.write" means the connection is read only: reconnect Vivu and allow write access. No Vivu tools at all: add the Vivu connector (https://mcp.vivu.ai/mcp) and stop |
| A shell with ffmpeg and ffprobe | measure the clips, read their dates, extract frames | ffmpeg -version and ffprobe -version |
| Read access to the footage folder | inventory and frame checks | list the folder once |
| The script or outline as text | the beats to search for | ask for the file or pasted text |
| A way to upload local files | move the clips into Vivu | the user's own browser, or a browser tool that can attach local files (Claude in Chrome takes up to 10 MB per upload call) |
| The right to use the footage | the user's own shoot, or footage they may process | ask the user (Compliance) |
Inputs to collect
Ask for anything missing, most important first.
- The script or edit outline (required). One beat per line is best; Claude numbers the beats.
- The footage folder (required).
- Which shooting days or subfolders to include. Default: all of them if the total fits what is left of the plan this month; otherwise the days the script needs (Step 3).
- How many picks per beat. Default: up to 3, the best first.
- The Vivu project name. Default: "Pull list PROJECT_NAME", where PROJECT_NAME is the name of the video, private.
Files and state
Keep the working files next to the footage, in their own folder:
pull-list/
config.json footage folder, project_id, script file, beats and their search wording
clips.csv file, day, duration_s, bytes, uploaded_name, video_id, subject, place, time_of_day, weather, people
summaries/ raw vivu_get_video_summary output, one JSON file per clip
results/ raw result of each beat search without its result page link, one JSON file per beat
frames/ frames Claude checked, named BEAT_FILE_START.png
pull_list.csv one row per pick (Step 7)
uncovered.md beats with no checked pick, and what was tried
state.json uploaded files with video_id, summaries read, searches run with job_id, picks checked
A rerun reads state.json first and skips what is done: clips already in the project, summaries already saved, beats already searched, picks already checked. When the user adds more footage later, only the new clips are uploaded and summarized; beat searches run again because a search covers the whole project, and checked picks in pull_list.csv are kept.
Step 1: Check the Vivu connector and the setup
Goal: every row of What you need is present, or the user knows exactly what is missing.
- Call vivu_get_account. If the Vivu tools are missing, tell the user to add the Vivu connector in Claude (https://mcp.vivu.ai/mcp) and stop. The account must show can_create_projects: true. If a later write call fails with "has not granted vivu.write", ask the user to reconnect Vivu and allow write access, then retry.
- Run ffmpeg -version and ffprobe -version. Without them the footage cannot be measured or checked; stop and say so.
- List the footage folder once, and read the script. If the script has no clear beats, ask the user to mark them (one line per beat) rather than guessing where one ends.
Done when vivu_get_account shows can_create_projects: true, ffmpeg and ffprobe answer, and the script is in hand.
Step 2: Inventory the footage and pick the days
Goal: clips.csv with one row per clip, its shooting day and its measured length.
- List the video files (FOLDER is the footage folder):
find "FOLDER" -type f \( -iname "*.mp4" -o -iname "*.mov" -o -iname "*.m4v" \) -not -path "*/pull-list/*"
- For each file (FILE), measure the length and read the camera's recording time:
ffprobe -v error -show_entries format=duration:format_tags=creation_time -of csv=p=0 "FILE"
The first value is the length in seconds, the second the recording time when the camera wrote one. When there is no creation_time, use the file's modification date and say so in the day column. Record the size in bytes too; Step 4 needs it for the upload path. 3. Group the clips by day and show the user the minutes per day. A whole trip is often more than a month of Vivu indexing, and a script usually needs only some of the days, so ask which days the script uses. Measuring was exercised in our test run; picking days by recording time was not exercised in our test run (the test clips carry no camera dates). 4. Look for two clips with the same name in different folders (cameras restart their counters). Vivu keeps the name, so Step 4 matches such clips by name and length; if two share both, upload them in separate batches.
Done when clips.csv has one row per chosen clip with duration_s and day filled, and the user has confirmed which days go in.
Step 3: Size the job and get approval
Goal: the user sees the index minutes and search credits before anything is uploaded.
- Sum duration_s of the chosen clips to minutes.
- Searches: one precise search per script beat, plus one rewording for a beat whose first results include a wrong clip. A precise search uses 5 credits in total. As an estimate, a script of 10 beats is 50 credits before rewordings, which is the whole Free month; label the credit figure as an estimate.
- Call vivu_get_usage for the plan and what remains. The plans: Free is $0 a month with 20 indexing minutes a month and 50 search credits a month; Premium is $30 a month with 180 indexing minutes a month and 500 search credits a month.
- Show one table:
| This job | Remaining this month | Fits | |
|---|---|---|---|
| Index minutes | measured sum | from vivu_get_usage | yes or no |
| Search credits (estimate) | beats x 5, plus rewordings | from vivu_get_usage | yes or no |
- If it does not fit, offer these levers in order: index only the days the script uses; within those days, leave out clips the user already knows they will not use (duplicates, test shots); split the beats into two sessions; move to a larger plan. Say which clips are left out. Never drop footage the user asked for without naming it.
If vivu_get_usage returns no remaining figures (some admin or team accounts return null), show the needed minutes and credits anyway and ask the user to confirm the allowance. In our test run the account returned null for both, so the table came from durations and search counts only.
Done when the user approves the clip list and the cost table.
Step 4: Upload and index
Goal: every approved clip is ready in one private Vivu project and matched to its row in clips.csv.
- Call vivu_list_projects. Reuse this video's project if one exists. Otherwise call vivu_create_project with the project name from the inputs and visibility "private"; the default is "organization", which every member of the Vivu workspace can see.
- Call vivu_open_upload_page with the project_id right before the upload. The link expires in 180 seconds, so request it only when the user or the browser tool is ready, and never paste it into a file.
- Give the link to the user to open in their own browser and select the clips of this batch (the page takes many files at once), or open it with a browser tool that can attach local files. Claude in Chrome accepts at most 10 MB per upload call; camera files are usually larger, so they go through the user's browser or the Vivu web app. Never split, trim or recompress a clip to fit.
- Poll vivu_list_videos about every 30 seconds until every clip shows status ready. Vivu replaces spaces and brackets in file names with underscores; match each video back to clips.csv by the normalized name and by duration_ms against duration_s, and write video_id into clips.csv and state.json.
The upload through the user's own browser was not exercised in our test run; the test clips reached Vivu through a different upload path. In our test run all 12 clips (6.34 minutes) were ready about 6.5 minutes after the upload began, indexed a few at a time, and each duration_ms matched the ffprobe length to the millisecond.
Done when vivu_list_videos shows every clip of the batch as ready and every row of clips.csv has a video_id.
Step 5: Read the summaries into clips.csv
Goal: one line of description per clip, used to group takes and to catch what the searches miss.
- For each clip, call vivu_get_video_summary with project_id, video_id and include_segments: true. Save the result as summaries/NAME.json and mark the clip in state.json.
- Fill subject, place, time_of_day, weather and people in clips.csv from the summary's own words. Write "not stated" when the summary does not say. People are described only as "passers by", "a person on camera" or "none", never named.
- Do not fill shot size or camera movement from the summary. Use the segment boundaries: a segment titled like an outro, end card or a turn to the sky marks where the usable picture stops.
- Whether reading summaries uses search credits was not measured in our test run. Call vivu_get_usage before and after the first batch of summaries and tell the user what changed.
Worked example from our test run (summaries)
The corpus was 12 public clips from one shooter's trip footage of a beach city (Creative Commons licensed, no dialogue, 6.34 minutes), renamed to camera style names so the names said nothing: a skyline filmed from the water on two occasions and once from a high rise in the evening, three takes of the same welcome sign, a marina at sunset, pelicans, a sailboat under storm clouds, a storm over the sea, handheld waves and an action camera clip along the beach road. Truth was written from per second contact sheets before any Vivu call.
The summaries named the subject correctly for every clip and split off a channel end card and a tilt up to the sky as their own segments. They stated the time of day for only a few clips, said "clear sky" where the sky was hidden behind palms, called a handheld wave clip a static shot and called the high rise view an aerial video. That is why clips.csv is a description to search and group by, and the pull list rests on frames.
Done when summaries/ has a file for every clip and clips.csv has the description columns filled or marked not stated.
Step 6: Turn the script into search wording
Goal: one search per beat, in words that describe what the camera saw.
- Number the beats. For each, write one query that names the subject, the place, the time of day and the weather in plain words: "the downtown skyline across the water at midday, filmed from the shoreline near water level, with flat white noon light on the buildings and a blue sky".
- Name concrete things a frame would show (water level, one boat large in the picture, rain falling far out over the water) rather than a mood ("a darkening sky"). In our test run the looser first wordings of two beats matched an evening clip, and its reason simply repeated the query's words.
- Leave out shot size, camera movement and speed effects. Where the beat needs one ("a slow push in", "a time-lapse"), search for the content and pick the move from frames in Step 7.
- Beats about something the creator said to the camera ("the bit where I say the ferry was late") are a speech search: word them by what was said, not the exact words. This was not exercised in our test run (the test footage has no talking to camera clips), so tell the user those picks are candidates until they listen to them. Mark these rows speech candidate in pull_list.csv (Step 8).
- Show the user the beat list with the wording and wait for approval.
| Field | Query | Mode | maximum_results |
|---|---|---|---|
| beat N picks (one search per beat) | subject + place + time of day + weather, written from the beat | precise | 10 |
| beat N said to camera (only for such beats) | what the creator said, in plain words | precise | 10 (not exercised in our test run) |
All searches are precise: only precise returns a time range and a reason Claude can check; fast returns the whole file with an empty reason. maximum_results 10 leaves room for several takes of one scene; it is also the ceiling on how many picks a beat can get, so raise it for a beat that returns exactly 10.
The chain: the summaries describe every clip; the beat search looks across the whole project and returns clips with a time range; frames from the user's file decide what goes into the pull list.
Done when the user has approved the numbered beats and their wording.
Step 7: Search each beat and check frames
Goal: for every beat, picks that Claude has looked at in the user's own file.
- Run each beat with vivu_search_videos (project_id, query, mode "precise", maximum_results 10). 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 the completed result as results/BEAT.json with its result_page_url field removed; the result page link may go in the live reply only, because it expires after four hours.
- For every result, extract one strip of three frames at the start, middle and end of the window (FILE is the clip, START, MID and END are seconds inside the window, BEAT and NAME name the output):
ffmpeg -v error -ss START -i "FILE" -ss MID -i "FILE" -ss END -i "FILE" -filter_complex "[0:v][1:v][2:v]hstack=inputs=3,scale=1500:-1" -frames:v 1 pull-list/frames/BEAT_NAME_START.png
- Look at the strip. Vivu's search by what a picture shows is rated weak in general (it misses shots and can return look alikes), so the frame check is what makes a pick, not the search. A result counts only when the frames show the beat's subject, place, light and weather. Do not trust the reason text for time of day or weather: it repeats the query's words. Rejected results go into uncovered.md with the reason text and what the frames showed, and are counted as false positives in the report.
- Where the strip's end frame is not usable (an end card, a tilt away, a camera being lowered), find where the picture stops with a half second strip and trim the end time:
ffmpeg -v error -ss TAIL -t 4 -i "FILE" -vf "fps=2,scale=320:-2,tile=4x2" -frames:v 1 pull-list/frames/BEAT_NAME_tail.png
TAIL is four seconds before the window's end. 5. If a beat's results include a wrong clip, reword that beat once (Step 6, point 2) and run it again. If a beat has no checked pick, look in clips.csv for clips whose description fits, check their frames the same way, and list the beat in uncovered.md when nothing fits. An empty search does not prove the footage has no such shot. 6. Report to the user per beat: results returned, picks kept, false positives, and beats left uncovered.
Worked example from our test run (searches)
In our test run, the final wordings for all the beats returned 12 results, 12 real and 0 false, and no truth clip was missed; the welcome sign beat returned all three takes of the sign. Two beats reached that after 1 rewording on the same corpus. The first skyline wording returned 3 results, 2 real and 1 false: the evening high rise clip, with a reason claiming "plain daytime light". The first sailboat wording returned 2 results, 1 real and 1 false: the same evening clip, whose boats are specks far below. Windows covered the whole clip for most results; one ran past the end of the footage into a channel end card, one ended a second into a tilt to the sky, and the rainbow window started before the rainbow appears. The test run used 10 precise searches, an estimate of 50 credits.
This is one small corpus shot by one person in one city, with no drone and no talking to camera clips; a library of a whole trip will have more look alike clips per beat, so expect more rejected results than this.
Done when every beat has a results file, every result has been judged from frames, and the user has seen the per beat counts.
Step 8: Build the pull list
Goal: pull_list.csv the creator can work through in their editor.
- Write one row per kept pick, beats in script order, the best pick first:
segment_no,script_line,source_file,start_mmss,end_mmss,what_is_on_screen,frame_path,other_takes,checked,use
2,"The evening we saw a rainbow over the bay",CLIP_NAME.MP4,00:06,00:19,"city and bay from high up, rainbow over the water, pink clouds",frames/BEAT_CLIP_NAME_3.png,CLIP_NAME.MP4 00:28-00:37,frame,
CLIP_NAME is the user's own file name. start_mmss and end_mmss come from the checked window, trimmed where frames showed the picture changing. what_is_on_screen is written from the frames, not from the reason. other_takes lists the other kept picks of the same beat and, from clips.csv, clips whose description matches the same scene. checked is frame for every row whose picture Claude looked at; a row from clips.csv that was not looked at says summary only; a pick for a said to camera beat says speech candidate, because frames cannot confirm what was said and this search was not exercised in our test run. The user listens to it before using it. use is left empty for the creator. 2. Show the user the first rows and the field mapping, and wait for a yes before writing the rest:
| Field | Source | If unavailable |
|---|---|---|
| source_file, start_mmss, end_mmss | the search window, trimmed by frames | the row is not written |
| what_is_on_screen | the frames | UNCERTAIN |
| other_takes | kept picks of the same beat, clips.csv | empty |
| checked | frame, summary only, or speech candidate | summary only |
- Write uncovered.md: beats without a checked pick, and the rejected results with what the frames showed. Suggest stock or a pickup shot only for beats in this file.
- Tell the user how to open a pick: the clip name and time are enough in any editor; the Vivu result page link from Step 7 works for four hours and is not stored.
In our test run the pull list had a row for every beat and uncovered.md listed only the two rejected results.
Done when pull_list.csv and uncovered.md exist, and the user has seen the counts of picks, rejected results and uncovered beats.
Compliance
- Rights to the footage. Use only footage the user shot or may process. Footage with other people's work (a performance, a licensed track in the background) is fine to search but its use in the video is the creator's call. Ask before Step 4.
- People on camera. Passers by are described, never identified. The skill does no face recognition and does not name anyone. Private videos centered on children are left out unless the user is their parent or guardian and chooses to include them.
- Where the videos go. The clips are stored in the user's Vivu project until the user deletes them. Create the project as private; the default "organization" visibility shows it to every member of the workspace. The skill never calls vivu_delete_project or vivu_delete_video unless the user asks, and confirms first.
- Nothing leaves the computer except the upload. The skill posts nothing and changes no file of the user's; the pull list is a new file.
Known failure modes
| Symptom | Cause | Fix |
|---|---|---|
| (observed) a daytime beat returns an evening clip, with a reason claiming "plain daytime light" | the reason repeats the query's words about light | judge light from frames; reword with concrete features (water level, noon light on the buildings) |
| (observed) a sailboat beat returns a high view where boats are specks, with a reason claiming "moored white sailboats under a dark, stormy gray sky" | the reason turns a far view into the asked for close subject | ask for the subject large in the picture; reject from frames |
| (observed) the summary says "This aerial video captures a sweeping panoramic view" for a clip shot from a high rise | summaries guess how a shot was made | never take camera position or movement from the summary |
| (observed) the summary says "The video features a static shot of gentle ocean waves" for a handheld moving clip | the same | pick moves from frames only |
| (observed) a window runs past the end of the footage into an end card or a tilt to the sky | windows cover whole clips and do not stop where the picture changes | check the tail with a half second strip and trim end_mmss |
| (observed) the summary names a time of day for only a few clips | summaries describe content first | leave time_of_day as not stated; the beat search and frames decide |
| "has not granted vivu.write" | Vivu connected read only | the user reconnects Vivu and allows write access |
| 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 camera file is rejected by the browser upload tool | the file is above the tool's limit (Claude in Chrome takes up to 10 MB per call) | the user opens the upload link in their own browser or adds the file in the Vivu web app; never split or recompress it |
| two rows point at the same Vivu video | cameras restart their counters, so two days share a file name | match on name and length; upload same name clips in separate batches |
| a beat returns exactly maximum_results picks | the search reached its ceiling | raise maximum_results for that beat |
| a beat returns nothing although the user remembers the shot | an empty result does not prove the footage has no such shot | look in clips.csv for matching descriptions and check their frames |
| the allowance runs out partway | more days were indexed than the month allows | stop, keep state.json, and continue with the remaining beats next month or on a larger plan |