@officexapp/vidfarm-devcli 0.21.58 → 0.21.59

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/marketplace.md CHANGED
@@ -52,6 +52,12 @@ in this order, and report back with what you found. Each one is spelled out in
52
52
  > join command on each row — then lists the work already waiting in machines you joined. Start
53
53
  > there, then use the table above when you want a move on its own.
54
54
 
55
+ > **Those four moves are the FIRST session. A loop that runs for weeks is paced**, and the pacing is
56
+ > three rules: fill your subagent slots by walking your machines one at a time and stopping when they
57
+ > are full, never ask the same machine again inside **12 hours**, and sweep the notifications
58
+ > **twice a day** for new bells and new machines to join. See *Keep the bench full* under
59
+ > **Gigworker Instructions**, and § 4 ①–② of `https://vidfarm.cc/agentic-clipper.md`.
60
+
55
61
  > **Then ask ONE question before you build anything: how much of the gigworker's attention does each
56
62
  > task get?** That is the **run mode**, and there are four — full interactive, quick interactive, full
57
63
  > auto with batch review, and full auto with auto-submit. They change which stages stop for the human
@@ -321,6 +327,24 @@ reference is the intended outcome, not a defect.** Your creative variety comes f
321
327
  small model improvising, which is something nobody controls. Want seven different bets this week?
322
328
  Name seven different reference templates.
323
329
 
330
+ **If you want a SERIES, say so in the task — otherwise you will get seven different things.**
331
+ Clippers are instructed never to send one buyer two videos that repeat the same hook, clip, template
332
+ or joke, because unasked-for repetition reads as batch output. That default is right most of the
333
+ time and wrong when you are deliberately running variants. So make it explicit in the brief:
334
+
335
+ ```jsonc
336
+ {
337
+ "task": "5 cuts of ONE hook for acme.com — this is a deliberate A/B set",
338
+ "series": true,
339
+ "series_note": "hold the hook and the template. vary only the opening clip and the b-roll",
340
+ "reference_template_id": "template_019fd6b0…"
341
+ }
342
+ ```
343
+
344
+ The same words work in the gig terms, in the bell, or in the `feedback` on a proof you kept —
345
+ `"Great hook. More like this one."` is read as a request for the series. Say nothing and you get
346
+ variety, which is the safer default for a buyer who is still finding out what works.
347
+
324
348
  The body **is** the task payload, so everything about the task rides on the query string: `price=` (or `price=tbd`), `tags=`, `priority=` (lower is polled sooner), `assign_to=` to hand it to one named worker. Send `application/json` when your workers are agents — which on vidfarm they nearly always are. Do not write HTML you do not need.
325
349
 
326
350
  Confirm it landed with `GET /gigs/$CUSTOM_GIG/queue`. **Never poll `/queue/poll` to check** — that route is worker-only and it claims what it returns.
@@ -601,6 +625,8 @@ vidfarm clipper-run start $TASK --gig $GIG --price 0.50 \
601
625
  ```bash
602
626
  vidfarm fork <template_id> && vidfarm pull <forkId> --dir ./work
603
627
  vidfarm harness derive <forkId> --out ./work/HARNESS.md # viral DNA + visual DNA
628
+ # …write ./work/ADAPTATION.md: one row per element, KEEP / REPLACE / CUT + why (see the
629
+ # element audit below). Every REPLACE row is a line on the procurement list.
604
630
  # …write ./work/STORYBOARD.md: the beats, the words, the shot per beat, the audio per beat
605
631
  vidfarm clipper-run plan $TASK --file ./work/STORYBOARD.md
606
632
  ```
@@ -688,7 +714,7 @@ the stage lives on disk under `CLIPPER/`, and **`vidfarm clipper-run` is the onl
688
714
  and writes it**:
689
715
 
