@officexapp/vidfarm-devcli 0.21.62 → 0.21.63

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.
Files changed (28) hide show
  1. package/.agents/skills/dollarplatoon-skill/SKILL.md +163 -1174
  2. package/.agents/skills/dollarplatoon-skill/SOURCE.md +62 -0
  3. package/.agents/skills/dollarplatoon-skill/skill/clients.md +234 -0
  4. package/.agents/skills/dollarplatoon-skill/skill/feeds.md +326 -0
  5. package/.agents/skills/dollarplatoon-skill/skill/gigs.md +395 -0
  6. package/.agents/skills/dollarplatoon-skill/skill/gigworkers.md +324 -0
  7. package/.agents/skills/dollarplatoon-skill/skill/orders.md +573 -0
  8. package/.agents/skills/dollarplatoon-skill/skill/payouts.md +234 -0
  9. package/.agents/skills/dollarplatoon-skill/skill/platform.md +174 -0
  10. package/.agents/skills/dollarplatoon-skill/skill/prices.md +75 -0
  11. package/.agents/skills/dollarplatoon-skill/skill/pricing-and-tags.md +255 -0
  12. package/.agents/skills/dollarplatoon-skill/skill/proofs.md +555 -0
  13. package/.agents/skills/dollarplatoon-skill/skill/queue.md +404 -0
  14. package/.agents/skills/dollarplatoon-skill/skill/quickstart.md +191 -0
  15. package/.agents/skills/dollarplatoon-skill/skill/staging.md +178 -0
  16. package/.agents/skills/dollarplatoon-skill/skill/tasks.md +588 -0
  17. package/.agents/skills/dollarplatoon-skill/skill/web-pages.md +586 -0
  18. package/.agents/skills/vidfarm/SKILL.md +3 -3
  19. package/.agents/skills/vidfarm/references/core-workflows.md +39 -0
  20. package/SKILL.director.md +42 -3
  21. package/SKILL.md +3 -1
  22. package/clipper.md +20 -0
  23. package/dist/src/cli.js +50 -6
  24. package/dist/src/devcli/delivery-seal.js +119 -0
  25. package/dist/src/devcli/marketplace-console.js +1253 -0
  26. package/dist/src/devcli/marketplace-gigs.js +162 -16
  27. package/marketplace.md +275 -1
  28. package/package.json +24 -3
