twentythree-skills 1.0.0

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.
@@ -0,0 +1,146 @@
1
+ ---
2
+ name: upload-and-publish
3
+ description: Upload a video file, set metadata, and publish it on TwentyThree.
4
+ ---
5
+
6
+ # Workflow: Upload and Publish a Video
7
+
8
+ > Complete sequence for uploading a video file, setting metadata, and making it publicly visible.
9
+ > All commands use `--json` — capture IDs from the `data.photo_id` field of upload responses and `data.id` for other responses.
10
+
11
+ > See [`reference/video.md`](../reference/video.md) for exhaustive flag details and [`reference/category.md`](../reference/category.md) for category selection.
12
+
13
+ ## Prerequisites
14
+
15
+ - Auth scope required: **write**
16
+ - Run `twentythree auth credentials` if not already configured.
17
+ - Confirm auth: `twentythree auth status --json`
18
+ - Chunked upload is automatic — `twentythree video upload` handles chunking internally (see `reference/video.md` §video upload).
19
+
20
+ ## Steps
21
+
22
+ ### 1. (Optional) List categories to find a target category ID
23
+
24
+ ```bash
25
+ twentythree category list --json
26
+ ```
27
+
28
+ Expected output shape: `{ data: [ { id, title, description, hidden }, ... ] }`
29
+ Capture: `data[n].id` of the desired row as `category_id`
30
+ On failure:
31
+ - `401 Unauthorized` → run `twentythree auth status --json` to confirm credentials
32
+ - Empty list → confirm workspace has categories; create one with `twentythree category create --title "…" --json`
33
+
34
+ ---
35
+
36
+ ### 2. Upload the video
37
+
38
+ ```bash
39
+ twentythree video upload ./video.mp4 --title "Product Demo" --category-id <category_id> --json
40
+ ```
41
+
42
+ Expected output shape: `{ ok: true, data: { photo_id, tree_id, token } }`
43
+ Capture:
44
+ - `data.photo_id` as `video_id`
45
+ - Construct admin URL as: `https://<domain>/manage/video/<data.photo_id>`
46
+ (surface this to the user — the CLI prints it on stdout but it is not in the JSON data object)
47
+
48
+ On failure:
49
+ - Network error or `401` → run `twentythree auth status` and `twentythree doctor`
50
+ - Upload stalls → retry; chunked upload resumes automatically (see `reference/video.md` for `--chunk-size` / `--concurrency` tuning)
51
+ - `413 Payload Too Large` → the file exceeds workspace quota; check `twentythree site get --include-quota --json`
52
+
53
+ ---
54
+
55
+ ### 3. (Optional) Set additional metadata
56
+
57
+ ```bash
58
+ twentythree video update <video_id> --description "Launch video for Q2 release" --tags "product q2 launch" --json
59
+ ```
60
+
61
+ Expected output shape: `{ ok: true, data: { photo_id, title, description, ... } }`
62
+ Capture: none (fire-and-forget update — verify with `twentythree video get <video_id> --json` if needed)
63
+ On failure:
64
+ - `403 Forbidden` → confirm auth scope is `write`, not `read`
65
+ - `404 Not Found` → confirm `video_id` is correct and video exists (`twentythree video get <video_id> --json`)
66
+
67
+ ---
68
+
69
+ ### 4. (Optional) Set a custom thumbnail frame
70
+
71
+ ```bash
72
+ twentythree video frame <video_id> --time 10 --json
73
+ ```
74
+
75
+ Expected output shape: `{ data: { id, thumbnail_url } }`
76
+ Capture: none
77
+ On failure:
78
+ - `400 Invalid Time` → ensure `--time` is less than video duration (check via `twentythree video get <video_id> --json`)
79
+
80
+ ---
81
+
82
+ ### 5. (Optional) Wait for transcoding to complete
83
+
84
+ ```bash
85
+ twentythree video transcoding-progress <video_id> --json
86
+ ```
87
+
88
+ Expected output shape: `{ data: { status, progress } }`
89
+ Capture: `data.status` — must be `complete` before publishing
90
+ On failure:
91
+ - Status stuck at `processing` for >10 minutes → contact support; do NOT publish
92
+ - Status `failed` → check the video file; re-upload if corrupt
93
+
94
+ Polling pattern:
95
+
96
+ ```bash
97
+ while true; do
98
+ STATUS=$(twentythree video transcoding-progress <video_id> --json | jq -r '.data.status')
99
+ if [ "$STATUS" = "complete" ]; then break; fi
100
+ sleep 30
101
+ done
102
+ ```
103
+
104
+ ---
105
+
106
+ ### 6. Publish
107
+
108
+ ```bash
109
+ twentythree video update <video_id> --publish --json
110
+ ```
111
+
112
+ Expected output shape: `{ data: { id, published: true } }`
113
+ Capture: confirm `data.published` is `true`
114
+ On failure:
115
+ - `403 Forbidden` → confirm auth scope is `write`
116
+ - Publish fails silently → run `twentythree video get <video_id> --json` and check `published` field
117
+
118
+ ---
119
+
120
+ ## Error Handling
121
+
122
+ | Step | Failure | What to check |
123
+ |------|---------|---------------|
124
+ | 1 | Empty category list | `twentythree category create --title "…" --json` to create one |
125
+ | 1 | `401 Unauthorized` | `twentythree auth status --json` to confirm credentials |
126
+ | 2 | Upload auth/network error | `twentythree auth status --json`, `twentythree doctor` |
127
+ | 2 | Quota exceeded | `twentythree site get --include-quota --json` |
128
+ | 3 | 403 Forbidden | Confirm auth scope is `write` |
129
+ | 3 | 404 Not Found | `twentythree video get <video_id> --json` to confirm video exists |
130
+ | 4 | Invalid time | `--time` must be less than duration from `video get` |
131
+ | 5 | Transcoding stuck | Poll `transcoding-progress` after 30s; contact support after 10 min |
132
+ | 5 | Status `failed` | Check video file integrity; re-upload if corrupt |
133
+ | 6 | 403 Forbidden | Confirm auth scope is `write` |
134
+ | 6 | Publish fails silently | `twentythree video get <video_id> --json` to check `published` field |
135
+
136
+ ## Notes
137
+
138
+ - All 6 steps can be scripted in sequence; only Steps 2 and 6 are strictly required (1, 3, 4, 5 are optional).
139
+ - For a minimal end-to-end sequence: pass `--publish` directly to the upload command:
140
+ ```bash
141
+ twentythree video upload ./video.mp4 --title "Demo" --publish --json
142
+ ```
143
+ This is valid but skips the optional metadata, frame, and transcoding-check steps.
144
+ - The admin URL from Step 2 opens the video's admin edit page — surface this to the user so they can review or make manual edits. Construct it as `https://<domain>/manage/video/<data.photo_id>` (it is printed on stdout by the CLI but is not included in the JSON data object).
145
+ - `--category-id` accepts a comma-separated list of IDs to assign to multiple categories simultaneously.
146
+ - After a successful publish, use `twentythree video get <video_id> --json` to confirm the `published` field is `true` before reporting success to the user.
@@ -0,0 +1,209 @@
1
+ ---
2
+ name: webinar-lifecycle
3
+ description: Create, configure, run, record, and archive a live webinar end-to-end.
4
+ ---
5
+
6
+ # Workflow: Webinar Lifecycle
7
+
8
+ > Complete sequence from creating a webinar through archiving it after the session ends.
9
+ > All commands use `--json` — capture IDs from the `data.id` field of each response.
10
+ > CLI `webinar` maps to API `live` — see `reference/webinar.md` §Terminology Notes.
11
+
12
+ > See [`reference/webinar.md`](../reference/webinar.md) for exhaustive flag details on every command referenced below.
13
+
14
+ ## Prerequisites
15
+
16
+ - Auth scope required: **write** (create, update, upload-image, recording, publishing)
17
+ - Some read-only steps (room connect, clips) accept `read` scope
18
+ - Run `twentythree auth credentials` if not already configured.
19
+ - Confirm auth: `twentythree auth status --json`
20
+ - NOTE: There is no `webinar get` command — to retrieve webinar details, use `webinar list --search "<title>" --json` (see `reference/webinar.md`).
21
+
22
+ ## Steps
23
+
24
+ ### 1. Create the webinar
25
+
26
+ ```bash
27
+ twentythree webinar create --title "Q2 Town Hall" --live-date "2026-05-15T16:00:00Z" --description "Quarterly update" --json
28
+ ```
29
+
30
+ Expected output shape: `{ data: { id, admin_url } }`
31
+ Capture:
32
+ - `data.id` as `webinar_id`
33
+ - `data.admin_url` as `admin_url` (surface to the user — always print ID + admin URL after create)
34
+
35
+ On failure:
36
+ - `400 Invalid date` → `--live-date` must be ISO 8601 (e.g. `2026-05-15T16:00:00Z`)
37
+ - `401 Unauthorized` → run `twentythree auth status --json`
38
+
39
+ ---
40
+
41
+ ### 2. (Optional) Add agenda sections
42
+
43
+ ```bash
44
+ twentythree webinar section add <webinar_id> --title "Intro" --start-time 0 --json
45
+ twentythree webinar section add <webinar_id> --title "Q&A" --start-time 1800 --json
46
+ ```
47
+
48
+ Expected output shape: `{ data: { id, title, start_time } }`
49
+ Capture: `data.id` as `section_id` if you intend to update or remove this section later; otherwise none
50
+ On failure:
51
+ - `404 Not Found` → confirm `webinar_id` exists (`twentythree webinar list --search "<title>" --json`)
52
+ - Validation error → confirm `--start-time` is in seconds, not mm:ss format
53
+
54
+ ---
55
+
56
+ ### 3. (Optional) Add speakers
57
+
58
+ ```bash
59
+ twentythree webinar speaker add <webinar_id> --name "Jane Doe" --email jane@example.com --title "CTO" --json
60
+ ```
61
+
62
+ Expected output shape: `{ data: { id, name, role } }`
63
+ Capture: `data.id` as `speaker_id` if you need to update or remove this speaker later
64
+ On failure:
65
+ - Missing required flag → run `twentythree webinar speaker add --agent` to see the complete flag list
66
+ - `404 Not Found` → confirm `webinar_id` exists
67
+
68
+ ---
69
+
70
+ ### 4. (Optional) Upload a thumbnail image
71
+
72
+ ```bash
73
+ twentythree webinar upload-image <webinar_id> ./thumb.jpg --type thumbnail --json
74
+ ```
75
+
76
+ Expected output shape: none (upload-image returns no JSON body — success is confirmed by exit code 0)
77
+ Capture: none (image is attached to the webinar automatically)
78
+ On failure:
79
+ - `413 Payload Too Large` → resize image; chunked upload is automatic but workspace size limits still apply
80
+ - `401 Unauthorized` → run `twentythree auth status --json`
81
+
82
+ ---
83
+
84
+ ### 5. Publish the webinar (make visible to registrants)
85
+
86
+ ```bash
87
+ twentythree webinar update <webinar_id> --publish --json
88
+ ```
89
+
90
+ Expected output shape: `{ data: { id, published: true } }`
91
+ Capture: confirm `data.published` is `true`
92
+ On failure:
93
+ - `403 Forbidden` → auth scope `write` required
94
+ - Publish fails silently → run `twentythree webinar list --search "<title>" --json` and check the `published` field
95
+
96
+ ---
97
+
98
+ ### 6. Get room connection info (when going live)
99
+
100
+ ```bash
101
+ twentythree webinar room connect <webinar_id> --json
102
+ ```
103
+
104
+ Expected output shape: `{ data: { stream_key, room_url } }`
105
+ Capture:
106
+ - `data.stream_key` as `stream_key` — pass to your broadcasting software (OBS, Zoom, etc.)
107
+ - `data.room_url` as `room_url` — pass to moderators who join the room
108
+
109
+ On failure:
110
+ - Webinar status is `previous` → room connection unavailable for archived webinars; run `twentythree webinar update <webinar_id> --status upcoming --json` to re-open
111
+ - `404 Not Found` → confirm `webinar_id` is correct
112
+
113
+ ---
114
+
115
+ ### 7. (Optional) Start recording once the live session is active
116
+
117
+ ```bash
118
+ twentythree webinar recording start <webinar_id> --json
119
+ ```
120
+
121
+ Expected output shape: `{ data: {} }` (recording start returns minimal output; confirm via `recording status`)
122
+ Capture: none (recording is attached to the webinar; monitor via `webinar recording status`)
123
+ On failure:
124
+ - `409 Conflict` → recording already in progress; run `twentythree webinar recording status <webinar_id> --json` to check
125
+ - `403 Forbidden` → auth scope `write` required
126
+
127
+ ---
128
+
129
+ ### 8. Stop recording (after session ends)
130
+
131
+ ```bash
132
+ twentythree webinar recording stop <webinar_id> --json
133
+ ```
134
+
135
+ Expected output shape: `{ data: {} }` (recording stop returns minimal output; clip processing begins asynchronously)
136
+ Capture: none
137
+ On failure:
138
+ - `409 Conflict` → no recording in progress; confirm with `twentythree webinar recording status <webinar_id> --json`
139
+
140
+ ---
141
+
142
+ ### 9. Check recording status and wait for clips
143
+
144
+ ```bash
145
+ twentythree webinar recording status <webinar_id> --json
146
+ twentythree webinar clips <webinar_id> --json
147
+ ```
148
+
149
+ Expected output shape:
150
+ - `recording status`: `{ data: { status, ... } }` — check `data.status` for `processing` or `complete`
151
+ - `webinar clips`: `{ data: [ { id, title, duration, ... } ] }` — array of clip objects; empty while still processing
152
+
153
+ Capture:
154
+ - `recording status` `data.status` — must be `complete` before clips are fully available
155
+ - `webinar clips` array — each element is a clip with an `id` you can use with `twentythree video` commands
156
+
157
+ On failure:
158
+ - Clips array empty immediately after `stop` → normal; recording processing takes several minutes
159
+ - Clips still empty after 10+ minutes → contact support
160
+
161
+ Polling pattern (wait for at least one clip to be available):
162
+
163
+ ```bash
164
+ while true; do
165
+ CLIPS=$(twentythree webinar clips <webinar_id> --json | jq '.data | length')
166
+ if [ "$CLIPS" -gt 0 ]; then break; fi
167
+ sleep 60
168
+ done
169
+ ```
170
+
171
+ ---
172
+
173
+ ### 10. (Optional) Archive — mark as previous
174
+
175
+ ```bash
176
+ twentythree webinar update <webinar_id> --status previous --json
177
+ ```
178
+
179
+ Expected output shape: `{ data: { id, status: "previous" } }`
180
+ Capture: none
181
+ On failure:
182
+ - `400 Bad Request` → check current status; `recording stop` must be called before archiving a live session
183
+ - Some status transitions may be blocked: confirm `recording status` is not `recording` before archiving
184
+
185
+ ---
186
+
187
+ ## Error Handling
188
+
189
+ | Step | Failure | What to check |
190
+ |------|---------|---------------|
191
+ | 1 | Invalid date | `--live-date` must be ISO 8601 (e.g. `2026-05-15T16:00:00Z`) |
192
+ | 1 | `401 Unauthorized` | `twentythree auth status --json` to confirm credentials |
193
+ | 2-3 | Missing required flags | Run `twentythree webinar <subtopic> <cmd> --agent` to enumerate all flags |
194
+ | 2-3 | `404 Not Found` | `webinar_id` invalid; `twentythree webinar list --search "<title>" --json` to find it |
195
+ | 5 | Publish 403 | Confirm auth scope is `write` |
196
+ | 6 | Room connection blocked | Webinar status must be `upcoming` or `live`, not `previous` |
197
+ | 7 | Recording 409 Conflict | Already recording; `twentythree webinar recording status <webinar_id> --json` first |
198
+ | 8 | Stop 409 Conflict | No recording in progress; verify with `recording status` |
199
+ | 9 | Clips empty | Processing can take 10+ minutes after `recording stop`; poll every 60s |
200
+ | 10 | Status transition blocked | Confirm `recording stop` was called; check `recording status` is not `recording` |
201
+
202
+ ## Notes
203
+
204
+ - Steps 2-4 (sections, speakers, thumbnail) are optional but improve viewer experience.
205
+ - Step 6 (`room connect`) returns credentials for a third-party broadcaster. Agents should NOT attempt to stream content themselves — pass the `stream_key` and `room_url` to the user.
206
+ - Steps 7-8 (recording start/stop) are optional. If you skip them, no clips will be generated after the session.
207
+ - Step 9's polling loop can be replaced by subscribing to the `recording.completed` webhook event (see `reference/webhook.md`).
208
+ - Use `twentythree webinar list --search "<title>" --json` as the canonical way to retrieve webinar details — there is no `webinar get` command.
209
+ - Clips generated from recording are standard video assets. After they appear in `webinar clips`, you can manage them with the full `video` command set (e.g. `twentythree video update <clip_id> --publish --json`).