mirror of
https://github.com/magnus919/agent-skills.git
synced 2026-09-11 19:47:12 +03:00
Research-driven rebuild of the peertube skill (docs.joinpeertube.org REST reference 8.1.0 + SepiaSearch + server source + live anonymous probes): - SKILL.md rewritten to the lastfm model: intent-grouped commands, pipeline recipes, jq guidance, researched gotchas, When-to-use/When-not-to-use, reference routing table. New negative boundary in the description (YouTube/Vimeo uploads, video editing, server administration). - scripts/peertube-cli -> scripts/peertube, rewritten and extended: offset (start/count) pagination replaces the nonexistent page param, comments fixed to the hyphenated /comment-threads route, server command now composes /config/about + /server/stats (canonical paths), search gains --search-target with searchTarget=local default and help text stating its instance-local scope, new video/comments/channel/account/ my-videos/logout commands, --server hoisted before or after the subcommand, OAuth2 password grant hardened for 2FA (x-peertube-otp) and the production client_secret masking behavior, per-instance owner-only token file with refresh-before-expiry and revocation. - references/: auth-and-tokens, search-and-discovery, endpoint-catalog, gotchas-field-guide, worked-recipes - all cited to official docs with Sources footers (URLs verified live at authoring time). - scripts/test_peertube.py: 54 offline tests (help, argument errors, dry-run plans, mocked OAuth2 persistence/refresh/revocation, handler contracts, documented pipeline chains) passing pytest strict-markers, unittest discovery, and the proxy-trap zero-egress rerun; one env-guarded anonymous live probe (PEERTUBE_LIVE_TESTS=1). - evals/evals.json: six schema-v1 cases incl. SepiaSearch-scope and masked-secret cases plus a should-not-trigger YouTube negative probe. - README refreshed for humans; root README blurb and skill-triggers row synced; marketplace.json/llms.txt regenerated (codex artifacts unchanged); test-results/ gitignored (pytest runner artifact). Co-authored-by: factory-droid[bot] <138933559+factory-droid[bot]@users.noreply.github.com>
7.4 KiB
7.4 KiB
PeerTube gotchas field guide
Failure signatures and behavioral traps, distilled from the official docs, the server source, and live probes. Each entry: symptom → cause → what to do.
Instance plurality (the big one)
- Symptom: same CLI command works on one instance and 400s/401s/empty-results on another; or a token that worked on instance A 401s on instance B.
- Cause: PeerTube is federated software, not a single API. Every instance is an independent deployment with its own rules, allowances, moderation policy, enabled features (NSFW policy, search-index support, registration, transcoding) and its own user accounts and OAuth tokens. A token minted by instance A is meaningless to instance B; instance B may have closed registrations, disabled uploads, or set its own NSFW default.
- Do: always configure the instance host per operation (
PEERTUBE_SERVERor--server); keep per-instance token files; never assume an account or video exists on a different instance. Federated content viewed on instance X still belongs to the origin instance (channel.host/account.host/ videourltell you which).
Search scope confusion
- Symptom: "search across the fediverse" expectations return only a handful of local results; or results reference videos the instance doesn't host.
- Cause:
searchTargethas two scopes:local(instance-known objects only) andsearch-index(external fediverse index, admin-enabled). Omitting the parameter gives the instance's own scope on current servers (observed), not the fediverse. - Do: pass
searchTarget=localexplicitly for instance scope; use SepiaSearch (https://sepiasearch.org/api/v1/search/videos) for fediverse-wide scope. Index results point at origin instances — followchannel.host/urlrather than expecting the queried instance to serve them.
Pagination: start/count, never page
- Symptom: client pages with
page=1&count=15and gets identical results forever. - Cause: the API has no
pageparameter; unknown params are ignored, sopage=1requests silently return the firstcountrows every time. - Do: advance
startby the page size untilstart >= totalor an empty page. Maxcountis 100 (higher values are rejected).skipCount=truetrades thetotalfield for speed — then you must stop on the first short page.
Comment route spelling
- Symptom: fetching comments with
/videos/{id}/commentsor/videos/{id}/commentthreadsreturns 400 (current servers answer 400, not 404, for bad routes — see below) while other endpoints work. - Cause: the route is
GET /videos/{id}/comment-threads(hyphenated). The v8.3/comments/{commentId}/repliesroute is for replies, not top-level threads. - Do: use
/comment-threadswithstart/count/sort=-createdAt|-totalReplies.
Instance metadata endpoint names
- Symptom:
/instance/stats,/instance/about,/instance/configall 400/404. - Cause: mixed current naming: stats live at
/server/stats(operation titled "Get instance stats"), about at/config/about, config at/config. - Do: compose
/config/about+/server/statsfor a full instance picture.
oauth-clients/local secret masking
- Symptom:
GET /oauth-clients/localreturns"client_secret": "********************************"; the following token request 400s with invalid_client. - Cause: current production servers mask the secret in this response (the value is still delivered to the web client via served front-end assets; the API response masks it). Older instances/versions return the real secret.
- Do: detect the masked value; if masked, obtain the client pair from the instance's
served front-end JS (the same source its own web UI uses) before the token request. Never
persist the masked string as a secret. The endpoint is also Host-header-guarded (403 if
the
Hostheader disagrees with the configured webserver hostname — mind reverse proxies).
Auth error signatures
| Status | Where | Meaning |
|---|---|---|
400 on POST /users/token |
invalid client pair (including the masked-secret case) or wrong credentials | RFC7807-style application/problem+json body; check detail |
401 on POST /users/token |
account has 2FA and no x-peertube-otp header supplied |
supply OTP header |
| 401 on authenticated GETs | token expired/revoked/malformed, or missing | re-run password grant |
403 on oauth-clients/local |
Host-header mismatch (proxy misconfiguration) | fix the proxy/Host |
| 429 anywhere | rate limit (default 50 req/10 s; token endpoint tighter) | read Retry-After + X-RateLimit-* headers, back off |
| 400 on unknown routes | current servers answer 400 with an error body for unrecognized API routes | read the body; the classic "404 means missing route" assumption misleads here |
| connection errors | wrong/unreachable PEERTUBE_SERVER |
no HTTP response at all; classify as transport failure |
Shape and value traps
- duration is seconds (integer). Sample list value
1419= 23:39, not milliseconds. - ids are triple: numeric
id,uuid(UUIDv4), andshortUUID— all three are accepted by/videos/{id}and family;uuidis the safest portable choice in scripts. users/mesample is an array in the docs; live servers return a single object. Tolerate both when writing generic parsers.roleis an object{id, label}on/users/me— don't stringify the dict.videoQuotais bytes (large integer).{total, data}everywhere: collections never wrap in{"videos": []}at the API layer (the bundled CLI adds that key in its JSON output; know which layer you're reading).nsfwfilter is a string ("true"/"false") in query params.- filter names end in
OneOf/AllOf(categoryOneOf,tagsAllOf, ...); barecategory=from old wrappers is ignored silently. - federated results: a video listed on instance X may be hosted on instance Y
(
account.host/channel.host). Views/likes counters are local-ish and eventually consistent across the federation — don't expect exact global numbers.
Version drift
- Docs reference page currently identifies PeerTube 8.1.0 while the changelog already
carries 8.3.0 material — instance versions vary; validate optional parameters
(
stateOneOf>= 8.2,autoTagOneOf>= 6.2) before relying on them. - Historical renames worth knowing when reading old code:
/videos/channels/*→/video-channels/*,/videos/accounts/{id}/channels→/accounts/{id}/video-channels(v1.0.0-beta.4). - Refresh-token request fields are underspecified in official docs; don't build refresh-critical logic without testing against your target instance.
Sources
- https://docs.joinpeertube.org/api-rest-reference.html (operation pages: searchVideos, getVideos, comment-threads, getOAuthToken, revokeOAuthToken, getInstanceStats; Errors, Rate-limits sections)
- https://docs.joinpeertube.org/api/rest-getting-started
- https://docs.joinpeertube.org/use/search (scope semantics)
- https://docs.joinpeertube.org/admin/configuration (global-search admin enablement)
- https://docs.joinpeertube.org/CHANGELOG (route renames, version additions)
- https://raw.githubusercontent.com/Chocobozzz/PeerTube/develop/server/core/controllers/api/oauth-clients.ts (Host guard)
- Live anonymous probes (secret masking, search default scope, route status codes, response shapes), 2026-08-29.