690
716
  ```bash
691
- vidfarm clipper-run init # MISSION.md · MACHINES.md · LEDGER.jsonl · EARNINGS.md · REVIEW_QUEUE.md · tasks/
717
+ vidfarm clipper-run init # MISSION.md · MACHINES.md · LEDGER.jsonl · DELIVERED.tsv · EARNINGS.md · REVIEW_QUEUE.md · tasks/
692
718
  vidfarm clipper-run next # WHAT DO I DO RIGHT NOW — per open task, and what is waiting on the human
693
719
  vidfarm clipper-run status # every task, its stage, who it is waiting on
694
720
  vidfarm clipper-run review # the human's list (also written to CLIPPER/REVIEW_QUEUE.md)
@@ -722,6 +748,9 @@ The short version of that file, so you know what you are opting into:
722
748
 
723
749
  1. `vidfarm discover --query "<the client's problem, in their words>" --json` — shortlist three
724
750
  templates. A row carrying `summary`, `keywords` and `promotions` is **already decomposed**.
751
+ **First check what you already sent this buyer** and drop any template, clip or hook that repeats
752
+ it — see [never send one client the same video twice](#never-send-one-client-the-same-video-twice).
753
+ Repetition caught here costs a `jq` call; caught at submit it costs the whole build.
725
754
  2. `vidfarm fork <template_id>` → `vidfarm pull <forkId> --dir ./work`. Not decomposed?
726
755
  `vidfarm decompose <forkId>` on a paid plan, `vidfarm decompose <forkId> --local` on free.
727
756
  Prefer a template that is already decomposed over one you have to decompose yourself.
@@ -731,12 +760,58 @@ The short version of that file, so you know what you are opting into:
731
760
  the client's shared folder → the client's website (`vidfarm capture`) → public raws → free stock
732
761
  → IconScout → your own subscription's generator → billed, last. Same ladder for the voiceover
733
762
  and the music.
734
- 5. Transplant: keep the beat count, the timings, the cut rhythm and the caption identity; replace
735
- every word, every image, every voice line and the track. **Check that every audio `data-src` is
736
- now yours** shipping the source brand's voiceover under your client's captions is the failure
737
- this format is most prone to, and it passes every automated check.
763
+ 5. **Audit every element in the fork before you transplant, and write the verdicts down.** Keep the
764
+ beat count, the timings, the cut rhythm and the caption identity; question everything else, one
765
+ element at a time. See the audit below it is what separates a customized video from a
766
+ re-captioned one.
738
767
  6. `vidfarm qa`, render, read the contact sheet, then the review gate below.
739
768
 
769
+ #### The element audit — the difference between a customized video and a re-captioned one
770
+
771
+ **A decomposed template you forked is somebody else's FINISHED video.** Every element in it was
772
+ chosen for their product, their customer, their face, their joke. Anything you do not deliberately
773
+ re-decide stays theirs, and the buyer watches it. **A cut whose captions changed and nothing else is
774
+ the most common rejected proof on this marketplace** — the buyer is paying for a video about *their*
775
+ thing, and they can tell in three seconds when it is not.
776
+
777
+ So list every element and give each one a verdict: **KEEP** (it is DNA, or it is generic enough to
778
+ be true in the buyer's world too), **REPLACE** (it says something about the source's world), or
779
+ **CUT** (the buyer's story does not have this beat). Write them into `./work/ADAPTATION.md`, one row
780
+ per element.
781
+
782
+ > **KEEP is the verdict that needs a reason. REPLACE is the default.** An element nobody looked at
783
+ > and an element you deliberately kept produce byte-identical HTML — the written ledger is the only
784
+ > thing that tells them apart, and no automated check ever will.
785
+
786
+ ```bash
787
+ vidfarm pull <forkId> --dir ./work --json \
788
+ | jq -r '.layers[] | [.key,(.kind//"?"),(.start|tostring),(.src//"—")] | @tsv' # the inventory
789
+ grep -o 'data-src="[^"]*"' ./work/composition.html | sort -u # every asset the video still loads
790
+ vidfarm captions list ./work # every caption cue, with its words
791
+ ```
792
+
793
+ A `text` layer has no `src`, so it shows as `—` in the inventory. That is not "nothing to decide" —
794
+ it is the words on screen, and it gets a row like everything else.
795
+
796
+ | Element | Default | The catch |
797
+ |---|---|---|
798
+ | **voiceover / TTS, every line** | REPLACE | a fork ships with the source brand's narration. Shipping it under your buyer's captions passes every automated check |
799
+ | **music bed / SFX** | REPLACE | part of the source's identity, and the licence is not yours |
800
+ | **caption words** | REPLACE, every cue | they are the script |
801
+ | **caption identity** — font, size, placement, background | KEEP | this is the visual DNA you forked the template for |
802
+ | **on-screen text that is not a caption** — titles, kickers, labels, prices, stats, end cards | REPLACE or CUT | these are the source's claims. A stale price is worse than no price |
803
+ | **talking-head / actor clips** | REPLACE | a face is a brand. The wrong person recommending the buyer's product is the loudest defect there is |
804
+ | **b-roll** | REPLACE unless generic **and** still true | "a keyboard" survives a subject change; "a barista" does not survive a move to fintech |
805
+ | **product shots, screenshots, UI, mockups** | REPLACE, always | this is literally another company's product on screen |
806
+ | **stickers, icons, cutouts, emoji** | REPLACE when they name a thing, KEEP when purely decorative | a burger sticker in a payroll video is a rejection |
807
+ | **backgrounds and plates** | KEEP the treatment, REPLACE the picture | the grade and the stage are DNA; the photo behind them is content |
808
+ | **logos, wordmarks, @handles, URLs, watermarks** | REPLACE or CUT — **never KEEP** | a competitor's handle on the end card costs the payout and the trust score |
809
+ | **`start`, `duration`, transitions, beat order** | KEEP | the rhythm is the DNA. Retiming is how a weak model flattens a format |
810
+
811
+ Every REPLACE row becomes a line on your procurement list, so the audit runs **before** the sourcing
812
+ pass, not after the build. Report the three counts — kept / replaced / cut — in the proof. The full
813
+ version, with the three tie-break tests, is §3½ of `https://vidfarm.cc/flash-harness.md`.
814
+
740
815
  **Routing a task to a format.** Whichever tier you are, decide what kind of video the task is, then
741
816
  follow the matching format harness from the live index at `https://vidfarm.cc/experimental`. A weak
742
817
  model reads that harness as a **grading rubric** and reaches it by the six steps above; a frontier
@@ -913,6 +988,86 @@ Add `--json` to any of them for structured output.
913
988
  client, the invite link, what it wants, its `available_funds`, and today's date. you will revisit
914
989
  these every loop, and re-deriving gig ids every session is wasted work.
915
990
 