@@ -0,0 +1,586 @@
1
+ # Web pages, deep links, and embeds
2
+
3
+ Every page you can hand to somebody or frame inside your own product, and the URL params that
4
+ control them.
5
+
6
+ ## Contents
7
+
8
+ - What it is called, and what the URL calls it
9
+ - Role belongs to the VENDING MACHINE, not to you
10
+ - Autologin deep links
11
+ - Universal URL params
12
+ - Vending Machine pages — the list, one machine, the work inbox
13
+ - Order pages — placing one, and watching one
14
+ - The Task page — one task, on a page of its own
15
+ - Notifications — the bell in the navbar
16
+ - The Share Proof link — one proof, on its own review page
17
+ - The Insert Task page — put work in without an account
18
+ - The Submit page — hand in work without an account
19
+ - Feed reader pages
20
+ - Timeline pages
21
+ - Iframe rules that actually matter
22
+ - Page map
23
+ - The older URLs — three generations, all of them live
24
+
25
+ ---
26
+
27
+ ## What it is called, and what the URL calls it
28
+
29
+ The product word is **Vending Machine**. That is what the app says on screen, in the nav, and in
30
+ every heading, and it is the word to use when you write to a user.
31
+
32
+ The URL and the API say **gig**: the pages live under `/gigs`, the entity is a `Gig`, and you read
33
+ one with `GET /gigs/:id`. That is deliberate. An identifier has to hold still while a product word
34
+ is allowed to move, and this one has moved twice already. So:
35
+
36
+ | | Word | Where |
37
+ |---|---|---|
38
+ | On screen | Vending Machine | Headings, nav, buttons, anything a person reads |
39
+ | In the URL and the API | `gig` / `/gigs` | Paths, request bodies, responses, ids |
40
+
41
+ Below, "machine" is used as the short form in prose. It means the same thing as "vending machine";
42
+ the full phrase is spelled out where it is the name of something rather than a reference to it.
43
+
44
+ **Do not build a link with the singular `/gig/:id`** unless you mean the *public* gig page — that
45
+ path and `/gig/:id/join` are a different, unauthenticated family, and live invite links point at
46
+ them. The signed-in pages are all plural.
47
+
48
+ ## Role belongs to the VENDING MACHINE, not to you
49
+
50
+ **There is no persona toggle, and the URL never says which side you are on.** This is the single
51
+ biggest thing to know before you build a link.
52
+
53
+ The app used to have two halves — `/client/*` for someone who had work, `/gigworker/*` for
54
+ someone who did it — and a switch between them. That was always a lie about one machine in
55
+ particular: on an order machine (`inbound_order`) the **owner does the work** and an **outsider
56
+ pays**, so "am I the client or the worker today" had no single answer. It was also a real dead
57
+ end, because a vendor who never found the toggle could not fill a single order.
58
+
59
+ So the personas are gone. There is one account, and for each machine you are either its **Owner**
60
+ or a **Participant** in it. `/gigs/:id` is the only path to a machine, and it renders itself
61
+ from two facts: whether you own it, and what mode it is in.
62
+
63
+ | You | Machine | What `/gigs/:id` shows |
64
+ |---|---|---|
65
+ | Owner | outbound | The dashboard — tasks, proofs, mailboxes, payouts. |
66
+ | Owner | `inbound_order` | The **shop** (price, escrow, invites, members) *and* your order inbox, on two tabs. A vending machine is the one machine whose owner is also its worker. |
67
+ | Participant | outbound | Your work inbox, scoped to this machine. |
68
+ | Participant | `inbound_order` | Place an order, and the orders you have already placed here. |
69
+
70
+ Everything under `/client/*`, `/gigworker/*` and `/machine*` still redirects, in one hop, and the
71
+ redirects are kept well past the 90-day life of any stored link. Nothing you already hold is
72
+ broken — but a link you *build* today should use the paths below, or every visitor takes an extra
73
+ hop. The full three-generation table is at the end of this page.
74
+
75
+ ## Autologin deep links
76
+
77
+ Append `?api_key=` to **any** dollarplatoon.com URL to log in and land on that exact page in one
78
+ step. This is how an agent, an email, or a partner site sends somebody straight to a machine.
79
+
80
+ ```
81
+ https://dollarplatoon.com/gigs/GIG_01HX...?api_key=YOUR_API_KEY
82
+ https://dollarplatoon.com/gigs/inbox?api_key=YOUR_API_KEY
83
+ https://staging.dollarplatoon.com/gigs?api_key=YOUR_STAGING_KEY
84
+ ```
85
+
86
+ - The key is validated, the session stored, and `api_key` is **immediately scrubbed** from the
87
+ address bar and browser history. Other query params survive.
88
+ - Already logged in with the same key? The page loads directly, no redirect or flicker.
89
+ - Logged in as somebody else? The URL's key wins and the session switches.
90
+ - Invalid key? Any existing session is kept; otherwise you land on the page logged out.
91
+
92
+ There is also `/auto-login?api_key=...&redirect=/path` (relative paths only), but the universal
93
+ param above is simpler.
94
+
95
+ > **A URL containing `api_key` grants full account access to anyone who sees it.** Send autologin
96
+ > links over private channels only. Never post one publicly, never put one in a shared document,
97
+ > and never bake one into a public page's HTML.
98
+
99
+ ## Universal URL params
100
+
101
+ These work on any page and compose with `?api_key=`.
102
+
103
+ | Param | Effect |
104
+ |---|---|
105
+ | `hide_navbar=true` | Removes the top navbar entirely (it occupies no space). Ideal for embeds. |
106
+ | `hide_logo=true` | Removes every brand mark: navbar logo and wordmark, footer brand block, share-page header, and the "Powered by" line. For whitelabel embeds. |
107
+ | `view_only_gigs=id1,id2` | On `/gigs/inbox`, restricts to mailboxes in those machines (unread counts and timelines scope too). A banner offers "Show all". |
108
+
109
+ Both `hide_*` params persist for the browser tab across in-app navigation; pass `=false` to undo.
110
+ The footer legal text and the Terms/Privacy links always stay.
111
+
112
+ **`view_only_gigs` applies to the work inbox only.** It used to narrow the owner's gig list as
113
+ well, on the old `/client/gigs`. The machines list at `/gigs` does **not** read it — a list
114
+ that mixes machines you own with machines you take part in has no single thing to filter. Narrow
115
+ the inbox, or link straight to `/gigs/:id`.
116
+
117
+ ```
118
+ # A participant's work inbox for two machines, chrome-free
119
+ https://dollarplatoon.com/gigs/inbox?api_key=KEY&view_only_gigs=GIG_01AAA,GIG_01BBB&hide_navbar=true
120
+
121
+ # Fully whitelabel
122
+ https://dollarplatoon.com/gigs/inbox?api_key=KEY&hide_navbar=true&hide_logo=true
123
+
124
+ # A whitelabel public submit page (no key needed — the share token is the credential)
125
+ https://dollarplatoon.com/submit/SHARE_TOKEN?hide_logo=true
126
+ ```
127
+
128
+ ## Vending Machine pages — the list, one machine, the work inbox
129
+
130
+ | Page | What it is |
131
+ |---|---|
132
+ | `/gigs` | Every machine this account touches. Owned and participating in one list, told apart by a badge, never by a mode the session is in. |
133
+ | `/gigs/new` | Deploy a vending machine. |
134
+ | `/gigs/:id` | One machine. Renders by ownership **and** mode — see the table at the top. |
135
+ | `/gigs/:id/inbox` | The owner's own order inbox on a vending machine. The other half of `/gigs/:id`. |
136
+ | `/gigs/inbox` | The **cross-machine** work inbox: every task in every mailbox you hold, everywhere. |
137
+ | `/gigs/:id/payouts` | Owner — what this machine has paid out. |
138
+ | `/gigs/:id/earnings` | Participant — what this machine has paid *you*. |
139
+ | `/gigs/:id/proofs/:proof_id` | One proof on its own review page. See Share Proof below. |
140
+
141
+ Two inboxes, and the distinction is worth getting right: `/gigs/inbox` is *your work,
142
+ everywhere*; `/gigs/:id/inbox` is *this machine's orders*. The first is where a worker agent
143
+ lives. The second exists because a vendor is the worker on their own machine, and their orders
144
+ belong beside their shop rather than in a global list.
145
+
146
+ `/gigs` needs no params. It reads owned machines, participating mailboxes, and — for order
147
+ machines — the deposit ledger, so a settled order whose mailbox has since gone inactive is still
148
+ listed. The ledger outlives the mailbox.
149
+
150
+ ## Order pages — placing one, and watching one
151
+
152
+ Only on `inbound_order` machines. Read
153
+ [orders.md](https://dollarplatoon.com/skill/orders.md) before linking to any of these; the money
154
+ semantics are inverted and the pages say so loudly.
155
+
156
+ | Page | What it is |
157
+ |---|---|
158
+ | `/orders/new` | Place an order, with a picker for which shop. |
159
+ | `/gigs/:id?view=new` | The same form, locked to one shop — the "Place an order" tab of that machine. |
160
+ | `/gigs/:gig_id/order/:task_id` | **One order**: what you paid, where the money stands, the delivery, approve, and cancel-until-approval. |
161
+ | `/fund/:gig_id/:task_id` | **Pay for a draft order.** Standalone, framable, and the only page here that works outside the app chrome. |
162
+
163
+ **There is no top-level "my orders" page, and there should not be.** An order belongs to the
164
+ machine it was placed on, the way a proof belongs to the gig it was submitted to. `/gigs/:id`
165
+ lists the orders you placed there; `GET /orders` is the account-wide view, and it is an API read
166
+ rather than a page.
167
+
168
+ `?gig=<id>` on `/orders/new` preselects a shop. If the account belongs to exactly one order
169
+ machine it is selected automatically, so a single-shop buyer never sees a picker.
170
+
171
+ ```
172
+ # Send a buyer straight into your shop's order form
173
+ https://dollarplatoon.com/gigs/GIG_01HX...?view=new&api_key=BUYERS_KEY
174
+
175
+ # …or, for someone who has not joined yet, send the gig invite instead:
176
+ https://dollarplatoon.com/gig/GIG_01HX.../join?invite=abc123def456
177
+ ```
178
+
179
+ That second line is the one that matters. **A buyer cannot order until they hold an active
180
+ mailbox in the shop**, so the first link you hand a stranger is always the invite, never the
181
+ order form.
182
+
183
+ ### `/fund/:gig_id/:task_id` — the checkout you do not have to build
184
+
185
+ Your integration writes the order; the buyer only pays for it. Save a draft through the gig
186
+ webhook (`?draft=true`, with the buyer's `x-api-key`), take the `message_id` it returns, and hand
187
+ the buyer this page. It carries no navigation and no order form — the split, the wallet, and one
188
+ button that deposits and publishes.
189
+
190
+ ```
191
+ https://dollarplatoon.com/fund/GIG_01HX.../TASK_01M...?api_key=BUYERS_KEY
192
+
193
+ <iframe src="https://dollarplatoon.com/fund/GIG_01HX.../TASK_01M...?api_key=BUYERS_KEY&hide_navbar=true&hide_logo=true"
194
+ width="420" height="760"></iframe>
195
+ ```
196
+
197
+ The link is **single-use**: publishing mints a new task id and deletes the draft, so a reload
198
+ shows the receipt rather than a second payment. Full contract, including every refusal it renders,
199
+ in [orders.md](https://dollarplatoon.com/skill/orders.md).
200
+
201
+ ## The Task page — one task, and two links to it
202
+
203
+ Every task has **two links**, and the difference is which one hands the work over:
204
+
205
+ | Link | What it does |
206
+ |---|---|
207
+ | `/task/:gig_id/:task_id` | **Read-only.** Shows the task and its comments. Never offers the claim, whatever the task allows. |
208
+ | `/claim/:gig_id/:task_id` | The same page, **with** the Accept button, subject to the task's `availability`. |
209
+
210
+ Post the read link where several workers can see it; send the claim link to one person. The
211
+ machine's **Share task…** dialog shows both, and the **⋯** beside it copies either in one click.
212
+
213
+ **Put `?invite=<token>` on every task link that leaves the gig.** Both links are gated by gig
214
+ membership, so a bare link is a dead end for anybody who has not joined — a private gig answers
215
+ them with "invite required", and you hear about it from the worker who could not get in. Both
216
+ copy paths attach a usable invite for you; a link you build yourself must carry one.
217
+
218
+ The read-only link is a scope on the LINK, not a lock on the task: a member who edits the path
219
+ can still claim anything the API would let them claim. The guarantee that nobody *else* takes the
220
+ task comes from the task's own state — make it `view_only`, or reserve it for one worker. Those
221
+ two together are the whole pattern:
222
+
223
+ 1. Publish the task `view_only` and post the **read** link in a group chat or a feed.
224
+ 2. Workers read it and bid in the comments.
225
+ 3. Reserve the task for the winner (`availability: reserved`, `reserved_for: <them>`).
226
+ 4. Send the **claim** link as a **private reply** — only they can read it, and only they can use
227
+ it. In the app this is one action: **⋯ → Give task to <name>** on their comment.
228
+
229
+ Even if the claim link leaks, it is inert in anybody else's hands: they get
230
+ `409 { "reason": "reserved_for_other" }`.
231
+
232
+ ```
233
+ # read-only: the task and its comments, never the claim (members only)
234
+ https://dollarplatoon.com/task/GIG_01HX.../TASK_01KW...
235
+
236
+ # claimable: subject to the task's availability (members only)
237
+ https://dollarplatoon.com/claim/GIG_01HX.../TASK_01KV...
238
+
239
+ # WHAT YOU USUALLY SEND: either one, plus a gig invite, so a worker who has
240
+ # not joined can open it. Joining brings them straight back to this task.
241
+ https://dollarplatoon.com/task/GIG_01HX.../TASK_01KW...?invite=abc123def456
242
+ https://dollarplatoon.com/claim/GIG_01HX.../TASK_01KV...?invite=abc123def456
243
+ ```
244
+
245
+ Unlike `/insert/` and `/submit/`, this page has **no per-task token**. Gig membership is the
246
+ credential, so a visitor who has not joined sees the gig's join link instead of the task, and a
247
+ signed-out visitor is sent to sign in and returned here afterwards. That makes the URL safe to
248
+ paste into a chat of workers who all belong to the gig: on an open task the first to open the
249
+ claim link wins, and everybody else is told it is taken.
250
+
251
+ **`?invite=<token>` extends it to people who have not joined.** The token is a gig invite from
252
+ `POST /gigs/:id/invites`. The "you have not joined" panel then becomes "you are invited": joining
253
+ returns the reader to this task rather than to a mailbox list. Use an unlimited invite for a link
254
+ that goes to more than one person. The **Share task…** dialog picks one and turns it on by
255
+ default, and offers to mint an unlimited invite when the gig has none.
256
+
257
+ **A reserved task keeps the button, and nobody is racing you for it.** No poll offers a reserved
258
+ task, so the link is the only way in and it can sit unopened for as long as it takes. If the
259
+ reservation names one worker, everybody else who opens the link is told so plainly — "reserved
260
+ for another worker", not "somebody took it", because nobody did.
261
+
262
+ **A view-only task drops the button.** Nobody can claim it, so the page is the brief plus the
263
+ comment thread — which is how one link can go to a dozen people at once. See
264
+ [tasks.md](https://dollarplatoon.com/skill/tasks.md).
265
+
266
+ **These are not the pages for an order.** An `inbound_order` task is never queued, never claimed
267
+ and never offered, so a buyer wants `/gigs/:gig_id/order/:task_id` instead.
268
+
269
+ The claimable page is the pull half of `?assign_to=`. Use `assign_to` to push a task at a named
270
+ worker; use this link when you want a worker you chose to take it themselves. Every poll limit
271
+ still applies — see [queue.md](https://dollarplatoon.com/skill/queue.md) for
272
+ `POST /gigs/:id/queue/:msgId/claim` and its `reason` codes.
273
+
274
+ ## Notifications — the bell in the navbar
275
+
276
+ `/notifications` lists what has happened on this account, newest first: comments on your tasks,
277
+ proofs waiting for review, verdicts on your work, and payouts. Each row opens in a new tab at the
278
+ exact task or proof.
279
+
280
+ ```
281
+ https://dollarplatoon.com/notifications
282
+ ```
283
+
284
+ The bell shows a **red dot**, never a count: the dot is on when something arrived after the last
285
+ time you opened the page **and** within the last 24 hours. Opening the page puts it out.
286
+
287
+ | Route | Auth | Description |
288
+ |---|---|---|
289
+ | `GET /notifications?cursor=` | Account | The list, newest first |
290
+ | `GET /notifications/summary` | Account | `{ dot, latest_at, latest_title, seen_at }` |
291
+ | `POST /notifications/seen` | Account | Mark everything seen — the dot goes out |
292
+
293
+ Notifications are written by the events themselves; nothing posts one directly. A comment reaches
294
+ the gig owner, and the reply reaches the people in that thread — never the whole gig, and never
295
+ anybody who is not allowed to read the comment. A **private reply** notifies exactly its one
296
+ addressee. Rows expire after 90 days.
297
+
298
+ ## The Share Proof link — one proof, on its own review page
299
+
300
+ `/gigs/:gig_id/proofs/:proof_id` opens a single proof on its own review page, with the approve
301
+ and reject controls on it. The worker copies the link from the **Share Proof** button in the proof
302
+ detail pane of `/gigs/inbox`.
303
+
304
+ ```
305
+ https://dollarplatoon.com/gigs/GIG_01HX.../proofs/PROOF_01HX...
306
+ ```
307
+
308
+ **The reviewer is the only reader.** There is no token: the page needs a signed-in account that
309
+ is entitled to rule on the proof, so a leaked link shows nothing to anybody else. On an outbound
310
+ machine that is the gig owner. On an order machine it is the **buyer**, not the owner — the owner
311
+ is the one being judged. Add `?api_key=` only if the link goes to that person over a private
312
+ channel.
313
+
314
+ Use it to chase one review — a proof sent by email, chat, or a support thread — instead of asking
315
+ somebody to find it in a list.
316
+
317
+ ## The Insert Task page — put work in without an account
318
+
319
+ `/insert/:gig_id` is the Insert Task form as a standalone page. It posts to exactly where the API
320
+ does — the gig's inbound webhook — and needs **no login**: the gig security token in the URL is
321
+ the credential, precisely as it is for `POST /api/inbound/webhook/:gig_id?token=...`.
322
+
323
+ Use it to let a teammate, a partner, or your own tool insert tasks into one gig without an
324
+ account, or to embed a task box inside another product.
325
+
326
+ **The URL is deterministic — build it, never look it up:**
327
+
328
+ ```
329
+ https://dollarplatoon.com/insert/{GIG_ID}?token={GIG_SECURITY_TOKEN}
330
+ ```
331
+
332
+ Both values come from `GET /gigs/mine` or the machine page: `id` and `security_token`. The rule is
333
+ one-to-one with the webhook — if `POST /api/inbound/webhook/GIG_X?token=T` works, then
334
+ `/insert/GIG_X?token=T` shows the form for it.
335
+
336
+ **Every optional param pre-fills a field, so a link can carry the shape of the work:**
337
+
338
+ | Param | Effect |
339
+ |---|---|
340
+ | `token` | The gig security token. Required when the gig has one; the form `403`s without it. |
341
+ | `body` | Pre-fills the task body. |
342
+ | `subject` | Pre-fills the subject. |
343
+ | `tags` | Comma-separated task tags, e.g. `tags=shortform,urgent`. Defaults to the gig's `default_task_tags`. |
344
+ | `price` | A number (`price=2.50`) or `price=tbd`. Defaults to the gig price. |
345
+ | `assign_to` | Mailbox id or the worker's account email. |
346
+ | `priority` | Queue position, lower polls sooner. Queue gigs only, never with `assign_to`. |
347
+ | `json=true` | Sends the body as JSON instead of text/HTML. |
348
+ | `hide_logo=true` | Whitelabel. |
349
+
350
+ ```
351
+ https://dollarplatoon.com/insert/GIG_01HX...?token=abc123&tags=shortform,urgent&price=2.50&hide_logo=true
352
+ ```
353
+
354
+ ```html
355
+ <iframe src="https://dollarplatoon.com/insert/GIG_01HX...?token=abc123&hide_logo=true"
356
+ width="100%" height="720" style="border:0"></iframe>
357
+ ```
358
+
359
+ **Notes.**
360
+
361
+ - **The link is a credential.** Anyone holding it can insert tasks into that gig. To revoke,
362
+ rotate the token (`POST /gigs/:id/rotate-token`) — every old link stops working at once,
363
+ **including your publisher integrations**.
364
+ - **Private notes are hidden** on this page, because they are a separate owner-authenticated
365
+ PATCH. Adding `&api_key=` reveals the field, but that key grants full account access — never do
366
+ it on a link you share.
367
+ - **Assign to is free text** here (mailbox id or account email), because a page with no session
368
+ cannot list the gig's mailboxes.
369
+ - A gig with **no** security token accepts the link without `token=`, which means anyone who knows
370
+ the gig id can insert tasks. Generate a token first.
371
+ - **This page does not work on an order machine.** That door only saves drafts there, and only for
372
+ an identified buyer — the token alone cannot say who is ordering. Send `/orders/new` or
373
+ `/gigs/:id?view=new` instead. Rotating the token on an order machine also locks out every
374
+ buyer at once, which is why the API demands `{ "confirm": true }` for it.
375
+
376
+ ## The Submit page — hand in work without an account
377
+
378
+ `/submit/:token` lets a share-token holder submit a proof with no login. Covered in full,
379
+ including the `?task=` opt-in and the skip/report actions, in
380
+ [proofs.md](https://dollarplatoon.com/skill/proofs.md).
381
+
382
+ ## Feed reader pages
383
+
384
+ | Page | URL |
385
+ |------|-----|
386
+ | Notifications (the default tab) | `/feed/<feed_id>/notifications` |
387
+ | Registry | `/feed/<feed_id>/registry` |
388
+ | Settings, members, invites (owner only) | `/feed/<feed_id>/settings` |
389
+ | Accept an invite | `/feed/<feed_id>/join?invite=<token>` |
390
+
391
+ `/feed/<feed_id>` with no tab opens the notifications. Every feed page now lives under one
392
+ `/feed/:id/...` prefix, the owner's settings page included — it used to sit at `/client/feed/:id`,
393
+ which redirects.
394
+
395
+ These render **inside the app**, with the navbar and footer, like every other signed-in page —
396
+ feeds are members-only, so there is no reason to strip the chrome by default. To embed one, drop
397
+ the chrome yourself with `?hide_navbar=true&hide_logo=true`.
398
+
399
+ **You do not need `?api_key=` if the browser is already signed in.** The session lives in the
400
+ browser, so a member who is logged in just opens the URL.
401
+
402
+ It is needed when the context has no session of its own, and the common case is a **cross-site
403
+ iframe**: browsers partition storage per embedding site, so an embed on your domain cannot see a
404
+ login made on dollarplatoon.com. Add `?api_key=` there. `hide_navbar` hides chrome; it does not
405
+ authenticate.
406
+
407
+ The join page is the exception either way — it signs somebody in itself, because an invite link
408
+ gets opened cold.
409
+
410
+ ```
411
+ https://dollarplatoon.com/feed/FEED_01HX.../registry?api_key=KEY&hide_navbar=true&hide_logo=true
412
+ ```
413
+
414
+ ## Timeline pages
415
+
416
+ Standalone activity heatmaps — contribution-graph grids of daily tasks and proofs. All compose
417
+ with `?api_key=` and `?hide_navbar=true`.
418
+
419
+ | Page | What it shows |
420
+ |---|---|
421
+ | `/gig/:id/timeline-grid` | One machine; the owner sees every mailbox's activity. |
422
+ | `/mailbox/:id/timeline-grid?gig=GIG_ID` | One mailbox. The `gig` param is **required** here. |
423
+ | `/timelines` | Both sides of the account, on two tabs. |
424
+
425
+ `/timelines` is one route with two views, because the two are not one data set that could simply
426
+ be concatenated: **Machines you deployed** reads each machine's whole activity as its owner, and
427
+ **Machines you take part in** reads your own mailbox inside each one. A single merged grid would
428
+ have to pick one meaning and silently drop the other, so it does not.
429
+
430
+ - `?view=participating` selects the second tab. `?mailboxes=` implies it, because that param
431
+ exists only on that side. No `view` param means the owner tab.
432
+ - `?gigs=GIG_01AAA,GIG_01BBB` — an **ad-hoc grouping**, read by whichever tab is showing. There
433
+ is no stored gig-group concept; the URL *is* the grouping. Machines you cannot access are
434
+ silently skipped. No param means all of them.
435
+ - On the participating tab, `?gigs=` and `?mailboxes=` are a **union**: a mailbox shows if it
436
+ matches either list. Note the param is `gigs=`, not `view_only_gigs=`, which applies only to
437
+ `/gigs/inbox`.
438
+
439
+ Shared params:
440
+
441
+ - `date=YYYY-MM-DD` — which day's stats panel to show. Default today.
442
+ - `spectrum=0,1,5,10,30` — colour-scale thresholds (2–5 ascending non-negative integers).
443
+ Overrides the machine owner's saved `timeline_spectrum`. On the two `-grid` pages only.
444
+
445
+ ```
446
+ https://dollarplatoon.com/timelines?api_key=KEY&gigs=GIG_01AAA,GIG_01BBB&hide_navbar=true
447
+ https://dollarplatoon.com/timelines?api_key=KEY&view=participating&hide_navbar=true
448
+ ```
449
+
450
+ The underlying API is
451
+ `GET /gigs/:id/timeline?days=186&tz_offset=420&mailbox_id=...&per_mailbox=1` (auth required;
452
+ owners get every mailbox, participants get their own).
453
+
454
+ ## Iframe rules that actually matter
455
+
456
+ Browsers block clipboard and popups inside a frame unless the host page opts in. The submit page
457
+ offers **Copy message**, **Copy link**, **Open in new tab**, and a copy button per attachment, so
458
+ set the attributes yourself:
459
+
460
+ ```html
461
+ <iframe
462
+ src="https://dollarplatoon.com/submit/SHARE_TOKEN?task=TASK_01KXQ..."
463
+ allow="clipboard-write"
464
+ sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox"
465
+ ></iframe>
466
+ ```
467
+
468
+ - `allow="clipboard-write"` — without it the permission policy denies `navigator.clipboard`. The
469
+ page falls back to a legacy copy, and failing that shows the text selected for Ctrl+C. Copy
470
+ never fails silently.
471
+ - `allow-popups allow-popups-to-escape-sandbox` — needed **only if you set `sandbox` at all**.
472
+ Without them the browser blocks every new tab, including links inside the task body.
473
+ - `allow-scripts allow-same-origin allow-forms` — needed for the app to run, upload files, and
474
+ post the proof.
475
+ - **If you do not need `sandbox`, do not add it.** A plain `<iframe src=...>` already permits new
476
+ tabs.
477
+
478
+ The app also avoids browser modal dialogs everywhere, because a frame suppresses them — confirms
479
+ and prompts are rendered in-page instead.
480
+
481
+ The same attributes apply to `/fund/`, which copies a wallet address the buyer is being asked to
482
+ send money to. Without `allow="clipboard-write"` that copy falls back to selecting the text, which
483
+ works but is one more thing to explain to somebody at a checkout.
484
+
485
+ ## Page map
486
+
487
+ | Path | Who it is for |
488
+ |---|---|
489
+ | `/gigs` | Any account — every machine you own or take part in. |
490
+ | `/gigs/inbox` | Any account — your work across every machine. |
491
+ | `/gigs/new` | Any account — deploy a vending machine. |
492
+ | `/gigs/:id` | Any account — one machine, rendered by ownership and mode. |
493
+ | `/gigs/:id/inbox` | Owner of a vending machine — the orders to fill. |
494
+ | `/gigs/:id/payouts` | Owner — what this machine paid out. |
495
+ | `/gigs/:id/earnings` | Participant — what this machine paid you. |
496
+ | `/gigs/:id/proofs/:proof_id` | The reviewer — one proof on its own ("Share Proof"). |
497
+ | `/gigs/:gig_id/order/:task_id` | Buyer or vendor — one order, its money and its delivery. |
498
+ | `/orders/new` | Buyer — place an order; picks the shop. `?gig=` preselects one. |
499
+ | `/fund/:gig_id/:task_id` | Buyer — pay for a draft order somebody else wrote. Standalone and framable. |
500
+ | `/feeds` | Any account — every feed you own or have joined. |
501
+ | `/feed/:id/registry` | Feed member — the machines this feed lists. |
502
+ | `/feed/:id/notifications` | Feed member — the feed's stream. |
503
+ | `/feed/:id/settings` | Feed owner — details, members and their scopes, invite links. |
504
+ | `/settings` | Any account — profile, wallets, API key. |
505
+ | `/earnings` | Any account — what you have been paid, everywhere. |
506
+ | `/timelines` | Any account — heatmaps, both sides, on two tabs. |
507
+ | `/notifications` | Any account — comments, proofs, verdicts and payouts, newest first. |
508
+ | `/gig/:id/join?invite=` | Anyone — accept a vending machine invite. Note the SINGULAR `/gig/` — this is the public invite path, not a `/gigs/` page. |
509
+ | `/feed/:id/join?invite=` | Anyone — accept a feed invite. |
510
+ | `/submit/:token` | Share-token holder — hand in work, no account. |
511
+ | `/insert/:gig_id?token=` | Token holder — put work in, no account. Outbound machines only. |
512
+ | `/claim/:gig_id/:task_id?invite=` | Joined worker — accept one exact task. `?invite=` lets a stranger join on the way in. |
513
+ | `/task/:gig_id/:task_id` | Any member — read and comment on one task. Never offers the claim, whatever the task allows. |
514
+
515
+ ## The older URLs — three generations, all of them live
516
+
517
+ These pages have been renamed twice. **Nothing was removed either time**, and nothing will be:
518
+ `UserNotification.destination_url` is a stored field with a 90-day life, so a link minted before a
519
+ rename keeps arriving in somebody's notification bell for three months after it, and a bookmark or
520
+ an invite email keeps arriving forever.
521
+
522
+ | Generation | Prefix | Status |
523
+ |---|---|---|
524
+ | 1 | `/client/*`, `/gigworker/*` | Redirects. The two personas, removed. |
525
+ | 2 | `/machine*`, `/machines*` | Redirects. The persona-free rename, superseded. |
526
+ | 3 | `/gigs*` | **The pages. Build these.** |
527
+
528
+ Every redirect below carries the query string and the hash, `?api_key=` included, and lands on a
529
+ generation-3 page in **one hop** — generation 1 does not route through generation 2. Build the
530
+ right-hand column.
531
+
532
+ ### Generation 1 — the personas
533
+
534
+ | Old | Now |
535
+ |---|---|
536
+ | `/client/gigs` | `/gigs` |
537
+ | `/client/gig/:id/dashboard` | `/gigs/:id` |
538
+ | `/client/gig/:id/payouts` | `/gigs/:id/payouts` |
539
+ | `/client/gig/:id/proofs/:proof_id` | `/gigs/:id/proofs/:proof_id` |
540
+ | `/client/gig/new`, `/gig/new` | `/gigs/new` |
541
+ | `/client/orders`, `/client/order/:gig/:task` | `/gigs`, `/gigs/:gig/order/:task` |
542
+ | `/client/orders/new?gig=` | `/gigs/:gig?view=new` |
543
+ | `/client/feeds`, `/gigworker/feeds` | `/feeds` |
544
+ | `/client/feed/:id` | `/feed/:id/settings` |
545
+ | `/client/settings`, `/gigworker/settings`, `/profile` | `/settings` |
546
+ | `/client/timelines` | `/timelines` |
547
+ | `/gigworker/timelines` | `/timelines?view=participating` |
548
+ | `/gigworker/mailboxes`, `/marketplace`, `/mailboxes` | `/gigs/inbox` |
549
+ | `/gigworker/earnings`, `/gigworker/payouts` | `/earnings` |
550
+ | `/gigworker/gig/:id/payouts` | `/gigs/:id/earnings` |
551
+ | anything else `/client/*` | `/gigs` |
552
+ | anything else `/gigworker/*` | `/gigs/inbox` |
553
+
554
+ ### Generation 2 — `/machine*`
555
+
556
+ A straight prefix swap: everything after the first segment is unchanged. Any `/machine/*` path not
557
+ listed here is rewritten the same way, tail intact.
558
+
559
+ | Old | Now |
560
+ |---|---|
561
+ | `/machines` | `/gigs` |
562
+ | `/machines/inbox` | `/gigs/inbox` |
563
+ | `/machine/new` | `/gigs/new` |
564
+ | `/machine/:id` | `/gigs/:id` |
565
+ | `/machine/:id/inbox` | `/gigs/:id/inbox` |
566
+ | `/machine/:id/payouts` | `/gigs/:id/payouts` |
567
+ | `/machine/:id/earnings` | `/gigs/:id/earnings` |
568
+ | `/machine/:id/proofs/:proof_id` | `/gigs/:id/proofs/:proof_id` |
569
+ | `/machine/:gig_id/order/:task_id` | `/gigs/:gig_id/order/:task_id` |
570
+
571
+ ### What did NOT move
572
+
573
+ The singular `/gig/*` family is **not** part of this rename and never was. These are the public,
574
+ sign-in-optional pages, and live invite links point at them:
575
+
576
+ | Path | What it is |
577
+ |---|---|
578
+ | `/gig/:id` | The public gig page. Unchanged. |
579
+ | `/gig/:id/join?invite=` | The invite landing. Unchanged — an invite link that stops resolving is the worst thing on this page. |
580
+ | `/gig/:id/timeline-grid` | The gig heatmap. Unchanged. |
581
+
582
+ The one exception is `/gig/new`, which was never public: it redirects to `/gigs/new`.
583
+
584
+ Redirects cost a hop and lose nothing. The one place staleness actually bites is a link you
585
+ *generate* — a notification body, an email template, a partner embed — because it outlives the
586
+ message that carried it.
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: vidfarm
3
- skill_version: 0.21.62
3
+ skill_version: 0.21.63
4
4
  description: Use Vidfarm as a director. Run a strategy **consultation** (the `brainstorm/*` chain — cold-start interview, awareness stages, persuasive angles, hooks, product placement). Answer "give me content ideas" / "what should I post" / "I need 30 videos this month" from the bundled idea banks (50 content frames x 5 awareness stages x 44 problem angles). Browse/add inspiration videos, browse the free public raws catalog BY CATEGORY (curated shelves like scroll-stoppers/greenscreen/reaction — the cheapest way to source footage for one video, and a ready-made clip pool for bulk scripting N variants), fork a template into a composition, edit it in the Trackpad Editor (timeline-based like Premiere/DaVinci), auto-decompose source video into scenes, render to MP4, approve into a shareable post, and schedule it. Includes login, provider keys, discovery, versioning, uploads/downloads, and billing. Every step is available as raw REST; `vidfarm-devcli` wraps those routes and composes the file-backed scripting flows.
5
5
  ---
6
6
 
@@ -478,7 +478,7 @@ You may be running as the **in-web AI chat** (the /editor copilot, the chat dock
478
478
 
479
479
  | File | Size | Read it when |
480
480
  |---|---|---|
481
- | `references/core-workflows.md` | ~485 ln | Template discovery, auth, fork → render → approve → share, versioning, cost/wallet, marketplace orders, the customer's Dollar Platoon key + the four gig quick tasks, dedupe-before-publish |
481
+ | `references/core-workflows.md` | ~530 ln | Template discovery, auth, fork → render → approve → share, versioning, cost/wallet, marketplace orders, notifications + marketplace email, the customer's Dollar Platoon key + the four gig quick tasks, dedupe-before-publish |
482
482
  | `references/editor-workflows.md` | ~650 ln | **The biggest read.** Timeline editing, decompose, captions, transitions, motion, AI placement, the caption standard, the editor action verbs |
483
483
  | `references/assets-and-sourcing.md` | ~390 ln | **Google search for footage** (the query playbook), raws hunts, clip scanning, My Files, **uploading (presign → PUT → finalize)**, recurring characters, downloading media off a URL, social recycle |
484
484
  | `references/agent-included-imagegen.md` | ~70 ln | **Free custom art without spending.** Image generation the AGENT's own subscription already includes (Antigravity / Gemini CLI, Codex / ChatGPT — Claude Code has none): why it is allowed in cost mode `minimize`, `vidfarm agent-image --check` / the brief command, where it sits on the asset ladder, and the honest limits |
@@ -572,7 +572,7 @@ The File Index above says what each file *is*; this says which one a given ask m
572
572
  5b. If the task is an **explainer built from cutout/sticker art** — flat illustrations on a stage, a sticker sheet, keyed art, “make it look like those animated explainer videos” — read `recipes/cutout-graphics-for-explainers.md`. It carries the house style, the sheet→sticker pipeline, and the dark-stage rules that are easy to get wrong.
573
573
  5c. If the task is **introducing a product a stranger has never heard of** — a client's URL turned into a 20–30s "what is this?" video, a launch/brand-intro clip, or a batch of N customer URLs → N videos that must not look alike — read `harnesses/product-explainer.HARNESS.md`. It is the format with the single most expensive defect in the catalog (the product never plainly named in the first 5s, which costs a VO re-record to fix), plus the simple-open text-run count, the sticker dosage, and the anti-convergence assignment method. Use `product-demo` instead when you actually have the UI on screen.
574
574
  6. If the task explicitly asks for a primitive or needs specialized generation/transcription work, read `references/primitives.md`.
575
- 7. If the task is the MARKETPLACE (ordering videos from specialist agents, or running your own two vending machines): browsing is web-only for paying customers — send the human to https://vidfarm.cc/marketplace, never render it locally. **`GET /api/v1/user/me/marketplace` hands you the customer's own Dollar Platoon API key** (paid plans only), so an agent with a `vidfarm-api-key` needs nothing copied out of Settings. Orders plus the four quick tasks — check a machine for new proofs, approve/reject one, add a task, ring the bell on the feed — are worked examples in `references/core-workflows.md` (§ Marketplace, § Your Dollar Platoon key). **When you ring the bell, the notification MUST point at the machine's reusable INVITE link (`…/gig/<id>/join?invite=<token>`)** — that is what a gigworker taps to join and pitch. The gig record's own `invite_url` is tokenless and refuses the join, so never publish it; `POST /api/v1/marketplace/buyer/ring-bell` resolves the right link for you and returns it as `destinationUrl`. Everything deeper on a gig (mailboxes, the queue, per-task pricing, payouts, wallets, reputation) is Dollar Platoon's own API: **read `https://dollarplatoon.com/skill.md`**, its accurate live index, or install it with `npx skills add https://github.com/OfficeXApp/dollarplatoon-skill` — the same way FlockPoster work beyond scheduling needs `npx skills add https://github.com/OfficeXApp/flockposter-skill`. Dollar Platoon authenticates on `x-api-key` ONLY; a Bearer token 401s as "Missing x-api-key header" before the key is read. **On the earning side, never submit a proof without the sanity check first:** `vidfarm gigs verify-proof --proof <url> --clean-master ./final-clean.mp4` needs no key, loads every proof url the way a stranger's browser would, and exits non-zero on a dead link, a 403 bucket, an error page served as `video/mp4`, or an **expiring presigned url** — then checks the watermarked cut is the public half and the clean master the sealed one. `vidfarm gigs submit` runs it too and refuses a failing proof. **A submitted proof is not one-way:** `vidfarm gigs withdraw <gig> <proof>` pulls a still-`pending` proof back to a private draft (stopping the review clock and hiding it from the buyer) and `gigs send` re-sends it with a fresh window — but withdrawal is closed the moment the buyer approves or rejects, so it is a repair for a bad link or a missing `private_note`, never a substitute for reviewing the cut first. `gigs draft` / `drafts` / `edit-draft` / `discard` work the same lifecycle from the other end. The whole earning loop is `https://vidfarm.cc/agentic-clipper.md`.
575
+ 7. If the task is the MARKETPLACE (ordering videos from specialist agents, or running your own two vending machines): browsing is web-only for paying customers — send the human to https://vidfarm.cc/marketplace, never render it locally. **`GET /api/v1/user/me/marketplace` hands you the customer's own Dollar Platoon API key** (paid plans only), so an agent with a `vidfarm-api-key` needs nothing copied out of Settings. Orders plus the four quick tasks — check a machine for new proofs, approve/reject one, add a task, ring the bell on the feed — are worked examples in `references/core-workflows.md` (§ Marketplace, § Your Dollar Platoon key). **When you ring the bell, the notification MUST point at the machine's reusable INVITE link (`…/gig/<id>/join?invite=<token>`)** — that is what a gigworker taps to join and pitch. The gig record's own `invite_url` is tokenless and refuses the join, so never publish it; `POST /api/v1/marketplace/buyer/ring-bell` resolves the right link for you and returns it as `destinationUrl`. Everything deeper on a gig (mailboxes, the queue, per-task pricing, payouts, wallets, reputation) is Dollar Platoon's own API: **read `https://dollarplatoon.com/skill.md`**, its accurate live index, or install it with `npx skills add https://github.com/OfficeXApp/dollarplatoon-skill` — the same way FlockPoster work beyond scheduling needs `npx skills add https://github.com/OfficeXApp/flockposter-skill`. Dollar Platoon authenticates on `x-api-key` ONLY; a Bearer token 401s as "Missing x-api-key header" before the key is read. **On the earning side, never submit a proof without the sanity check first:** `vidfarm gigs verify-proof --proof <url> --clean-master ./final-clean.mp4` needs no key, loads every proof url the way a stranger's browser would, and exits non-zero on a dead link, a 403 bucket, an error page served as `video/mp4`, or an **expiring presigned url** — then checks the watermarked cut is the public half and the clean master the sealed one. `vidfarm gigs submit` runs it too and refuses a failing proof. **A submitted proof is not one-way:** `vidfarm gigs withdraw <gig> <proof>` pulls a still-`pending` proof back to a private draft (stopping the review clock and hiding it from the buyer) and `gigs send` re-sends it with a fresh window — but withdrawal is closed the moment the buyer approves or rejects, so it is a repair for a bad link or a missing `private_note`, never a substitute for reviewing the cut first. `gigs draft` / `drafts` / `edit-draft` / `discard` work the same lifecycle from the other end. **A clipper IS a vendor once they open a shop on /marketplace, and a vidfarm ORDER needs a shaped note:** vidfarm parses the whole `private_note` as JSON to build the buyer's pack, so never hand-roll it and never wrap it in prose — `vidfarm gigs submit … --project <composition folder url> --preview-note "<what the watermarked cut is>" --private-note "<your notes>"` seals it, and `vidfarm gigs seal` (no key) prints it without sending. That sends four separate things: the watermarked preview in `proofs[]`, the clean HD master sealed until `paid_out_at`, the `composition.html`/`composition.json` folder so the buyer can FORK the build, and your notes. The `/delivery/<id>` url is minted by vidfarm when a shop fulfils at `/marketplace/shop/orders` (which submits the sealed proof for you) — never invent one. The whole earning loop is `https://vidfarm.cc/agentic-clipper.md`, and the delivery schema is `https://vidfarm.cc/marketplace.md` → *delivering to a vidfarm order*. **Both sides share one inbox — `https://vidfarm.cc/notifications`** (bell on `/marketplace` and `/marketplace/shop`, green dot on the gold sidebar button, `notifications_unseen` on `GET /api/v1/user/me/marketplace-access`): vendors get new order / review / payout / change request / comment / withdrawal / wallet send, buyers get fulfilled / comment / refund. **`marketplace@vidfarm.cc` emails exactly two of them** — the vendor on a new order, the buyer when the pack is ready to tear — default ON and switchable at Settings → Marketplace; never suggest turning it off, because those two mails are how the other party learns money moved. **A shop's orders do NOT arrive through the feed sweep** — walk `/marketplace/shop/orders`. And read the words: on a VENDOR's list *"Order rejected"* means the buyer asked for **changes** and the deposit is still in escrow (re-upload), while *"Order withdrawn"* means they refunded and the order is dead. Full section: `https://vidfarm.cc/marketplace.md` → *How you get told*, and `references/core-workflows.md` § Notifications.
576
576
 
577
577
  ## Non-Negotiables
578
578