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.
package/README.md ADDED
@@ -0,0 +1,47 @@
1
+ # twentythree-skills
2
+
3
+ AI agent skills for the [TwentyThree CLI](https://github.com/23/twentythree-cli) — installable markdown skill definitions for Claude Code, OpenAI Codex, GitHub Copilot, and Cursor.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npx twentythree-skills
9
+ ```
10
+
11
+ Detects your agent runtime and copies skill files into the right location automatically. Run again at any time to update — it's idempotent.
12
+
13
+ **Project-local install:**
14
+
15
+ ```bash
16
+ npx twentythree-skills --project
17
+ ```
18
+
19
+ Installs into `.claude/skills/`, `.agents/skills/`, `.github/skills/`, or `.cursor/skills/` relative to the current directory.
20
+
21
+ ## What's included
22
+
23
+ - `skills/SKILL.md` — root skill file: auth setup, command syntax, resource index, `--agent` flag docs
24
+ - `skills/reference/*.md` — 22 reference files, one per TwentyThree CLI resource group (video, webinar, analytics, …)
25
+ - `skills/workflows/*.md` — workflow files for high-value automation patterns (video upload, webinar lifecycle)
26
+
27
+ ## Supported runtimes
28
+
29
+ | Runtime | Detection | Global install path |
30
+ |---------|-----------|---------------------|
31
+ | Claude Code | `~/.claude/` | `~/.claude/skills/twentythree/` |
32
+ | OpenAI Codex | `~/.codex/` | `~/.codex/skills/twentythree/` |
33
+ | GitHub Copilot | `~/.github/copilot/` | `~/.github/skills/twentythree/` |
34
+ | Cursor | `~/.cursor/` | `~/.cursor/skills/twentythree/` |
35
+
36
+ ## Prerequisites
37
+
38
+ The skills document the [twentythree-cli](https://www.npmjs.com/package/twentythree-cli). Install and authenticate it first:
39
+
40
+ ```bash
41
+ npm install -g twentythree-cli
42
+ twentythree auth credentials
43
+ ```
44
+
45
+ ## License
46
+
47
+ MIT
package/bin/add.js ADDED
@@ -0,0 +1,103 @@
1
+ #!/usr/bin/env node
2
+ // bin/add.js — TwentyThree Skills installer
3
+ // Node.js built-ins only. ESM. No build step. Target: < 150 lines.
4
+
5
+ import { existsSync, mkdirSync, cpSync, readdirSync } from 'node:fs'
6
+ import { join, dirname, relative } from 'node:path'
7
+ import { homedir } from 'node:os'
8
+ import { fileURLToPath } from 'node:url'
9
+
10
+ const __dirname = dirname(fileURLToPath(import.meta.url))
11
+ const skillsSource = join(__dirname, '..', 'skills')
12
+ const home = homedir()
13
+ const cwd = process.cwd()
14
+ const isProject = process.argv.includes('--project')
15
+
16
+ const RUNTIMES = [
17
+ {
18
+ name: 'Claude Code',
19
+ detect: join(home, '.claude'),
20
+ globalDest: join(home, '.claude', 'skills', 'twentythree'),
21
+ projectDest: join(cwd, '.claude', 'skills', 'twentythree'),
22
+ },
23
+ {
24
+ name: 'OpenAI Codex',
25
+ detect: join(home, '.codex'),
26
+ globalDest: join(home, '.codex', 'skills', 'twentythree'),
27
+ projectDest: join(cwd, '.agents', 'skills', 'twentythree'),
28
+ },
29
+ {
30
+ name: 'GitHub Copilot',
31
+ detect: join(home, '.github', 'copilot'),
32
+ globalDest: join(home, '.github', 'skills', 'twentythree'),
33
+ projectDest: join(cwd, '.github', 'skills', 'twentythree'),
34
+ },
35
+ {
36
+ name: 'Cursor',
37
+ detect: join(home, '.cursor'),
38
+ globalDest: join(home, '.cursor', 'skills', 'twentythree'),
39
+ projectDest: join(cwd, '.cursor', 'skills', 'twentythree'),
40
+ },
41
+ ]
42
+
43
+ function walkDir(dir) {
44
+ const files = []
45
+ for (const entry of readdirSync(dir, { withFileTypes: true })) {
46
+ if (entry.isSymbolicLink()) continue
47
+ const full = join(dir, entry.name)
48
+ if (entry.isDirectory()) {
49
+ files.push(...walkDir(full))
50
+ } else {
51
+ files.push(full)
52
+ }
53
+ }
54
+ return files
55
+ }
56
+
57
+ function shortPath(abs) {
58
+ if (abs.startsWith(home)) return '~' + abs.slice(home.length)
59
+ if (abs.startsWith(cwd + '/')) return '.' + abs.slice(cwd.length)
60
+ if (abs === cwd) return '.'
61
+ return abs
62
+ }
63
+
64
+ function installTo(destRoot, label) {
65
+ mkdirSync(destRoot, { recursive: true })
66
+ console.log(`\n${label}`)
67
+ for (const absFile of walkDir(skillsSource)) {
68
+ const rel = relative(skillsSource, absFile)
69
+ const destFile = join(destRoot, rel)
70
+ mkdirSync(dirname(destFile), { recursive: true })
71
+ try {
72
+ cpSync(absFile, destFile, { dereference: false })
73
+ console.log(` ✓ ${rel}`)
74
+ } catch (err) {
75
+ console.error(` ✗ Error installing ${rel}: ${err.message}`)
76
+ process.exitCode = 1
77
+ }
78
+ }
79
+ }
80
+
81
+ if (!existsSync(skillsSource)) {
82
+ console.error('Skills source directory not found. The package may be corrupted.')
83
+ process.exit(1)
84
+ }
85
+
86
+ const detected = RUNTIMES.filter(r => existsSync(r.detect))
87
+
88
+ if (detected.length === 0) {
89
+ const checked = RUNTIMES.map(r => shortPath(r.detect)).join(' ')
90
+ console.log('No supported agent runtime detected.\n')
91
+ console.log(`Checked: ${checked}\n`)
92
+ console.log('Install manually or see: https://www.npmjs.com/package/twentythree-skills')
93
+ process.exit(0)
94
+ }
95
+
96
+ for (const runtime of detected) {
97
+ const dest = isProject ? runtime.projectDest : runtime.globalDest
98
+ const label = `${runtime.name} (${shortPath(dest)}/)`
99
+ installTo(dest, label)
100
+ }
101
+
102
+ console.log('\nDone.')
103
+ process.exit(process.exitCode ?? 0)
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "twentythree-skills",
3
+ "version": "1.0.0",
4
+ "description": "AI agent skills for the TwentyThree CLI",
5
+ "license": "MIT",
6
+ "author": "TwentyThree",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/23/twentythree-cli.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/23/twentythree-cli/issues"
13
+ },
14
+ "homepage": "https://github.com/23/twentythree-cli#readme",
15
+ "type": "module",
16
+ "engines": {
17
+ "node": ">=22.0.0"
18
+ },
19
+ "bin": {
20
+ "twentythree-skills": "./bin/add.js"
21
+ },
22
+ "files": [
23
+ "/bin",
24
+ "/skills",
25
+ "/README.md"
26
+ ],
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "keywords": [
31
+ "ai",
32
+ "skills",
33
+ "twentythree",
34
+ "cli",
35
+ "agent",
36
+ "claude",
37
+ "claude-code",
38
+ "copilot",
39
+ "cursor",
40
+ "codex",
41
+ "ai-agent"
42
+ ],
43
+ "scripts": {
44
+ "test": "node scripts/validate-skills.mjs"
45
+ }
46
+ }
@@ -0,0 +1,211 @@
1
+ ---
2
+ name: twentythree
3
+ description: |
4
+ Full TwentyThree video platform CLI. Use when the user asks to upload or manage
5
+ videos, run webinars, query analytics, manage audiences, configure players,
6
+ create categories, manage tags, spots, thumbnails, webhooks, collectors, polls,
7
+ presentations, or any TwentyThree platform operation. Covers 235+ API commands
8
+ across 22 resource groups plus meta commands (auth, workspace, autocomplete, doctor).
9
+ Every command supports --json for machine-readable output and --agent for
10
+ self-describing metadata (api_endpoint, auth_scope, output_shape, side_effects).
11
+ triggers:
12
+ - upload video
13
+ - manage videos
14
+ - webinar
15
+ - live event
16
+ - analytics
17
+ - twentythree
18
+ - video platform
19
+ - TwentyThree CLI
20
+ invocable: true
21
+ argument-hint: "<topic> <verb> [flags]"
22
+ allowed-tools: Bash(twentythree *)
23
+ compatibility: Requires twentythree-cli installed globally (npm install -g twentythree-cli). Node.js >=22.
24
+ ---
25
+
26
+ # TwentyThree CLI
27
+
28
+ > Terminal access to the full TwentyThree video platform API — videos, webinars, analytics, audiences, and every related resource. 235+ commands across 22 resource groups.
29
+ >
30
+ > Always use `--json` in agentic contexts for structured output. Always run `twentythree <command> --agent` before calling an unfamiliar command to discover its flags, API endpoint, auth scope, and side effects.
31
+
32
+ ## Prerequisites: Authentication
33
+
34
+ Before any command, configure credentials once per workspace:
35
+
36
+ ```bash
37
+ twentythree auth credentials
38
+ ```
39
+
40
+ Prompts interactively for:
41
+ - **Domain** — your workspace domain (e.g. `company.video.twentythree.com`)
42
+ - **Bearer token** — copy from `Settings → API` inside your TwentyThree workspace admin
43
+
44
+ Credentials are stored in the OS keychain (macOS Keychain, Windows Credential Manager, Linux Secret Service) — never in plaintext files.
45
+
46
+ Verify auth is working:
47
+
48
+ ```bash
49
+ twentythree auth status
50
+ ```
51
+
52
+ ### Multi-Workspace
53
+
54
+ The CLI supports multiple workspaces simultaneously:
55
+
56
+ ```bash
57
+ twentythree workspace list # Show all configured workspaces
58
+ twentythree workspace use <domain> # Set the active workspace
59
+ twentythree <command> --workspace <domain> # One-off override for a single call
60
+ ```
61
+
62
+ ## Command Syntax
63
+
64
+ ```
65
+ twentythree <topic> <verb> [flags]
66
+ ```
67
+
68
+ Global flags available on every command:
69
+
70
+ | Flag | Purpose |
71
+ |------|---------|
72
+ | `--json` | Machine-readable JSON output — always use in agentic contexts |
73
+ | `--agent` | Return machine-readable command metadata (no API call made) |
74
+ | `--workspace <domain>` | Target a specific workspace for this call only |
75
+
76
+ ## Self-Discovery: The `--agent` Flag
77
+
78
+ Before calling any command you haven't used recently, introspect it:
79
+
80
+ ```bash
81
+ twentythree video upload --agent
82
+ ```
83
+
84
+ Returns JSON:
85
+
86
+ ```json
87
+ {
88
+ "command": "video:upload",
89
+ "description": "Upload a video file",
90
+ "flags": [
91
+ { "name": "title", "type": "option", "required": true, "description": "..." },
92
+ { "name": "category-id", "type": "option", "required": false, "description": "..." }
93
+ ],
94
+ "examples": ["twentythree video upload ./file.mp4 --title \"Demo\""],
95
+ "api_endpoint": "POST /photo/redeem-upload-token",
96
+ "auth_scope": "write",
97
+ "output_shape": { "type": "key-value" },
98
+ "side_effects": "creates"
99
+ }
100
+ ```
101
+
102
+ Key fields returned by `--agent`:
103
+
104
+ - **`api_endpoint`** — the underlying REST endpoint (note terminology mapping below)
105
+ - **`auth_scope`** — one of `anonymous`, `none`, `read`, `write`, `admin`, `super`
106
+ - **`output_shape`** — `{ type: "table", columns: [...] }`, `{ type: "key-value" }`, or `{ type: "none" }`
107
+ - **`side_effects`** — `none`, `creates`, `updates`, or `destructive`
108
+ - **`flags`** — the complete flag list with types, defaults, and required-ness
109
+
110
+ Always check `auth_scope` and `side_effects` before write/admin operations.
111
+
112
+ ## Key Invariants
113
+
114
+ - **Use `--json` in agentic contexts.** Human-formatted tables are the default; agents should always request JSON.
115
+ - **File uploads use chunked upload automatically.** Never construct multipart requests directly — `twentythree video upload <file>` handles chunking under the hood.
116
+ - **Terminology mapping** — the CLI uses product-domain names while the API uses legacy names:
117
+ - CLI `video` ↔ API `photo`
118
+ - CLI `category` ↔ API `album`
119
+ - CLI `webinar` ↔ API `live`
120
+ - The `api_endpoint` field in `--agent` output shows the actual API path.
121
+ - **After upload or create, the CLI prints the new resource ID and its admin URL.** Use the ID for follow-up updates (e.g. setting thumbnail, publishing).
122
+ - **On persistent errors, run `twentythree doctor`** to diagnose auth, connectivity, and dependency issues.
123
+
124
+ ## Resource Index
125
+
126
+ All 22 resource groups. Every topic supports `--agent`, `--json`, and `--workspace`.
127
+
128
+ | Topic | Representative verbs | Use for |
129
+ |-------|---------------------|---------|
130
+ | `video` | `upload`, `list`, `get`, `update`, `delete`, `replace`, `frame`, `transcoding-progress` | Video file management, upload, metadata, thumbnails |
131
+ | `webinar` | `create`, `list`, `get`, `update`, `delete`, `repeat`, `highlights`, `clips`, `metrics`, `log` + attachment/mail/queued-video/recording/room/section/series/speaker/transcription subtopics | Live events, scheduling, recordings, attendee comms |
132
+ | `analytics` | `conversions`, `live`, `usage`, `video` subtopics (many verbs each) | Reporting, viewer data, playback metrics, conversion tracking |
133
+ | `audience` | `list`, `create`, `get`, `update`, `delete` + segment ops | Audience segmentation and targeting |
134
+ | `category` | `list`, `create`, `get`, `update`, `delete` | Content organization (API: albums) |
135
+ | `action` | `list`, `create`, `get`, `update`, `delete` + subtypes | Interactive overlays, CTAs inside videos |
136
+ | `collector` | `list`, `create`, `delete` | Lead capture forms |
137
+ | `comment` | `list`, `create`, `get`, `update`, `delete` | Video comments moderation |
138
+ | `player` | `list`, `create`, `get`, `update`, `delete` | Player configuration and theming |
139
+ | `poll` | `list`, `create`, `get`, `update`, `delete` | In-video polls |
140
+ | `spot` | `list`, `create`, `get`, `update`, `delete` | Hotspot annotations on videos |
141
+ | `tag` | `list`, `create` | Content tagging |
142
+ | `thumbnail` | `list`, `create`, `get`, `update`, `delete` | Video thumbnail management |
143
+ | `webhook` | `list`, `create`, `get`, `update`, `delete` | Event webhooks |
144
+ | `app` | `list`, `thumbnail`, `create`, `get`, `update`, `delete` | App/integration management |
145
+ | `presentation` | `list` + page/setting subtopics | Presentation content |
146
+ | `protection` | `list`, `create`, `delete` | Access protection |
147
+ | `session` | `list`, `get` | Viewer session data |
148
+ | `setting` | `get` | Workspace settings |
149
+ | `site` | `list`, `search` | Site-level operations |
150
+ | `openupload` | `list`, `create`, `delete` | Open upload tokens |
151
+ | `user` | `list`, `create`, `get`, `update`, `delete` | User management |
152
+
153
+ ## Meta Commands
154
+
155
+ These are not in the 22 resource groups — they are CLI-local utilities:
156
+
157
+ | Topic | Commands | Purpose |
158
+ |-------|----------|---------|
159
+ | `auth` | `credentials`, `status` | Configure and verify bearer-token auth |
160
+ | `workspace` | `list`, `use` | Multi-workspace selection |
161
+ | `autocomplete` | `bash`, `zsh` | Shell completion (`twentythree autocomplete bash | source`) |
162
+ | `doctor` | (top-level: `twentythree doctor`) | Diagnose auth, connectivity, dependency issues |
163
+
164
+ ## Common Workflows
165
+
166
+ ### Upload and Publish a Video
167
+
168
+ ```bash
169
+ # 1. Upload (chunked upload is automatic)
170
+ twentythree video upload ./video.mp4 --title "Product Demo" --json
171
+ # => prints { "id": "<video-id>", "admin_url": "..." }
172
+
173
+ # 2. Assign to a category (API: album)
174
+ twentythree video update <video-id> --category-id <cat-id> --json
175
+
176
+ # 3. Set a thumbnail at second 5
177
+ twentythree thumbnail create --video-id <video-id> --time 5 --json
178
+
179
+ # 4. Publish
180
+ twentythree video update <video-id> --published 1 --json
181
+ ```
182
+
183
+ ### Webinar Setup
184
+
185
+ ```bash
186
+ # 1. Create the webinar (API: live)
187
+ twentythree webinar create --title "Q2 Kickoff" --scheduled-at "2026-05-01T14:00:00Z" --json
188
+ # => prints { "id": "<webinar-id>", "admin_url": "..." }
189
+
190
+ # 2. Fetch room URL and stream key
191
+ twentythree webinar get <webinar-id> --json
192
+
193
+ # 3. Start an associated session when the event begins
194
+ twentythree session list --webinar-id <webinar-id> --json
195
+ ```
196
+
197
+ ## Diagnostics
198
+
199
+ ```bash
200
+ twentythree doctor # Check auth, connectivity, Node version, keychain access
201
+ twentythree --version # Print CLI version
202
+ twentythree <cmd> --help # Human-readable help for any command
203
+ twentythree <cmd> --agent # Machine-readable metadata for any command (preferred for agents)
204
+ ```
205
+
206
+ If a command fails unexpectedly, in order:
207
+ 1. `twentythree auth status` — confirm credentials are present and the workspace matches
208
+ 2. `twentythree <cmd> --agent` — confirm required flags and auth scope
209
+ 3. `twentythree doctor` — catch environmental issues
210
+
211
+ See [twentythree-cli on npm](https://www.npmjs.com/package/twentythree-cli) for installation, and the GitHub repo for docs and issue reporting.
@@ -0,0 +1,233 @@
1
+ ---
2
+ name: action
3
+ description: Manage calls-to-action (CTAs) and interactive overlays on videos and webinars.
4
+ ---
5
+
6
+ # TwentyThree Action Commands
7
+
8
+ > Attach, configure, and manage interactive CTA overlays on video and webinar timelines.
9
+ > Always use `--json` in agentic contexts for structured output.
10
+
11
+ ## Prerequisites
12
+
13
+ Auth scope required: read (list, get, types), write (add, update, delete, exclude, include, upload).
14
+ Run `twentythree auth credentials` if not already configured.
15
+ Verify: `twentythree auth status --json`
16
+
17
+ > For any flag not listed here, run `twentythree action <cmd> --agent` to get the complete flag list, types, and defaults.
18
+
19
+ ## Commands
20
+
21
+ ### action list
22
+
23
+ **Auth scope:** read **Side effects:** none **Output:** table (ID, Name, Type, Start, End)
24
+
25
+ Flags:
26
+
27
+ | Flag | Required | Description |
28
+ |------|----------|-------------|
29
+ | `--object-id` | no | Object ID to filter actions by |
30
+ | `--video-id` | no | Video ID to filter actions by (maps to photo_id) |
31
+ | `--webinar-id` | no | Webinar ID to filter actions by (maps to live_id) |
32
+ | `--player-id` | no | Player ID to filter actions by |
33
+ | `--exclude-internal` | no | Exclude internal actions |
34
+ | `--exclude-pending` | no | Exclude pending actions |
35
+ | `--exclude-items` | no | Exclude action items |
36
+
37
+ ```bash
38
+ # List all actions in the workspace
39
+ twentythree action list --json
40
+
41
+ # List actions for a specific video
42
+ twentythree action list --video-id <video-id> --json
43
+ ```
44
+
45
+ ### action add
46
+
47
+ **Auth scope:** write **Side effects:** creates **Output:** key-value
48
+
49
+ Flags:
50
+
51
+ | Flag | Required | Description |
52
+ |------|----------|-------------|
53
+ | `--type` | yes | Action type (use `action types` to list valid values) |
54
+ | `--object-id` | yes | Object ID (video or webinar) to attach the action to |
55
+ | `--fields` | no | Additional fields for the action (key=value pairs) |
56
+
57
+ ```bash
58
+ # Add a basic CTA action to a video
59
+ twentythree action add --type overlay --object-id <video-id> --json
60
+
61
+ # Add a CTA with custom field values
62
+ twentythree action add --type overlay --object-id <video-id> --fields "title=Buy Now" --json
63
+ ```
64
+
65
+ ### action get
66
+
67
+ **Auth scope:** read **Side effects:** none **Output:** key-value
68
+
69
+ Flags:
70
+
71
+ | Flag | Required | Description |
72
+ |------|----------|-------------|
73
+ | `--object-id` | no | Object ID context |
74
+ | `--video-id` | no | Video ID context (maps to photo_id) |
75
+ | `--webinar-id` | no | Webinar ID context (maps to live_id) |
76
+ | `--token` | no | Object token for authentication |
77
+ | `--player-id` | no | Player ID context |
78
+ | `--exclude-internal` | no | Exclude internal actions |
79
+ | `--exclude-pending` | no | Exclude pending actions |
80
+ | `--exclude-items` | no | Exclude action items |
81
+
82
+ ```bash
83
+ # Get details of a specific action by ID
84
+ twentythree action get <action-id> --json
85
+
86
+ # Get action in the context of a video
87
+ twentythree action get <action-id> --video-id <video-id> --json
88
+ ```
89
+
90
+ ### action update
91
+
92
+ **Auth scope:** write **Side effects:** updates **Output:** key-value
93
+
94
+ Flags:
95
+
96
+ | Flag | Required | Description |
97
+ |------|----------|-------------|
98
+ | `--name` | yes | Display name for the action |
99
+ | `--start-time` | yes | Start time of the action (seconds) |
100
+ | `--end-time` | yes | End time of the action (seconds) |
101
+ | `--time-relative-to` | no | What the timing is relative to (default: duration) |
102
+ | `--return-url` | no | Return URL for the action |
103
+
104
+ ```bash
105
+ # Update action timing and name
106
+ twentythree action update <action-id> --name "Buy Now" --start-time 10 --end-time 20 --json
107
+
108
+ # Update action with a click-through URL
109
+ twentythree action update <action-id> --name "Learn More" --start-time 30 --end-time 60 --return-url "https://example.com" --json
110
+ ```
111
+
112
+ ### action delete
113
+
114
+ **Auth scope:** write **Side effects:** destructive **Output:** key-value
115
+
116
+ Flags:
117
+
118
+ | Flag | Required | Description |
119
+ |------|----------|-------------|
120
+ | (none) | — | Takes action ID as positional argument |
121
+
122
+ ```bash
123
+ # Delete a CTA action
124
+ twentythree action delete <action-id> --json
125
+
126
+ # Delete with confirmation
127
+ twentythree action delete <action-id> --json
128
+ ```
129
+
130
+ ### action types
131
+
132
+ **Auth scope:** read **Side effects:** none **Output:** table (Type, Name / Description)
133
+
134
+ Flags:
135
+
136
+ | Flag | Required | Description |
137
+ |------|----------|-------------|
138
+ | `--exclude-internal` | no | Exclude internal action types from the list |
139
+
140
+ ```bash
141
+ # List all available action types
142
+ twentythree action types --json
143
+
144
+ # List only public action types (excluding internal)
145
+ twentythree action types --exclude-internal --json
146
+ ```
147
+
148
+ ### action exclude
149
+
150
+ **Auth scope:** write **Side effects:** updates **Output:** key-value
151
+
152
+ Flags:
153
+
154
+ | Flag | Required | Description |
155
+ |------|----------|-------------|
156
+ | `--object-id` | yes | Object ID to exclude the action from |
157
+ | `--undo` | no | Remove the exclusion (reverse this operation) |
158
+
159
+ ```bash
160
+ # Exclude a CTA from a specific video
161
+ twentythree action exclude <action-id> --object-id <video-id> --json
162
+
163
+ # Undo the exclusion (re-enable the action on the video)
164
+ twentythree action exclude <action-id> --object-id <video-id> --undo --json
165
+ ```
166
+
167
+ ### action include
168
+
169
+ **Auth scope:** write **Side effects:** updates **Output:** key-value
170
+
171
+ Flags:
172
+
173
+ | Flag | Required | Description |
174
+ |------|----------|-------------|
175
+ | `--object-id` | yes | Object ID to include the action on |
176
+ | `--undo` | no | Remove the inclusion (reverse this operation) |
177
+
178
+ ```bash
179
+ # Include an action on a specific video
180
+ twentythree action include <action-id> --object-id <video-id> --json
181
+
182
+ # Undo the inclusion
183
+ twentythree action include <action-id> --object-id <video-id> --undo --json
184
+ ```
185
+
186
+ ### action upload
187
+
188
+ **Auth scope:** write **Side effects:** creates **Output:** key-value
189
+
190
+ Takes positional arguments: `<action-id> <variable> <file>` — no additional flags.
191
+
192
+ ```bash
193
+ # Upload a banner image to an action's image variable
194
+ twentythree action upload <action-id> image ./banner.png --json
195
+
196
+ # Upload a video clip to an action's video variable
197
+ twentythree action upload <action-id> video ./clip.mp4 --json
198
+ ```
199
+
200
+ ## Common Patterns
201
+
202
+ ### Discover types, create, and configure an action
203
+
204
+ ```bash
205
+ # Step 1: List available action types to find a valid type value
206
+ twentythree action types --exclude-internal --json
207
+
208
+ # Step 2: Add the action to a video using the chosen type
209
+ twentythree action add --type <type> --object-id <video-id> --fields "title=Click Here" --json
210
+
211
+ # Step 3: Update the timing on the newly created action
212
+ twentythree action update <action-id> --name "Click Here" --start-time 15 --end-time 45 --json
213
+ ```
214
+
215
+ ### Suppress a global CTA on a specific video
216
+
217
+ ```bash
218
+ # List actions to find the global action ID
219
+ twentythree action list --json
220
+
221
+ # Exclude that action from the video where it should not appear
222
+ twentythree action exclude <action-id> --object-id <video-id> --json
223
+ ```
224
+
225
+ ### Upload a custom image to an overlay action
226
+
227
+ ```bash
228
+ # First add the action
229
+ twentythree action add --type overlay --object-id <video-id> --json
230
+
231
+ # Then upload the image file to the action variable
232
+ twentythree action upload <action-id> image ./custom-banner.png --json
233
+ ```