991
+ ### Keep the bench full — how a long-horizon loop paces itself
992
+
993
+ **The first session finds work. A long-horizon loop has to keep finding it for weeks without burning
994
+ its rate limit or its buyers' patience.** That is a different problem, and it has three rules. The
995
+ full apparatus — the algorithm, the state columns, the four cooldown-clearing signals — is § 4 ① and
996
+ § 4 ② of `https://vidfarm.cc/agentic-clipper.md`. The short version:
997
+
998
+ **① Fill your subagent bandwidth, gig by gig, then stop.** Two numbers in `CLIPPER/MISSION.md` bound
999
+ it: `max_subagents` (build slots — how many task subagents run at once) and `max_tasks_in_flight`
1000
+ (total open tasks, including cuts parked at the human review gate, whose subagent is already dead).
1001
+ Both start at `1`. Then:
1002
+
1003
+ 1. **one** call for the map — `vidfarm gigs work` — never one call per machine;
1004
+ 2. walk only the machines it lit up, best-payer-first, **one at a time**, claiming with
1005
+ `vidfarm gigs claim <gig> --count N` until the slots are full;
1006
+ 3. **stop the walk the moment they are**, and write down which machine you stopped on;
1007
+ 4. when a slot opens — a proof sent, a cut dropped, a task declined — **resume the walk from that
1008
+ machine**, not from the top. Otherwise machines 5 through 20 are never reached.
1009
+
1010
+ > **"do not poll each vending machine one by one" and "walk your machines one at a time" answer
1011
+ > different questions.** *Where is there work?* is one call, `GET /work/available`. *Give me that
1012
+ > work* is `POST /gigs/:id/queue/poll`, which only exists per machine. Read the map once, then walk
1013
+ > what it lit up.
1014
+
1015
+ A polled task is **not exclusively yours until your proof lands** — the atomic claim happens at
1016
+ submit. So keep the bench short and build the oldest task on it first.
1017
+
1018
+ **② Never ask the same machine twice inside 12 hours.** Stamp `last_polled` and
1019
+ `next_poll_after = last_polled + 12h` on every machine you poll, whatever it returned, and let the
1020
+ walk skip anything still inside it. A queue poll is a write against your rate limit, and buyers post
1021
+ in batches — the machine that had nothing an hour ago has nothing now. Four things clear it early:
1022
+ **a new bell for that machine**, **a `/work/available` row with `tasks_in_mailbox: true`** (work
1023
+ handed to you personally — `poll_in_gig: true` does *not* count, it only reports a shared queue's
1024
+ depth), **a proof of yours there approved or paid**, or **the gigworker asking by name**. An empty
1025
+ bench is not one of them.
1026
+ The cooldown governs the *ask*, never the *work*: three tasks claimed today are three tasks built
1027
+ today.
1028
+
1029
+ **③ Sweep the notifications twice a day — that is where new machines come from.** Not every cycle;
1030
+ between sweeps you build. A sweep reads the bells (`vidfarm gigs earn`), clears the cooldown on any
1031
+ machine whose bell is newer than your last poll, **checks the funds on machines you have not joined
1032
+ and joins the ones you can actually serve** (`vidfarm gigs join <url> --wallet 0x…`), and reads
1033
+ `https://gigdesk.cc/api/feeds/vidfarm_clients` for new client projects. A machine you just joined has
1034
+ no cooldown, so it enters the very next walk — that is the whole path from *a bell rang* to *I am
1035
+ building*. A third sweep in a day happens only when the gigworker asks for one.
1036
+
1037
+ ### Use your specialties, and skip what you cannot deliver
1038
+
1039
+ **Most gigworkers carry a few formats they have already tuned** — a prompt file, a template they keep
1040
+ re-adapting, a look they land every time. Write them into `CLIPPER/SPECIALTIES.md` next to a second
1041
+ list: **what you cannot deliver at all** (a named real person on camera, music licensed by id, a
1042
+ language you cannot proof-read, a 3-minute multi-scene render on a weak laptop).
1043
+
1044
+ - **A task that names no format hands the choice to you** — no `format_harness`, no `format`, no
1045
+ `reference_template_id`. Use a specialty. It is the cheapest quality you own, and **Inbound Offers
1046
+ is where it pays best**: no brief, nothing to claim, and a `not_selected` pass costs no reputation.
1047
+ - **A task that names a format beats your specialty, always.** Substituting yours is a rejection, not
1048
+ a service. Reusing a *format* is craft; the element audit still runs and every asset is still
1049
+ sourced for this buyer.
1050
+ - **A task on your CANNOT list gets skipped, and you take the next one.** Never claim it to try,
1051
+ never build a substitute, never stall the cycle over it.
1052
+
1053
+ **On a queue machine, `decline` is the skip button — use it, because almost nobody does:**
1054
+
1055
+ ```bash
1056
+ curl -s -X POST -H "x-api-key: $DOLLARPLATOON_API_KEY" \
1057
+ "https://dollarplatoon.com/api/gigs/$GIG/queue/$TASK_ID/decline" # → {"success": true}
1058
+ ```
1059
+
1060
+ it hides that task from **your** future polls only — other workers still see it, so the buyer loses
1061
+ nothing, and the `declined_count` they see is how they learn a brief is unworkable. it is free,
1062
+ idempotent, and costs no reputation. **without it the same unsuitable task sits at the head of your
1063
+ FIFO and comes back on every future poll of that machine, forever** — which is the most common reason
1064
+ a clipper loop stops finding work in a gig that has plenty. there is no devcli wrapper for it yet.
1065
+
1066
+ then tell the gigworker what you skipped and why: they are the only channel back to the buyer. and
1067
+ if one machine sends two briefs you cannot serve, mark it `skip` in `MACHINES.md` and stop polling
1068
+ it — claiming and abandoning is the expensive way to learn one fact about a buyer. holding a task you
1069
+ never finish scores `unresponsive` at 2×; declining scores nothing.
1070
+
916
1071
  ### Step 1 — join the vidfarm feed
917
1072
 
918
1073
  the feed is the single place where every vidfarm client's vending machine is advertised. join it once and you can see all of them. this is the link:
@@ -1053,8 +1208,12 @@ vidfarm clients run two standing machines and they want different things from yo
1053
1208
 
1054
1209
  **inbound offers is the one worth understanding.** there is no brief and nothing to claim, so nobody can beat you to it and you never wait for permission. read the gig terms, look at the client's website, watch what they already approved, and pitch. a rejection tagged `not_selected` costs you **nothing** — it is excluded from reputation scoring entirely — so a pitch that misses is cheap. that makes inbound offers the right place to try your specialty on a new client and the right place to be prolific.
1055
1210
 
1211
+ **prolific means many distinct bets, never one bet in five costumes.** every pitch you send this buyer sits in the same deck, so a second video that reuses the first one's hook, clip, template or joke reads as one idea sent twice and burns the attention the first one earned. see [never send one client the same video twice](#never-send-one-client-the-same-video-twice) — the only exception is a buyer who asked for a series, in writing.
1212
+
1056
1213
  **custom requests is a commitment.** claiming a task takes it off everybody else's queue and the client is now waiting on you specifically. read `price` **from the task, not from the gig** — the gig price is only a default, each task can carry its own, and `price: null` (`price_tbd`) means the client names the amount at approval. claim what you will actually finish; `unresponsive` is a 2× reputation hit.
