@officexapp/vidfarm-devcli 0.21.61 → 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 (29) 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 +28 -3
  29. package/public/assets/homepage-client-app.js +13 -13
@@ -0,0 +1,395 @@
1
+ # Gigs, invites, and mailboxes
2
+
3
+ The gig (vending machine) itself, the invite links that gate it, and the mailboxes that are a
4
+ worker's place inside it.
5
+
6
+ ## Contents
7
+
8
+ - Gig routes
9
+ - Create a gig
10
+ - Read and update a gig
11
+ - Invite links
12
+ - Security token
13
+ - Worker rate limits
14
+ - Task expiry
15
+ - Funding
16
+ - The dashboard
17
+ - Mailbox routes
18
+ - Join a gig
19
+ - Update a mailbox
20
+ - List your mailboxes
21
+ - Reading a mailbox's tasks
22
+
23
+ ---
24
+
25
+ ## Gig routes
26
+
27
+ | Method | Path | Auth | Description |
28
+ |--------|------|------|-------------|
29
+ | POST | `/gigs` | Yes | Create a gig |
30
+ | GET | `/gigs/mine` | Yes | Your owned gigs (`?tag=` substring filter) |
31
+ | GET | `/gigs/:id` | Optional | Gig detail |
32
+ | PATCH | `/gigs/:id` | Owner | Update |
33
+ | POST | `/gigs/:id/invites` | Owner | Mint an invite link |
34
+ | GET | `/gigs/:id/invites` | Owner | List invite links |
35
+ | DELETE | `/gigs/:id/invites/:token` | Owner | Revoke an invite link |
36
+ | POST | `/gigs/:id/rotate-token` | Owner | Rotate the security token |
37
+ | POST | `/gigs/:id/deposit` | Yes | Deposit USDC into the gig |
38
+ | GET | `/gigs/:id/dashboard` | Owner | Everything about the gig in one call |
39
+ | GET | `/gigs/:id/feeds` | Owner | Which feeds list this gig |
40
+ | POST | `/gigs/:id/tasks/:msgId/extend` | Owner | Reset a task's expiry clock |
41
+ | POST | `/gigs/:id/tasks/:msgId/recycle` | Owner | Take a task back and redistribute it |
42
+
43
+ `GET /gigs` returns `410 Gone`. There is no public marketplace — every gig is a private network
44
+ reached by invite.
45
+
46
+ ## Create a gig
47
+
48
+ ```json
49
+ POST /gigs
50
+ {
51
+ "title": "Reddit Comments for Product Launch",
52
+ "price": 0.50,
53
+ "terms": "Comment genuinely on the linked threads. Tags in use: reddit, urgent.",
54
+ "notes": "Internal notes, owner only",
55
+ "owner_wallet": "wallet_alias_id", // optional — auto-provisions a hot wallet if omitted
56
+ "join_policy": "invite", // "invite" (default) | "open"
57
+ "tags": ["reddit", "q3-launch"], // free-form, max 25 tags of 256 chars
58
+ "requires_approval": false,
59
+ "review_timeout": 172800, // seconds before an unreviewed proof auto-approves
60
+ "task_timeout": 86400, // seconds a worker may hold a task; null = never expires
61
+ "distribution": "queue", // see tasks.md for all eight modes
62
+ "queue_order": "fifo", // queue modes only: fifo | lifo | priority | random
63
+ "max_claims_per_task": 3, // queue_solo only; null = unlimited
64
+ "default_task_tags": ["shortform"], // stamped on tasks that arrive untagged
65
+ "default_rate_limit_count": 5, // worker throttle; both fields or neither
66
+ "default_rate_limit_minutes": 60,
67
+ "default_max_open_tasks": 3, // tasks one worker may hold unproven; null = unlimited
68
+ "allow_price_offers": false, // let workers quote their own price per proof
69
+ "task_escrow": false, // fund each task on chain as it is created — see tasks.md
70
+ "min_payout": 0,
71
+ "location": { "country": "US", "label": "United States" },
72
+ "icon_url": "https://...",
73
+ "proof_webhook_url": "https://...", // POSTed each proof submission
74
+ "join_webhook_url": "https://...", // POSTed a mailbox.joined event
75
+ "contract_address": "0x..."
76
+ }
77
+ ```
78
+
79
+ ```json
80
+ → {
81
+ "gig": {
82
+ "id": "GIG_01HX...",
83
+ "email": "GIG_01HX..._abc123.dollar-platoon@fwd.zoomgtm.com",
84
+ "webhook": "https://dollarplatoon.com/api/inbound/webhook/GIG_01HX...?token=abc123",
85
+ "invite_url": "https://dollarplatoon.com/gig/GIG_01HX.../join?invite=a1b2c3d4e5f6",
86
+ "join_policy": "invite", "price": 0.50, "status": "active"
87
+ }
88
+ }
89
+ ```
90
+
91
+ Creation runs a compliance check that blocks illegal content and warns on borderline content.
92
+
93
+ **`distribution: "inbound_order"` takes a different body.** Omit `price` — it is pinned to 0 —
94
+ and send `list_price` instead (minimum $0.02). `review_timeout` must be a positive number of at
95
+ least 3600 seconds; `-1` is refused. `price_tbd`, `allow_price_offers`, a non-null `task_timeout`
96
+ and a non-zero `min_payout` are all rejected at the door rather than quietly ignored. The response
97
+ adds `vendor_mailbox_id` — your own mailbox in your own shop, because there you are the worker
98
+ too. See [orders.md](https://dollarplatoon.com/skill/orders.md).
99
+
100
+ Tags are arbitrary — there is no whitelist. Use them to group gigs by campaign, client, or batch,
101
+ then filter with `GET /gigs/mine?tag=q3` (case-insensitive substring, comma-separated values
102
+ OR'd).
103
+
104
+ ## Read and update a gig
105
+
106
+ `GET /gigs/:id` returns the gig. An owner or member also sees `notes` and enriched fields. It
107
+ always shows `available_funds` and `reserved_funds`, which is how a worker judges whether the gig
108
+ can actually pay.
109
+
110
+ `PATCH /gigs/:id` accepts any subset of: `title`, `price`, `terms`, `status`, `review_timeout`,
111
+ `task_timeout`, `tags`, `default_task_tags`, `join_policy`, `distribution`, `requires_approval`,
112
+ `min_payout`, `location`, `notes`, `proof_webhook_url`, `join_webhook_url`, `contract_address`,
113
+ `default_rate_limit_count`, `default_rate_limit_minutes`, `default_max_open_tasks`,
114
+ `allow_price_offers`. `tags` replaces the whole list.
115
+
116
+ `allow_price_offers` lets a worker send `asking_price` with a proof. The ask is a quote: it never
117
+ becomes the payout unless you approve at that amount, and a review that times out still pays the
118
+ gig price. See [proofs.md](https://dollarplatoon.com/skill/proofs.md).
119
+
120
+ **An order machine adds three fields to `GET /gigs/:id` and moves one on PATCH.**
121
+ `list_price` is public — a buyer is entitled to see the sticker before joining. `fee_bps` is the
122
+ live Treasury rate, present even when its value is `null`, which means *"could not be read"* and
123
+ must never be replaced with a constant. `escrowed_funds` goes to the owner and members only, and
124
+ is how much of `available_funds` is customers' escrow rather than the vendor's takings; `null`
125
+ there means "not synced", not "zero". On PATCH, `list_price` moves and `price` answers `409` —
126
+ along with `distribution`, `contract_address`, `min_payout`, `task_timeout` and a `review_timeout`
127
+ of `-1`.
128
+
129
+ ## Invite links
130
+
131
+ Invite links gate who joins the private network. Two fields give you every mode:
132
+
133
+ - `max_uses` — `1` for one person, `N` for a cohort, `null` for unlimited.
134
+ - `email` — bind to one exact address, or `null` for anyone with the link.
135
+
136
+ ```json
137
+ POST /gigs/:id/invites { "max_uses": 1, "email": "worker@example.com", "label": "for Alice" }
138
+ → { "invite": { "token": "a1b2c3d4e5f6", "max_uses": 1, "uses": 0,
139
+ "invite_url": "https://dollarplatoon.com/gig/GIG_01HX.../join?invite=a1b2c3d4e5f6" } }
140
+ ```
141
+
142
+ An **email-bound invite is a pre-approval**: that worker skips `pending_approval` even when the
143
+ gig sets `requires_approval`. You named them, so the gate does not apply.
144
+
145
+ `GET /gigs/:id/invites` lists every invite with `uses`, `revoked`, and `exhausted`.
146
+ `DELETE /gigs/:id/invites/:token` revokes one. Use consumption is atomic, so concurrent joins
147
+ cannot race past `max_uses`.
148
+
149
+ ## Security token
150
+
151
+ Every gig has a 6-character token embedded in its inbound email address and webhook URL. It stops
152
+ anyone who guesses a gig id from injecting tasks.
153
+
154
+ - Email: `{gig_id}_{token}.dollar-platoon@fwd.zoomgtm.com`
155
+ - Webhook: `/inbound/webhook/{gig_id}?token={token}`
156
+ - Requests without a valid token get `403`.
157
+
158
+ ### Who can read it
159
+
160
+ The token is a **write credential** — whoever holds it can post tasks into the gig — so
161
+ `GET /gigs/:id` only puts it on the `webhook` URL for callers entitled to use that door:
162
+
163
+ | Caller | Gets `?token=` on `webhook` |
164
+ |---|---|
165
+ | The gig owner | Yes, on every gig |
166
+ | A member of an `inbound_order` gig | Yes — placing an order **is** posting to this webhook |
167
+ | A member of any other gig | **No.** A worker is not a publisher |
168
+ | Anyone else, signed in or not | No |
169
+
170
+ The `webhook` field itself always comes back, minus the token, so the shape of the response does
171
+ not change for a reader who is not entitled to the secret. Read it once as the owner and store
172
+ it; a publisher app is not expected to re-fetch it per request.
173
+
174
+ On a **`task_escrow`** gig the token is stronger than a write credential — creating a task
175
+ deposits the owner's USDC on chain — which is why a worker never sees it there.
176
+
177
+ ```json
178
+ POST /gigs/:id/rotate-token
179
+ → { "email": "GIG_01HX..._newtoken...", "webhook": "https://.../webhook/GIG_01HX...?token=newtoken" }
180
+ ```
181
+
182
+ **Rotation invalidates the old email address, the old webhook URL, and every Insert Task link at
183
+ once.** Update your publisher integrations immediately after.
184
+
185
+ Gigs created before tokens existed accept all inbound requests. Generate one from the dashboard
186
+ to turn protection on.
187
+
188
+ ## Worker rate limits
189
+
190
+ An optional throttle: each gigworker may take at most **N per M minutes**. "Take" counts proofs
191
+ submitted *and* queue tasks claimed but not yet proven, so a worker cannot hoard the queue by
192
+ claiming ahead.
193
+
194
+ - Gig-wide default: `default_rate_limit_count` + `default_rate_limit_minutes` (both positive
195
+ integers, or both `null` to disable).
196
+ - Per worker: `PATCH /gigs/:id/mailboxes/:mbx_id` with `rate_limit_count` + `rate_limit_minutes`
197
+ (owner only; both `null` reverts to the gig default).
198
+ - At the limit, `/queue/poll` and `POST /gigs/:id/proofs` return `429` with a readable `error` and
199
+ a `rate_limit` object: `{ count, minutes, source: "gig"|"mailbox", used, remaining, retry_at }`.
200
+ - Submitting a proof for a task you already claimed is **never** blocked — the claim was counted
201
+ at poll time, so the loop never double-charges.
202
+
203
+ ## Open task cap
204
+
205
+ The rate limit above is a rolling window, so a task a worker holds stops counting against it once
206
+ the claim ages out. "5 per hour" therefore lets one worker take 5 more tasks every hour and prove
207
+ none of them. The open task cap is the standing ceiling the window cannot express: **how many
208
+ tasks one worker may hold with no proof submitted, at any moment**.
209
+
210
+ - Gig-wide default: `default_max_open_tasks` (positive integer, or `null` for unlimited).
211
+ - Per worker: `PATCH /gigs/:id/mailboxes/:mbx_id` with `max_open_tasks` (owner only; `null`
212
+ reverts to the gig default).
213
+ - At the cap, `/queue/poll` returns `429` with an `open_tasks` object:
214
+ `{ max_open_tasks, source: "gig"|"mailbox", open, remaining }`. Under the cap, a poll is
215
+ trimmed to the slots left, and the same object rides on the response.
216
+ - A task with a proof against it is not open — the worker is waiting on review, not hoarding.
217
+ Assigned tasks and `queue_solo` copies do count.
218
+ - The only ways to free a slot: submit a proof, skip the task, report it, or let it expire.
219
+
220
+ Pair it with `task_timeout`. The cap stops a worker taking more; the timeout takes back what
221
+ they already hold.
222
+
223
+ ## Task expiry
224
+
225
+ Set `task_timeout` (seconds) to give workers a deadline. The clock starts when a task is claimed
226
+ (queue gigs) or delivered (push gigs). Default `null` — tasks never expire.
227
+
228
+ - After expiry, proof submission, skip, and report all return `410 Gone`.
229
+ - Unclaimed queue items never expire.
230
+ - Task listings carry `expires_at` and `expired`.
231
+ - **An expired task returns to the pool by itself.** The sweep runs on ordinary gig traffic (at
232
+ most once a minute), and the daily cron catches a gig nobody polled. It recycles the task
233
+ exactly as the route below does, so an expired hold is released even if you never look.
234
+ `tasks_received` is **not** given back on an expiry — running out of time is what
235
+ `response_rate` measures. An owner recycling by hand still discounts it, as before.
236
+
237
+ ```json
238
+ POST /gigs/:id/tasks/:msgId/extend
239
+ → { "success": true, "expires_at": "...", "expired": false }
240
+ ```
241
+
242
+ ```json
243
+ POST /gigs/:id/tasks/:msgId/recycle
244
+ → { "success": true, "requeued": true } // queue gig
245
+ → { "success": true, "reassigned_to": "MBX_...", "reassigned_to_name": "..." } // push gig
246
+ ```
247
+
248
+ Recycle takes the task back and redistributes it. On a `queue` gig it returns to the queue and the
249
+ previous holder will not receive it again. On `queue_solo` it discards that one worker's copy and
250
+ returns its claim slot, leaving everyone else untouched. On a push gig it reassigns per the gig's
251
+ distribution mode. Both routes reject an `UNASSIGNED` task — there is no holder and no clock.
252
+
253
+ ## Funding
254
+
255
+ ```json
256
+ POST /gigs/:id/deposit { "wallet_alias_id": "...", "amount": 100 }
257
+ → { "tx_hash": "0x...", "available_funds": 100 }
258
+ ```
259
+
260
+ Moves USDC from your hot wallet into the gig's on-chain balance. Budget **110%** of expected
261
+ payouts — the fee is charged on top. Funds are locked once deposited; there is no withdrawal.
262
+
263
+ **On an order machine this route answers `409`, and correctly.** An order machine is not funded
264
+ by its owner: each order is funded by the participant who places it, against a deposit that names
265
+ it. Money in the shared pot there would be unreachable — the deposit-naming payout can only spend
266
+ deposits it names, and the Treasury's reserved-balance guard refuses the legacy payout the float
267
+ would need. It would be money the vendor could never get out.
268
+
269
+ ## The dashboard
270
+
271
+ ```json
272
+ GET /gigs/:id/dashboard
273
+ → { "gig": {...}, "mailboxes": [...], "proofs": [...], "rollups": [...], "inbound_messages": [...] }
274
+ ```
275
+
276
+ Syncs the on-chain balance on every load and signs every S3 URL for proof attachments. Proofs and
277
+ inbound messages are cursor-paginated — follow `proofs_next_cursor` and `inbound_next_cursor` via
278
+ `GET /gigs/:id/dashboard/proofs?cursor=` and `GET /gigs/:id/dashboard/inbound?cursor=`. The
279
+ inbound page also accepts `?tag=`, `?tag_match=`, and `?tag_mode=`.
280
+
281
+ ---
282
+
283
+ ## Mailbox routes
284
+
285
+ A mailbox is one worker's place in one gig. It is created by joining and it is where tasks land.
286
+
287
+ | Method | Path | Auth | Description |
288
+ |--------|------|------|-------------|
289
+ | POST | `/gigs/:id/mailboxes` | Yes | Join the gig |
290
+ | GET | `/gigs/:id/mailboxes` | Owner | List mailboxes in the gig |
291
+ | PATCH | `/gigs/:id/mailboxes/:mbx_id` | Yes | Update (owner and worker set different fields) |
292
+ | DELETE | `/gigs/:id/mailboxes/:mbx_id` | Yes | Leave the gig |
293
+ | GET | `/mailboxes/mine` | Yes | Your mailboxes across every gig |
294
+ | GET | `/work/available` | Yes | Where work is waiting — see gigworkers.md |
295
+ | GET | `/mailboxes/:mbxId/inbound` | Yes | Tasks in one mailbox |
296
+ | POST | `/gigs/:id/mailboxes/:mbxId/regenerate-token` | Yes | New share token |
297
+
298
+ ## Join a gig
299
+
300
+ ```json
301
+ POST /gigs/:id/mailboxes
302
+ {
303
+ "name": "John's Mailbox",
304
+ "email": "john@example.com", // contact address for forwarded tasks
305
+ "invite": "a1b2c3d4e5f6", // required when join_policy is "invite"
306
+ "wallet_address": "0x...", // optional — hot wallet auto-provisioned if omitted
307
+ "webhook": "https://...", // optional — pushed tasks POST here
308
+ "notes": "I have experience with Reddit marketing",
309
+ "tags": ["urgent", "linkedin-batch"] // private to the worker
310
+ }
311
+ → { "mailbox": { "id": "MBX_01HX...", "status": "active" } } // or "pending_approval"
312
+ ```
313
+
314
+ The invite is the gate. An invite gig rejects a join without a valid token (`403`); an
315
+ email-bound invite must match your account email and skips owner approval. There are no
316
+ reputation thresholds — `min_rep_volume`, `min_rep_quality` and `min_rep_recency` were removed,
317
+ and a gig that still carries them is not gated by them.
318
+
319
+ If the gig sets `join_webhook_url`, each successful join fires a fire-and-forget POST:
320
+
321
+ ```json
322
+ { "event": "mailbox.joined", "gig_id": "GIG_01HX...", "mailbox_id": "MBX_01HX...",
323
+ "name": "John's Mailbox", "status": "active", "email": "john@example.com",
324
+ "wallet_address": "0x...", "invite_token": "a1b2c3d4e5f6", "joined_at": "..." }
325
+ ```
326
+
327
+ Useful for auto-provisioning a workspace or syncing a roster the moment somebody joins.
328
+
329
+ ## Update a mailbox
330
+
331
+ **The owner** sets `priority` (1–10, used by `priority_weighted`), `status` (`"active"` approves a
332
+ pending mailbox, `"inactive"` disables it), and the rate-limit override.
333
+
334
+ **The worker** sets `tags`, the standing `filter_*` preferences (see
335
+ [pricing-and-tags.md](https://dollarplatoon.com/skill/pricing-and-tags.md)), and
336
+ `wallet_address`.
337
+
338
+ Worker `tags` are **never returned to the gig owner**. They are for organising your own inbox.
339
+
340
+ Changing `wallet_address`:
341
+
342
+ - Must be a valid EVM address. It is registered to your account automatically; an address already
343
+ registered to a **different** account is rejected with `409`, because wallets stay 1:1 with
344
+ users so nobody can claim somebody else's settlement history.
345
+ - Takes effect for **future rollups only**. A rollup that already exists — including one still
346
+ retrying after a failure — pays to the address snapshotted when it was created.
347
+ - Your history survives, but it does not follow you automatically. Events accrue **per wallet**,
348
+ and `GET /reputation/:wallet/events` reads one address at a time — so after rotating a payout
349
+ address, anyone reading your record has to read both. Nothing is lost; it is simply in two
350
+ places. See [payouts.md](https://dollarplatoon.com/skill/payouts.md).
351
+
352
+ ## List your mailboxes
353
+
354
+ ```json
355
+ GET /mailboxes/mine
356
+ → { "mailboxes": [ { "id": "MBX_...", "gig_id": "GIG_...", "status": "active",
357
+ "gig_title": "...", "owner_display_name": "...", "share_token": "SHARE_...",
358
+ "tasks_received": 12, "proofs_submitted": 10, "response_rate": 0.83,
359
+ "tags": ["urgent"] } ], "next_cursor": null }
360
+ ```
361
+
362
+ Returns everything by default. Send `?limit=` (max 200) or `?cursor=` to page instead. Supports
363
+ `?tag=` and `?tag_match=` with the same semantics as `/work/available`.
364
+
365
+ This is also where an agent gets its own `share_token` to build a `/submit/:token` link. The
366
+ owner-facing list at `GET /gigs/:id/mailboxes` strips that field.
367
+
368
+ ## Reading a mailbox's tasks
369
+
370
+ ```json
371
+ GET /mailboxes/:mbxId/inbound
372
+ → { "inbound_messages": [ { "id": "TASK_...", "type": "email", "subject": "...",
373
+ "payload": "...", "payload_truncated": false, "payload_bytes": 4211,
374
+ "price": 2.5, "price_tbd": false, "tags": ["shortform"],
375
+ "expires_at": null, "expired": false, "alias": null,
376
+ "attachments": [ { "filename": "...", "url": "https://..." } ] } ],
377
+ "next_cursor": null }
378
+ ```
379
+
380
+ Newest first, 100 per page (`?limit=` up to 300). `?summary=1` returns every message with no body
381
+ at all — the cheap call for counts and unread badges.
382
+
383
+ **`payload` may be a preview.** Bodies over 6,000 characters are stored off-row, and a list
384
+ returns only the first 1,000 characters with `payload_truncated: true` and the true length in
385
+ `payload_bytes`. Fetch the whole body before acting on it:
386
+
387
+ ```json
388
+ GET /gigs/:id/tasks/:msgId
389
+ → { "task": { "id": "TASK_...", "payload": "<complete, never truncated>",
390
+ "payload_truncated": false, "payload_bytes": 31674, ... } }
391
+ ```
392
+
393
+ Readable by the gig owner, by the worker holding the task, and — for tasks still queued — by any
394
+ member of that gig. Tasks returned by `/queue/poll` always arrive complete, so a polling worker
395
+ never needs this route.