---
name: stock-clip-catalog
description: "Turn a folder of stock, drone or render clips with number-only file names into a searchable catalog CSV and a rename list with Vivu. Use when an editor cannot find B-roll by file name."
---Stock clip catalog with Vivu
This skill turns a folder of short clips whose names say nothing (stock downloads like 4998-720.mp4, drone files like DJI_0042.MP4, render outputs like 0001-0240.mp4) into a catalog an editor can search and sort. Claude measures the folder, prices it against the user's Vivu plan, indexes the clips in a private Vivu project, reads Vivu's description of each clip and turns it into fixed columns (subject, setting, time of day, weather, readable text), cross-checks the two tags editors search for most, aerial and time-lapse, with two Vivu searches, looks at frames of every clip where the sources disagree plus a sample of the rest (which is also where shot size and camera move come from), and writes catalog.csv and rename_plan.csv. The rename plan is a list of old name to new name; the editor reviews it and applies it with a short script. The skill itself never renames or moves a file.
The value is in what only the moving picture shows. These clips have no dialogue and no transcript, and a stock site's title, when it can still be found, is often wrong. Whether a clip is a drone shot or a drone filmed from the ground, a time-lapse or slow motion, a push in or a locked off frame, cannot be read from a file name and often not from one thumbnail. Vivu looks at the whole clip. Every row of the catalog says where its tags came from (two sources that agree, frames Claude looked at in the user's own file, or the summary alone), and the Vivu project stays searchable afterwards.
When to use
Use when someone says "I have 300 clips named with numbers, tell me what's in them", "catalog my stock footage folder", "tag my drone clips by shot type", "give my B-roll readable names", or "make my footage library searchable". It fits short clips without dialogue: stock and archive downloads, drone footage, timelapses, 3D renders, 5 to 30 seconds each.
Not for:
- One or two clips. Open them and look.
- Interviews, vlogs, webinars and anything where the speech carries the meaning. A transcript tool tags those better.
- Finding a particular person, face or brand logo. The skill does not identify people or logos.
- Renaming files automatically across a whole drive. The skill writes a plan; the user applies it.
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 source video. A column filled from the summary alone stays marked summary only until someone has looked at frames.
- 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 or that acts on their behalf: the clip list and the cost (before upload), the column layout and naming pattern (before the full catalog), and the rename (the user runs it).
- The user's files are never renamed, moved or re-encoded by Claude. Stock licenses and editing projects refer to the original names; the rename plan keeps each original number in the new name so a license or an edit can still be traced.
- The Vivu result page link expires after four hours, so it only appears in the live reply. catalog.csv refers to clips by file name.
What you need before starting
The skill runs in Claude Code on the computer or NAS mount that holds the clips (a terminal or the Code tab of Claude Desktop), because it reads local files and runs ffmpeg. No download is involved, so no particular network or residential IP is needed. It runs once per folder or batch; nothing is scheduled. 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 durations, extract frames to check tags | ffmpeg -version and ffprobe -version |
| python3 | the rename script in Step 8 (the user runs it) | python3 --version |
| Read access to the clip folder | inventory and frame checks | list the folder once |
| 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 clips | stock licenses and client footage | ask the user (Compliance) |
Inputs to collect
Ask for anything missing, most important first.
- The folder that holds the clips (required).
- Which clips: file types and subfolders. Default: every .mp4, .mov and .m4v file in the folder and its subfolders.
- The naming pattern for new names. Default: TAGS_subject-words_SHOT_ORIGINAL.ext, for example aerial_lake-islands-sunset_wide_4998-720.mp4. TAGS are the checked tags (aerial, timelapse, render; left out when there are none), SHOT is the shot size from frames (left out when not stated), and ORIGINAL is the old name without its extension; keeping it lets a license or an edit find the clip again.
- Batch size. Default: the whole folder if it fits what is left of the plan this month; otherwise batches that do (Step 3).
- The Vivu project name. Default: "Clip catalog FOLDER_NAME", where FOLDER_NAME is the name of the clip folder, private.
Files and state
Keep the working files next to the clips, in their own folder:
clip-catalog/
config.json clip folder, project_id, naming pattern, column vocabulary
clips.csv original_path, original_name, source_folder, duration_s, bytes, uploaded_name, video_id
summaries/ the raw vivu_get_video_summary output, one JSON file per clip
results/ the raw result of each search without its result page link, one JSON file per query
frames/ three frame strips for checked clips
catalog.csv one row per clip (Step 7)
rename_plan.csv original_path,new_path (Step 8)
apply_renames.py the rename script from Step 8
state.json uploaded names with video_id, summaries read, searches run with job_id, clips checked
A rerun reads state.json first and skips what is done: clips already in the project, summaries already saved, searches already run, rows already checked. When the user adds a new batch later, only the new clips are uploaded and summarized; the two searches run again because a search covers the whole project, and rows already in catalog.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, ffprobe -version and python3 --version. Without ffmpeg and ffprobe the clips cannot be measured or checked; stop and say so. Without python3 the catalog still works; the rename step then gives the plan only.
- List the clip folder once to confirm it can be read.
Done when vivu_get_account shows can_create_projects: true, ffmpeg and ffprobe answer, and the user has been told whether python3 is present.
Step 2: Inventory the folder
Goal: clips.csv with one row per clip and its measured duration.
- List the video files (FOLDER is the clip folder):
find "FOLDER" -type f \( -iname "*.mp4" -o -iname "*.mov" -o -iname "*.m4v" \) -not -path "*/clip-catalog/*"
- Measure each file: ffprobe -v error -show_entries format=duration -of csv=p=0 FILE, where FILE is one path from the list. Record the size in bytes too; Step 4 needs it for the upload path.
- Write clips.csv. source_folder is the subfolder the clip sits in (download batches often live in one subfolder each, which is itself useful in the catalog).
- Look for two clips with the same file name in different subfolders. Vivu keeps the name, so two clips called 0001.mp4 cannot be told apart by name alone. Step 4 matches them by name and duration; if two share both, upload them in separate batches.
The find listing was not exercised in our test run (the test clips were listed another way); ffprobe measured all twelve clips.
Done when clips.csv has one row per video file with duration_s filled, and the user has seen the count and total minutes.
Step 3: Size the job and get approval
Goal: the user sees the index minutes before anything is uploaded.
- Sum duration_s to minutes.
- Searches: two precise searches for the whole library (aerial and time-lapse), plus one rewording each if the first page is not clean, plus the optional readable text search if the user wants on_screen_text cross-checked; ask now whether to run it. A precise search uses 5 credits in total. Label the credit total as an estimate.
- Summaries: whether vivu_get_video_summary uses search credits was not measured in our test run (the test account shows no remaining allowance). Call vivu_get_usage before and after the first batch of summaries and tell the user what changed.
- 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) | 2 to 5 precise searches x 5 (the fifth only if the user chose the text search) | from vivu_get_usage | yes or no |
As an estimate, 300 clips of 15 seconds are 75 minutes, which fits a Premium month; a Free month covers about 80 such clips. If the job does not fit, offer these levers in order: catalog the subfolders the user reaches for most first; split the folder into monthly batches; move to a larger plan. Say which clips are left for later. Do not suggest dropping long clips to save minutes without saying which ones.
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.
Done when the user approves the clip list, the batch 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 library'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. Record the project_id in config.json.
- 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 message or 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; larger files go through the user's browser or the Vivu web app. Never split, trim or recompress a clip to fit.
- Poll vivu_list_videos every 30 seconds or so 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 uploaded_name and 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, twelve clips (2.6 minutes) were all ready about 8 minutes after the upload link was requested, indexed a few at a time, and each duration_ms matched the ffprobe duration to the millisecond, which is what makes the name and duration match safe.
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 and draft the rows
Goal: a draft row per clip from Vivu's own description, and an approved column layout.
- 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 add the clip to state.json. Clips this short usually come back as a single section covering the whole clip.
- Turn each summary into the draft columns, using the words of the summary and a fixed vocabulary kept in config.json:
- subject and setting: a few plain words each ("stacked rock formation", "green meadow with forested hills").
- time_of_day: day, golden hour, dusk, night, night to dawn, or "not stated". A frame cannot tell a sunrise from a sunset, so both are golden hour.
- weather: clear, clouds, rain, snow, fog or mist, or "not stated".
- render: yes when the summary says 3D, animated, CGI or render.
- on_screen_text: only words the summary quotes, marked for a frame check in Step 7.
- aerial_from_summary and timelapse_from_summary: yes only when a sentence says the shot itself is from a drone or the air, or that the clip is a time-lapse or hyperlapse. Read sentences, not keywords: a summary of a drone filmed from the ground can talk about "the unmanned aerial vehicle".
- Leave shot_size and camera_motion as "not stated". In our test run the summaries named a shot size only for the rain close-up and the neon sign, and the neon sign one was wrong; camera movement was described for some clips and not for others. Step 7 fills both columns from frames, so every row takes them from the same source.
- Show the user one sample row and the field mapping, and wait for approval before drafting the rest. Sample row (placeholder values; CLIP_ID is the original name without its extension, DOWNLOAD_BATCH the subfolder):
original_name,suggested_name,subject,setting,shot_size,camera_motion,time_of_day,weather,on_screen_text,aerial,timelapse,duration_s,source_folder,checked,sources,notes
CLIP_ID.mp4,aerial_lake-islands-golden-hour_wide_CLIP_ID.mp4,silhouetted islands on a calm lake,lake with hills,wide (from frames),flies forward,golden hour,not stated,none,yes,no,20.02,DOWNLOAD_BATCH,frame,aerial: search+summary,
| Field | Source | If unavailable |
|---|---|---|
| subject, setting | the summary | the clip goes to the frame check |
| time_of_day, weather | the summary | "not stated" |
| shot_size, camera_motion | frames in Step 7 | "not stated" |
| on_screen_text | the summary or the optional text search, then a frame | "none" |
| aerial, timelapse | Step 6 searches and the summary, frames when they disagree | UNCERTAIN |
| render | the summary, then a frame | "no" |
| checked | frame, summary+search, or summary only | summary only |
Say which fields are inferred: every column is inferred from the summary until a frame confirms it, which is what the checked column records.
Worked example from our test run (summaries)
The corpus was twelve public stock clips from a free stock site, 720p, no dialogue, named only by their stock number (2.6 minutes in total): drone shots, time-lapses, a 3D render, clips with readable signs, and look-alikes for each tag. Truth for every field was written from contact sheets before any Vivu call.
The summaries named the subject and the setting correctly for all twelve clips, and added details the contact sheets had missed (a red buoy on the river, a light trail from climbers on a mountain ridge). Time of day was right whenever it was stated. Shot size was the weak field: only the rain close-up and the neon sign summaries named a shot size, and the neon sign one was wrong (it called a medium shot a close-up), so shot size never comes from the summary. Camera movement was described for some clips and not for others, and was right where it was described apart from a tilt called a pan. The summaries called the sky, mountain and highway time-lapses time-lapses but described the night city hyperlapse as an ordinary drone shot, which is why Step 6 exists. Whether reading summaries uses search credits was not measured in our test run.
Done when summaries/ has a file for every clip, every clip has a draft row, and the user has approved the sample row and the field mapping.
Step 6: Cross-check the aerial and time-lapse tags with two searches
Goal: the two tags editors filter by most, checked by a second signal.
| Field | Query | Mode | maximum_results |
|---|---|---|---|
| aerial | aerial drone footage where the camera itself is flying above the land, water or city | precise | the number of clips in the project, up to 100 |
| timelapse | a time-lapse where the light changes from day to dusk or from night to dawn within a few seconds, or car lights blur into continuous streaks | precise | same |
| on_screen_text (optional) | readable words, letters or a sign visible in the picture | precise | same |
Run the text search only if the user chose it in Step 3.
The chain: the summaries give every column for every clip; these searches look across the whole project for the two tags, and where a search and a summary disagree, frames decide in Step 7. There is no speech to flip from, so the flip here is from what a clip contains (the summary) to how it moves over time (the searches). All three are precise because precise returns a reason Claude can read and check; fast returns the whole file with an empty reason.
In our test run every aerial and time-lapse result covered the whole clip, so for clips this short the tag searches work as a filter on clips, not on moments; the text search returned some shorter windows.
maximum_results is the ceiling on how many clips a search can list: set it to the clip count, and keep each project at 100 clips or fewer so no tag is cut off. The time-lapse wording names the two things a sped up clip shows (light that changes within seconds, car lights that become streaks) because the first, looser wording matched ordinary moving clouds and traffic.
Using fast for tagging was not tried in our test run.
- Run each query with vivu_search_videos (project_id, query, mode "precise", maximum_results as above). 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/FIELD.json with its result_page_url field removed. The result page link may go in the live reply; it expires after four hours, so it never goes into a file.
- Reconcile per clip: search and summary both say yes, tag yes (sources: search+summary); both say no, tag no; they disagree, the clip goes to the frame check in Step 7 with the tag UNCERTAIN until then.
- The text search is a second signal only. Every word it reports is read from a frame before it goes into on_screen_text.
- Show the user the counts per search: clips returned, how many agree with the summaries, and how many go to the frame check.
Worked example from our test run (searches)
In our test run the aerial search returned 4 results, 4 real and 0 false, and missed none of the drone shots in the truth. The drone filmed from the ground, the mountain view and the view from a bridge were not returned, and the summaries agreed on every clip, so no aerial tag needed a frame check.
The first time-lapse wording returned 7 results, 4 real and 3 false: a real time Times Square street scene, the 3D render and the drone against clouds, each with a reason claiming fast moving clouds or traffic. After 1 rewording on the same corpus, the wording above returned 5 results, 4 real and 1 false, and missed none of the time-lapses in the truth. The false one was a real time drone flight at sunset. Search and summaries disagreed on the night city hyperlapse (search right, summary silent) and on that drone flight (search wrong); the frames settled both.
The optional text search returned 3 results, 2 real and 1 false: the neon HOTEL sign and the Times Square billboards were real, and the "letters" it read in a snowy city were rows of parked cars. The searches were precise, an estimate of 20 credits for the test run.
Done when each search has run once, results/ holds the raw results, and every clip has a tag of yes, no or UNCERTAIN with its source.
Step 7: Check frames and finish the catalog
Goal: catalog.csv in which every tag has been either agreed by two sources or seen in frames.
- Pick the clips to check: every clip with an UNCERTAIN tag, every on_screen_text or render claim, and a random sample of the rest (at least 10 clips or 10 percent of the batch, whichever is more). If the sample finds a wrong subject or setting, check every clip.
- For each clip, extract one strip of three frames at 10, 50 and 90 percent of its length:
ffmpeg -v error -ss T10 -i FILE -ss T50 -i FILE -ss T90 -i FILE -filter_complex "[0:v][1:v][2:v]hstack=inputs=3,scale=1200:-1" -frames:v 1 clip-catalog/frames/NAME_strip.png
FILE is the clip, T10, T50 and T90 are 10, 50 and 90 percent of duration_s in seconds, NAME is the original name without its extension. Look at the strip: it shows the subject, the setting, the shot size, readable text, and whether the camera moves. 3. For a time-lapse question, one strip is not enough. Extract six frames half a second apart from the middle of the clip:
ffmpeg -v error -ss START -t 3 -i FILE -vf "fps=2,scale=400:-1,tile=3x2" -frames:v 1 clip-catalog/frames/NAME_every_half_second.png
START is a time in seconds near the middle. People who move one step between frames, or a sky that does not change, mean real time; clouds that change shape, light that changes, or car lights drawn as streaks mean a time-lapse. A flickering sign is not a time-lapse, and slow motion is the opposite of one. 4. Write what the frames show: shot_size (close-up, medium, wide) marked "from frames", camera_motion (static, pan, tilt, push in, pull back, orbit, or flies forward), the settled tags, and on_screen_text read from the frame. A claim the frame does not support is dropped and counted as false. 5. Set checked to frame for every clip looked at, summary+search where two sources agreed and no one looked, and summary only for the rest. Rows that are not frame are unverified tags, not facts, and the report says so. Report the counts to the user: clips checked, tags changed by the frame check (these are the false positives), and rows still unverified. 6. Show the user catalog.csv sorted by source_folder, and point out every UNCERTAIN cell.
In our test run all twelve clips were checked with strips, because the corpus is small enough to look at in full. The frames confirmed the night city hyperlapse as a time-lapse, removed the time-lapse tag from the sunset drone flight, and replaced the parked car "letters" with none; afterwards every aerial and time-lapse tag matched the truth. The strips were also how shot size was filled; that step was not measured against separate truth.
Done when catalog.csv has one row per clip with checked filled in, and the user has seen the counts of checked rows and changed tags.
Step 8: Build the rename plan and hand over the script
Goal: rename_plan.csv approved by the user, and a script the user runs themselves.
- Build new names from the approved pattern and the catalog: lowercase, words joined with "-" inside a part and "_" between parts, no other punctuation and no spaces, at most about 80 characters before the extension, and always ending with the original name. Tags go first only when they are checked (checked = frame) or both sources agree. Two clips must never get the same new name; the original number at the end keeps them apart.
- Write rename_plan.csv with two columns, original_path and new_path, both full paths in the same folder as the clip. Moving clips between folders is not part of the plan.
- Show the user the first rows and the full count, and say plainly that renaming breaks the links in any editing project that already uses these clips (Premiere Pro, DaVinci Resolve and Final Cut Pro ask to relink by name), so it is best done before the clips go into a project, or followed by a relink.
- Save this script as apply_renames.py in clip-catalog/. It prints what it would do; only with --apply does it rename, it never overwrites an existing file, and it writes an undo file:
import csv, os, sys, time
plan = next((a for a in sys.argv[1:] if not a.startswith("--")), "rename_plan.csv")
apply = "--apply" in sys.argv
with open(plan, newline="", encoding="utf-8") as f:
rows = list(csv.DictReader(f))
targets = [r["new_path"] for r in rows]
if len(set(targets)) != len(targets):
sys.exit("Two rows share a new_path. Fix the plan first.")
undo = []
for r in rows:
old, new = r["original_path"], r["new_path"]
if not os.path.exists(old):
print("MISSING", old)
continue
if os.path.exists(new):
print("SKIPPED, target exists", new)
continue
print(("RENAMED " if apply else "WOULD RENAME ") + old + " -> " + new)
if apply:
os.rename(old, new)
undo.append({"original_path": new, "new_path": old})
if undo:
name = "rename_undo_" + time.strftime("%Y%m%d_%H%M%S") + ".csv"
with open(name, "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=["original_path", "new_path"])
w.writeheader()
w.writerows(undo)
print("Undo file:", name, "(run this script on it with --apply to undo)")
- Tell the user to run it once without --apply (python3 apply_renames.py rename_plan.csv), read the output, and then run it with --apply if it looks right. Claude does not run --apply.
- After renaming, the Vivu project still shows the old names. catalog.csv keeps original_name next to suggested_name, so a later Vivu search result can be matched back.
Running the script was not exercised in our test run: rename_plan.csv was written, but apply_renames.py was not run on the test clips.
Done when the user has approved rename_plan.csv and has apply_renames.py, or has chosen to keep the original names and use the catalog only.
Compliance
- Rights to the clips. Catalog only footage the user has the right to use (their own shoots, licensed stock, renders they made, client footage they are allowed to process). Renaming does not change a stock license; the original number stays in the new name so the license can still be matched. Ask before Step 4.
- Uploading to Vivu. 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. Client footage under an NDA needs the client's permission to go into a cloud service. The skill never calls vivu_delete_project or vivu_delete_video unless the user asks, and confirms first.
- People in the footage. Passers by in stock clips are described as "pedestrians", never identified. The skill does no face recognition and no identification of people or logos; brand names only appear in on_screen_text when they are readable in a frame. Private videos centered on minors are not part of this skill; leave them out of the folder.
- No automatic sync. The skill catalogs the folder the user names, once per batch; it does not watch or sync a whole drive.
- The user's files are not changed by Claude. The rename is the user's action (Step 8).
Known failure modes
| Symptom | Cause | Fix |
|---|---|---|
| (observed) the time-lapse search returns real time clips, with a reason such as "The background shows a time-lapse of clouds moving much faster than real time behind the hovering drone." | a loose wording matches any moving clouds or traffic | use the light change and light streak wording from Step 6, and check every disagreement with a half second strip |
| (observed) a real time drone flight at sunset comes back from the reworded time-lapse search | the wording about light changing from day to dusk also fits a sunset scene | keep the tag UNCERTAIN until the half second strip shows a steady sky |
| (observed) the summary describes a night city hyperlapse as an ordinary drone shot | summaries do not always say a clip is sped up | the time-lapse search is the second signal; frames decide when they disagree |
| (observed) the text search reports words that are not there: "The letters 'OKOLL' are clearly visible and readable on the snow-covered ground" | the reason text read rows of parked cars as letters | on_screen_text only from a frame Claude has looked at |
| (observed) a drone filmed from the ground has the word "aerial" in its summary | the summary talks about "the unmanned aerial vehicle" | read whole sentences; aerial means the camera flies |
| (observed) most summaries name no shot size, and one called a medium shot a close-up | summaries describe what is in the clip, not how it is framed | take shot size from the frame strip, or leave it as not stated |
| (observed) the summary says sunrise where the stock title says sunset | a frame cannot tell sunrise from sunset | use golden hour for both |
| "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 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 |
| catalog rows from different subfolders point at the same Vivu video | clips in different subfolders share a file name | match on name and duration; upload same name clips in separate batches |
| a tag search lists exactly maximum_results clips | the search reached its ceiling | raise maximum_results to the clip count (maximum_results accepts 1 to 100), or split the library into smaller projects |
| a tag search returns nothing for a tag the user expects | an empty result does not prove the footage has no such shot | check a sample of likely clips with frames before writing "no" |
| the editing project shows media offline after the rename | the editor links clips by file name | rename before import, or relink by name in the editor; the undo file restores the old names |
| the allowance runs out partway | the batch was larger than what was left this month | stop, keep state.json, and continue the next batch next month or on a larger plan |