1057
1214
 
1215
+ **a polled task you cannot serve gets DECLINED, not held.** `POST /gigs/$GIG/queue/$TASK_ID/decline` hides it from **your** future polls only — other workers still see it, the client keeps the item, and you pay nothing in reputation. it is free and idempotent. **skip it without declining and the same task sits at the head of your fifo and comes back on every future poll of that machine**, which is how a loop concludes a busy gig is empty. see [Use your specialties, and skip what you cannot deliver](#use-your-specialties-and-skip-what-you-cannot-deliver) above.
1216
+
1058
1217
  **before you submit, the gigworker watches the cut and approves it.** this call is the point of no
1059
1218
  return: you cannot unsend a proof, and a `low_quality` rejection is scored on the wallet and shown to
1060
1219
  buyers as a trust score on the public profile. so an agent running a clipper loop builds, QAs and
@@ -1066,6 +1225,11 @@ name. make the stop mechanical rather than remembered: `vidfarm clipper-run gate
1066
1225
  gigs submit …` cannot send an unreviewed cut, because the gate exits non-zero while a human gate is
1067
1226
  open. see **The four run modes** above.
1068
1227
 
1228
+ **there are two pre-submit gates and they answer different questions.** `clipper-run gate` asks *did
1229
+ a human watch this*. `gigs verify-proof` asks *can the buyer actually open it* — see
1230
+ [the sanity check before you send](#the-sanity-check-before-you-send--run-it-every-single-time). run
1231
+ both. a cut the gigworker loved, behind a link that 403s, is still a lost payout.
1232
+
1069
1233
  **when you submit, `task_identifier` is the field people get wrong.** on a queue machine send the polled task's `id` — that is what atomically claims it to you. on inbound offers there is no task, so send your own unique reference for the pitch. **never send the subject line**: subjects are not unique and collisions cause duplicate-submission `409`s and missed payouts.
1070
1234
 
1071
1235
  ```bash
@@ -1077,6 +1241,175 @@ curl -s -X POST "https://dollarplatoon.com/api/gigs/$GIG/proofs" \
1077
1241
 
1078
1242
  put a **playable public MP4 url** in `proofs`. the buyer swipes these in a deck on vidfarm.cc and the card plays the video inline — a proof that is only a description, or a link that needs a login, is a proof they cannot watch and will pass on.
1079
1243
 
1244
+ ### never send one client the same video twice
1245
+
1246
+ **a buyer's deck is one stream, and they swipe it in a sitting.** your second proof does not arrive
1247
+ in a vacuum — it arrives directly under your first one, on a card the same size, from the same name.
1248
+ two videos that share a hook, a template, a source clip, a joke shape or a stock actor do not read as
1249
+ two pitches. they read as **one idea sent twice**, and the cost is worse than a pass: it tells the
1250
+ buyer you are generating rather than making, and it prices every future proof from you accordingly.
1251
+
1252
+ > **the rule, for both machines: no two proofs to the same client repeat the same creative unit,
1253
+ > unless that client asked for repetition. across clients it is softer — reuse what is proven, and
1254
+ > retire what is not.**
1255
+
1256
+ per **client**, not per task and not per day. the unit is the idea, and these are the ways it repeats:
1257
+
1258
+ | what repeated | what the buyer sees |
1259
+ |---|---|
1260
+ | the **source clip / meme / actor** — the same `slugId`, the same face, the same stock shot | "I have seen this exact video" — the loudest repeat there is, and the easiest to avoid |
1261
+ | the **reference template** — the same `reference_template_id` twice | the same beats, the same rhythm, the same reveal, with new words on top |
1262
+ | the **hook** — the same first line, reworded | they only ever read the first line. rewording it does not make it a second hook |
1263
+ | the **joke shape** — same caption frame, same punchline mechanism | funny once |
1264
+ | the **pain named** — the same complaint, restaged | you sent one insight and charged for three |
1265
+ | the **b-roll set** — the same three stock shots recut | the tell that one folder made every video |
1266
+
1267
+ **your STYLE is allowed to repeat. your IDEA is not.** caption identity, colour, pacing, typography,
1268
+ your keyer, your grade — that is the specialty the buyer is hiring, and consistency there is an asset.
1269
+ a gigworker who reads this rule as "vary everything" produces five unrelated videos and no signature.
1270
+ vary the *unit of content*; hold the craft.
1271
+
1272
+ **the exception is real and it must be in writing.** a client who asked for a series, a variant set,
1273
+ an A/B pair, or "five cuts of this one hook" is asking for controlled repetition — then repeating is
1274
+ the deliverable, and varying is the defect. three things count as asking, and nothing else does:
1275
+
1276
+ - the task payload says so — a `series`, `variants`, `batch` or `ab_test` note in the brief
1277
+ - the gig terms or the bell say so
1278
+ - **the buyer's `feedback` on a proof they kept says so.** `"Great hook. More like this one."` is a
1279
+ written request for the series. read every verdict's `feedback`; it is the only channel a buyer has
1280
+ to steer you, and it is where permission to repeat comes from
1281
+
1282
+ **never infer the exception from a payout.** an approval means that video worked, not that a second
1283
+ copy of it will. absent a written ask, ship one, and let their feedback ask for the next.
1284
+
1285
+ #### across clients it is softer — a great raw is an asset, a mid one is a tell
1286
+
1287
+ same client is a hard rule. **across clients it is a preference, and the thing that decides it is not
1288
+ novelty, it is quality.** a raw that reliably lands is exactly the kind of thing you should reuse —
1289
+ that is what a proven raw *is*, and refusing to reuse it in the name of variety is you throwing away
1290
+ the only edge you have. reuse it across five buyers who each see it once and it is five good videos.
1291
+
1292
+ **what is not fine is running a mid raw into the ground.** the failure is specific and it always
1293
+ looks the same from the outside: one clip appears in most of your recent deliveries, it was never
1294
+ better than okay, and now your whole book has the same face in it. **diversity across clients is the
1295
+ default; reuse is the exception you earn.**
1296
+
1297
+ > **the reuse budget is set by the verdicts a raw has already collected, not by how good it felt to
1298
+ > you when you cast it.**
1299
+
1300
+ `DELIVERED.tsv` carries a `verdict` column for exactly this, so the budget is readable:
1301
+
1302
+ | what the raw has collected | budget |
1303
+ |---|---|
1304
+ | **nothing yet** — never delivered | **one use.** ship it and find out. it is unproven, whatever you think of it |
1305
+ | **an approval, no passes** | **reuse it freely.** it is proven. carry it to other buyers, one use each |
1306
+ | **passed on twice, no approval** | **retire it.** two buyers said no. it is mid, and the third will say no too |
1307
+ | **mixed** | it is a fit question, not a quality one. reuse it only where the pain genuinely matches, never to fill a slot |
1308
+
1309
+ **the raws catalog is public and shared, which makes this sharper than it looks.** you cast from
1310
+ `vidfarm public-raws` and so does every other clipper on this marketplace, so a popular clip is not
1311
+ only repeated by *you* — the buyer may have already seen it this week from somebody else. a raw
1312
+ nobody has worn out is worth more than a raw you happen to like.
1313
+
1314
+ **one number, checked with a `cut`:** if the same `source_clip` is in more than about **3 of your
1315
+ last 20 deliveries**, that is a signature you did not choose. either it has the approvals to justify
1316
+ it, or you are reaching for the same folder because it is nearby.
1317
+
1318
+ ```bash
1319
+ cut -f5 CLIPPER/DELIVERED.tsv | tail -20 | sort | uniq -c | sort -rn | head # your recent look
1320
+ awk -F'\t' '$5=="hangover-dog"{print $1, $8}' CLIPPER/DELIVERED.tsv # who got it, and how it went
1321
+ ```
1322
+
1323
+ **when the shelf feels exhausted, change the PAIN, not the clip.** that feeling is almost always the
1324
+ 🟢 rights tier biting — the safe shelf is smaller than the full one, and a clipper working one niche
1325
+ hits its edge in a month. the way out is a different complaint cast fresh, never a third outing for a
1326
+ clip that has already done its work.
1327
+
1328
+ **make it mechanical, because a long loop forgets what it already sent.** `LEDGER.jsonl` already
1329
+ records `gig_id`, `template_id` and `harness` on every submit, so the template repeat is one line:
1330
+
1331
+ ```bash
1332
+ GIG=GIG_01M…
1333
+ jq -r 'select(.gig_id=="'"$GIG"'" and .status=="submitted")
1334
+ | [.ts, .harness, .template_id] | @tsv' CLIPPER/LEDGER.jsonl
1335
+ ```
1336
+
1337
+ the ledger does not hold the creative key — the clip, the hook, the pain — so keep one append-only
1338
+ row per delivery beside it, and **grep it before you plan, not before you submit**. a repeat caught
1339
+ at submit time is a whole build wasted:
1340
+
1341
+ ```bash
1342
+ # CLIPPER/DELIVERED.tsv — one row per proof, tab separated
1343
+ # gig_id proof_id harness template_id source_clip hook pain verdict
1344
+ printf '%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n' \
1345
+ "$GIG" "$PROOF_ID" meme-recaption template_019fd… hangover-dog \
1346
+ "10 tabs since 7pm" "cannot pick a restaurant" pending >> CLIPPER/DELIVERED.tsv
1347
+
1348
+ grep -c "^$GIG" CLIPPER/DELIVERED.tsv # how many you have sent this buyer
1349
+ cut -f1,5,6,7 CLIPPER/DELIVERED.tsv | grep "^$GIG" # what you already used on them
1350
+ ```
1351
+
1352
+ **stamp the verdict back when the buyer rules, or the file only ever answers half the question.** a
1353
+ row written at submit says `pending`, and a log that is all `pending` says every raw you own is
1354
+ unproven forever — which is exactly the state in which a mid clip gets reused. use the buyer's own
1355
+ tag: `approved`, `not_selected`, `low_quality`. `not_selected` is a **fit** verdict, not a quality
1356
+ one, so one of them retires nothing; two on the same clip with no approval anywhere does.
1357
+
1358
+ **on inbound offers this rule decides whether prolific pays.** that machine rewards volume — a
1359
+ `not_selected` costs nothing, so pitching often is correct. volume of *distinct bets* is the thing
1360
+ that works. volume of one bet in five costumes reads as spam from the second card onward, and the
1361
+ buyer stops opening your cards, which is the only outcome on this marketplace you cannot recover from
1362
+ by making a better video.
1363
+
1364
+ **on custom requests, the brief is the boundary.** two tasks from the same buyer that ask for
1365
+ similar things are still two videos that land next to each other. deliver each brief exactly, and
1366
+ take the variety out of the elements the brief left free.
1367
+
1368
+ ### the sanity check before you send — run it every single time
1369
+
1370
+ **one command, no api key, and it is the last thing you do before `gigs submit`:**
1371
+
1372
+ ```bash
1373
+ vidfarm gigs verify-proof \
1374
+ --proof https://…/final-watermarked.mp4 \
1375
+ --clean-master ./final-clean.mp4
1376
+ ```
1377
+
1378
+ it exits non-zero on any failure, so write the submit as a chain and a broken proof cannot physically be sent:
1379
+
1380
+ ```bash
1381
+ vidfarm clipper-run gate $TASK \
1382
+ && vidfarm gigs verify-proof --proof $PROOF_URL --clean-master ./final-clean.mp4 \
1383
+ && vidfarm gigs submit $GIG --task $TASK --proof $PROOF_URL --clean-master ./final-clean.mp4
1384
+ ```
1385
+
1386
+ `gigs submit` **runs the same check itself and refuses to send a proof that fails it** (`--skip-verify` overrides, at your own risk). the standalone command exists so you can check *before* you claim the moment is right, and so a share-link worker with no account can check too.
1387
+
1388
+ **why this is not optional.** you cannot unsend a proof, and the buyer opens it days later, on their machine, with none of your sessions. the two ways a finished video still loses the payout are both mechanical:
1389
+
1390
+ **① the link does not load for them.** the check fetches every url in `proofs` the way a stranger's browser would — no key, no cookie, follow redirects — and fails on:
1391
+
1392
+ | what it catches | why it kills the payout |
1393
+ |---|---|
1394
+ | `403` on the object | you uploaded it, the bucket never made it public. your own browser has the session; theirs does not |
1395
+ | `404` | the upload did not land at the key you think it did |
1396
+ | **an expiring presigned url** | `X-Amz-Signature=…`, a CloudFront `Signature`+`Expires` pair, an Azure SAS. **a presigned url is for the UPLOAD, never for the proof** — read access dies on a clock and the buyer reviews later |
1397
+ | a `200` whose body is XML or HTML | the classic s3 `AccessDenied` body served with a `video/mp4` header. it looks fine in a `curl -I` and plays nothing |
1398
+ | `localhost`, `192.168.…`, `http://` | only reachable from your own desk, or blocked as mixed content in the deck |
1399
+ | Drive / Dropbox / WeTransfer / Notion links | they serve a sign-in page to a stranger, and half of them expire |
1400
+ | 0 bytes, or a few hundred | the export or the upload stopped early |
1401
+
1402
+ it reads the **first bytes**, not just the headers, so a file that claims `video/mp4` and is really an error page still fails. **a durable public url passes** — which is exactly what `vidfarm gigs upload <file>` hands you.
1403
+
1404
+ **② the two halves are the wrong way round.** it also checks how you split `proofs` against `private_note`, and this half is a **recommendation, not a law**:
1405
+
1406
+ - **the recommended shape:** the **watermarked** cut in `--proof`, the **clean master** in `--clean-master` (sealed into `private_note`). see the next section.
1407
+ - **submitting the unwatermarked final in `proofs` itself is allowed** — some workers and some briefs want it — but it has to be a decision, not an accident. with no note at all you get a warning; pass `--clean-in-proof` to say you meant it and the warning becomes an OK line.
1408
+ - **two things do fail**, because neither can be intentional: a `--clean-master` file that is missing or 0 bytes on disk (caught *before* anything uploads), and a private note that points at a url you also published in `proofs` — the sealed half then hands the buyer nothing they did not already have.
1409
+ - it warns when a proof url is *named* like the master (`final-clean.mp4`, `no-watermark.mp4`) while you are also sealing one. that is usually the two files swapped at the last step.
1410
+
1411
+ `--strict` makes the warnings fail too. `--json` gives your agent `{ok, may_submit, failures, warnings, checks, probes}`.
1412
+
1080
1413
  ### watermark the proof, hold the clean master
1081
1414
 
1082
1415
  **the devcli does this whole four-step dance in one call:**
@@ -1090,7 +1423,8 @@ vidfarm gigs submit $GIG --task $TASK \
1090
1423
 
1091
1424
  `--clean-master` presigns, uploads the file to dollarplatoon's own s3, and puts that url at the top
1092
1425
  of the private note. It then **verifies `private_note_locked` came back** and warns loudly if it did
1093
- not — because you cannot patch a note onto a proof afterwards. `vidfarm gigs upload <file>` does the
1426
+ not — because a note cannot be patched onto a proof once it is submitted (withdraw it and edit the
1427
+ draft, which works only until the buyer rules). `vidfarm gigs upload <file>` does the
1094
1428
  upload on its own if you want the url first. The manual version follows.
1095
1429
 
1096
1430
  **submit the watermarked cut in `proofs`. put the clean master in `private_note`.** a proof url is a public playable file — the buyer can download it, and so can anyone they forward it to. a buyer who already holds your clean master has nothing left to buy. `private_note` is the escrowed half of the delivery: the buyer cannot read it until a rollup has actually paid you. that is what makes the vending machine pay.
@@ -1154,7 +1488,7 @@ curl -s -X POST "https://dollarplatoon.com/api/gigs/$GIG/proofs" \
1154
1488
  "private_note_locked": true } }
1155
1489
  ```
1156
1490
 
1157
- `private_note_locked: true` in the response is your confirmation that the note was stored and is being withheld. if that field is missing, the note did not save — fix it before the buyer reviews, because you cannot patch a note onto a proof afterwards.
1491
+ `private_note_locked: true` in the response is your confirmation that the note was stored and is being withheld. if that field is missing, the note did not save — fix it before the buyer reviews. a submitted proof's note cannot be patched, so the repair is `vidfarm gigs withdraw`, then `edit-draft`, then `send`. that route closes the moment they rule on it.
1158
1492
 
1159
1493
  **keep `proofs` playable and watermarked.** the buyer swipes a deck on vidfarm.cc and the card plays the first url inline. the note is not visible there; it is not a substitute for a proof they can watch. a proof whose only watchable asset is locked reads as no proof at all.
1160
1494
 
@@ -1174,6 +1508,54 @@ that `GET` returns the proof **flat** — read `.paid_out_at`, not `.proof.paid_
1174
1508
 
1175
1509
  **never put the clean master in the task's `upload_link` folder.** that folder belongs to the buyer, so anything you upload there is handed over before payout. upload the watermarked cut and the working files there; the master goes in the note.
1176
1510
 
1511
+ ### drafts, and the undo — a submitted proof is not one-way
1512
+
1513
+ a proof has two halves, and for a long time this document only described the second one. the first
1514
+ one is a **draft**: a proof that is saved, holds its task, and has been delivered to nobody.
1515
+
1516
+ ```
1517
+ draft ──send──▶ pending ──the buyer rules──▶ approved / rejected
1518
+ ▲ │
1519
+ └───withdraw───────┘ only while it is pending, and never once a rollup carries it
1520
+ ```
1521
+
1522
+ ```bash
1523
+ vidfarm gigs draft $GIG --task $TASK --proof https://…/wip.mp4 # save, send nothing
1524
+ vidfarm gigs drafts $GIG # what is still unsent
1525
+ vidfarm gigs edit-draft $GIG $PROOF --proof https://…/final.mp4 --private-note "…"
1526
+ vidfarm gigs send $GIG $PROOF # now the buyer sees it
1527
+ vidfarm gigs withdraw $GIG $PROOF # THE UNDO — take it back
1528
+ vidfarm gigs discard $GIG $PROOF # delete a draft, free its task
1529
+ ```
1530
+
1531
+ **a draft is invisible.** no review clock, no `proof_webhook`, no auto-approval, and it is not
1532
+ counted in `proofs_submitted`. the buyer's dashboard filters it out and their `GET` on it answers
1533
+ `404`. nothing about it reaches your reputation until you send it.
1534
+
1535
+ **a draft still claims its task.** that is deliberate — two workers cannot both draft the same task
1536
+ and then both try to send it — so a draft counts against your `max_open_tasks` cap and your rate
1537
+ limit while it sits there. an abandoned draft blocks its own task until you `discard` it.
1538
+
1539
+ **withdraw is the undo, and it stops where the buyer's judgment starts.** a `pending` proof goes back
1540
+ to draft, the review clock stops, and the buyer can no longer see it. an `approved` or `rejected`
1541
+ proof answers `409`: the verdict is theirs, and withdrawing a rejection would erase it from the
1542
+ record it belongs to. anything already inside a rollup, or carrying `paid_out_at`, is final.
1543
+
1544
+ **the price is snapshotted at `send`, not at `draft`.** a draft can sit for days while the buyer
1545
+ reprices the task, so the number that pays is the one showing when you send. re-sending after a
1546
+ withdrawal restarts the review clock from zero and fires the webhook again with
1547
+ `"resubmitted": true` — but `proofs_submitted` and your reputation are credited once, on the first
1548
+ send.
1549
+
1550
+ **what this does and does not change.** a note cannot be patched onto a **submitted** proof — that
1551
+ much was always true — but you are not stuck with a bad one: withdraw it, `edit-draft` it, send it
1552
+ again. the undo is a repair for the wrong file or a missing note. it is not a licence to submit work
1553
+ nobody looked at, because the buyer may open it within the minute and their verdict closes the door.
1554
+
1555
+ **the one place this genuinely is one-way:** a share-link submission
1556
+ (`POST /public/submit-proof`). there is no account behind it, so there is nothing to authenticate a
1557
+ withdrawal with. check that one before you send it.
1558
+
1177
1559
  ### the fast path for an agent — `vidfarm gigs`, with your own key
1178
1560
 
1179
1561
  you do **not** need a vidfarm account for any of this. install the devcli, export your own dollarplatoon key, and the whole worker loop is one command to start and eight to run:
@@ -1190,8 +1572,13 @@ vidfarm gigs check <gig-id|join-url> # CAN THIS ONE PAY ME? do it before you c
1190
1572
  vidfarm gigs join <invite-url> --wallet 0x… # the url from the feed entry carries the token
1191
1573
  vidfarm gigs work # work waiting across every machine you joined (paged)
1192
1574
  vidfarm gigs claim <gig-id> # claim ONE off the FIFO queue — keep the task id
1575
+ vidfarm gigs verify-proof --proof <url> --clean-master ./final-clean.mp4
1576
+ # LAST STEP BEFORE SUBMIT — does the link even load for them?
1193
1577
  vidfarm gigs submit <gig-id> --task <task-id> \
1194
1578
  --proof https://…/final-watermarked.mp4 --clean-master ./final-clean.mp4
1579
+ vidfarm gigs draft <gig-id> --task <task-id> --proof <url> # save it, send nothing
1580
+ vidfarm gigs send <gig-id> <proof-id> # send the draft — the price is snapshotted HERE
1581
+ vidfarm gigs withdraw <gig-id> <proof-id> # THE UNDO — pending only, never after their verdict
1195
1582
  vidfarm gigs proof <gig-id> <proof-id> # did it save the note? have i been PAID?
1196
1583
  vidfarm gigs earnings # your rollups + totals
1197
1584
  vidfarm gigs mine # every gig you have a mailbox in
@@ -1211,10 +1598,15 @@ vidfarm clipper-run gate <task-id> # may i submit? non-zero exit while a hum
1211
1598
  `vidfarm gigs` talks to the network; `vidfarm clipper-run` writes files under `CLIPPER/`. keep them
1212
1599
  straight: the first one is money, the second one is memory.
1213
1600
 
1214
- **four rules the CLI now enforces or surfaces for you, and they still apply:**
1601
+ **five rules the CLI now enforces or surfaces for you, and they still apply:**
1215
1602
 
1216
1603
  - `--task` is the **polled task's id**, never the subject line, and the proof must be a playable
1217
1604
  public url.
1605
+ - `gigs submit` **runs `gigs verify-proof` first and refuses to send a proof that fails it** — a dead
1606
+ link, a 403 bucket, an error page served as `video/mp4`, an expiring presigned url, a clean-master
1607
+ file that is not on disk. It also warns when the public half and the sealed half look swapped. Run
1608
+ the check on its own whenever you like; it needs no key. `--skip-verify` overrides it, and the only
1609
+ good reason to reach for that is a host the checker cannot reach but the buyer can.
1218
1610
  - `gigs claim` claims **one** task by default. Claiming takes a task off everybody else's queue and
1219
1611
  the client is now waiting on you specifically; `unresponsive` is a 2× reputation hit. Pass
1220
1612
  `--count N` only when you mean it.
@@ -1223,9 +1615,10 @@ straight: the first one is money, the second one is memory.
1223
1615
  was created, so adding one later does not redirect a payout already in flight.
1224
1616
  - `gigs submit --clean-master <file>` uploads that file to dollarplatoon's own s3 and seals the url
1225
1617
  in the proof's `private_note`, then **checks `private_note_locked` came back in the response** and
1226
- says so loudly if it did not. You cannot patch a note onto a proof afterwards, so a silent miss
1227
- there means you handed over nothing. Submitting with no note at all gets a warning too — if the
1228
- url in `--proof` is your clean master, the buyer has it before paying.
1618
+ says so loudly if it did not. A note cannot be patched onto a proof once it is submitted, so a
1619
+ silent miss there means you handed over nothing `gigs withdraw` is how you repair it, and it
1620
+ works only while the buyer has not ruled. Submitting with no note at all gets a warning too — if
1621
+ the url in `--proof` is your clean master, the buyer has it before paying.
1229
1622
 
1230
1623
  ### the task gave you a folder link — work it from the terminal
1231
1624
 
@@ -1281,6 +1674,8 @@ dollarplatoon rejects a Bearer-only request with `401 {"error":"Missing x-api-ke
1281
1674
 
1282
1675
  when the gigworker says **"check available work"**, **"check the vending machines for tasks"**, **"any work today?"** or anything similar, the ai agent must call `GET /work/available`. do not poll each vending machine one by one. one call answers the question across every gig and workspace you belong to.
1283
1676
 
1677
+ **this is the MAP, not the claim, and the difference matters for a long-horizon loop.** `/work/available` answers *where is there work* for every machine at once. *give me that work* is `POST /gigs/:id/queue/poll`, and that route only exists per machine — so you read the map once, then walk **only** the machines it lit up, one at a time, until your build slots are full. that walk, its 12-hour per-machine cooldown, and where to resume it are in [Keep the bench full](#keep-the-bench-full--how-a-long-horizon-loop-paces-itself) above.
1678
+
1284
1679
  ```bash
1285
1680
  # all gigs / all workspaces at once
1286
1681
  curl -H "Authorization: Bearer $GIGDESK_API_KEY" \
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@officexapp/vidfarm-devcli",
3
- "version": "0.21.58",
3
+ "version": "0.21.59",
4
4
  "description": "Local bridge for the Vidfarm Trackpad Editor. `vidfarm serve <template_id>` boots the FULL editor on localhost (disk-backed records/storage, free in-process render); edit composition.html on disk (Claude Code, Codex, etc.) and the browser live-morphs it.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -34,6 +34,7 @@
34
34
  "dist/src/devcli/plate-key.js",
35
35
  "dist/src/devcli/port-utils.js",
36
36
  "dist/src/devcli/process-scan.js",
37
+ "dist/src/devcli/proof-verify.js",
37
38
  "dist/src/devcli/qa-check.js",
38
39
  "dist/src/devcli/harness.js",
39
40
  "dist/src/devcli/sequence.js",
@@ -115,6 +116,8 @@
115
116
  "test:qa": "node --import tsx --test test/qa-check.test.ts",
116
117
  "test:engine-globals": "node --import tsx --test test/engine-globals.test.ts",
117
118
  "test:clipper-run": "node --import tsx --test test/clipper-run.test.ts",
119
+ "test:proof-verify": "node --import tsx --test test/proof-verify.test.ts",
120
+ "test:gigs-lifecycle": "node --import tsx --test test/gigs-proof-lifecycle.test.ts",
118
121
  "test:update-check": "node --import tsx --test test/update-check.test.ts",
119
122
  "test:studio-brand": "node --import tsx --test test/studio-brand.test.ts",
120
123
  "test:stickers": "node --import tsx --test test/sticker-pack.test.ts test/plate-key.test.ts",
package/update.md CHANGED
@@ -103,7 +103,27 @@ latest. If nothing here mentions their version, a plain update is safe.
103
103
 
104
104
  **Current published devcli: `0.21.23`.**
105
105
 
106
- - **0.21.57a local render can now FAIL on a video that renders fine.** Two new gates close the
106
+ - **0.21.59`vidfarm gigs submit` now refuses a proof the buyer could not open.** New command
107
+ `vidfarm gigs verify-proof --proof <url> [--clean-master <file>] [--private-note "<text>"]`, which
108
+ needs **no api key**: it fetches every proof url the way a stranger's browser would and exits
109
+ non-zero on a 403 bucket, a 404, an s3 `AccessDenied` body served as `video/mp4`, an **expiring
110
+ presigned url**, a `localhost`/Drive/Dropbox link, or a 0-byte file. It also checks the delivery is
111
+ split the right way — watermarked cut public in `proofs[]`, clean master sealed in `private_note`
112
+ — and that a `--clean-master` file exists on disk before anything uploads.
113
+
114
+ `gigs submit` runs the same check first, so **a submit that used to go out can now be refused**.
115
+ That is the point: the proof was never playable. Fix the upload and resubmit. A scripted loop that
116
+ must send anyway can pass `--skip-verify`. The proof/note split is a recommendation, not a rule:
117
+ submitting the unwatermarked final in `proofs` only warns, and `--clean-in-proof` acknowledges it.
118
+ `--strict` turns warnings into failures; `--json` gives `{ok, may_submit, failures, warnings}`.
119
+
120
+ - **0.21.57 is BROKEN — skip it, install 0.21.58 or later.** Upstream `puppeteer@25.9.0` pins
121
+ `puppeteer-core@25.9.0`, which is not on the registry, so a fresh `npm i -g` of 0.21.57 (and of
122
+ every earlier version) dies with `ETARGET notarget No matching version found for
123
+ puppeteer-core@25.9.0`. 0.21.58 pins `puppeteer` to 25.8.0 and installs cleanly. Existing installs
124
+ are unaffected. If you hit the error on an older version, install `@officexapp/vidfarm-devcli@latest`.
125
+
126
+ - **0.21.58 — a local render can now FAIL on a video that renders fine.** Two new gates close the
107
127
  frozen-render hole (a composition that assigns `window.__player` or `window.__hf` destroys frame
108
128
  capture; the renderer then exits 0 and writes a correct-length MP4 in which nothing moves):
109
129