Point your agent here. It will take it from there.
Three ways to teach any agent DemoTake, each one copy and paste. Start with the skill: it holds the whole workflow in one file your agent reads before recording.
The DemoTake skill
A SKILL.md with the full record, verify, edit and export workflow. Drop it in your agent’s skills folder, or point your agent at the URL.
llms.txt
A plain-text map of every doc page, tool and API section, written for language models to read.
llms-full.txt
All of the docs and the whole MCP tool reference in one file, for agents that prefer to load everything up front.
Add DemoTake to your agent.
DemoTake runs a local MCP server on your Mac. The bundled bridge finds it and its access token on its own, so nothing secret goes into your config, and it opens DemoTake if it isn’t running. DemoTake must stay open while your agent works.
claude mcp add demotake -- /Applications/DemoTake.app/Contents/MacOS/demotake-mcp
Then ask Claude Code for a demo. Add --scope user to use DemoTake in every project.
Using DemoTake Studio from the Mac App Store? It records and edits, and your agent operates your app with its own computer-use tools. Connect your agent covers both editions.
Then just ask.
Every tool, with parameters and examples: the MCP reference.
---
name: demotake
description: Record, verify, edit and export product demo videos of Mac apps, iOS Simulator apps and web apps with DemoTake over MCP. Use when the user asks for a demo, walkthrough, screencast, tutorial video, release video, an app review video (App Store, TikTok, Meta, Google OAuth), or wants an existing demo updated after a UI change.
---
# DemoTake
DemoTake records polished, re-recordable demos. A **take** is one demo made of **scenes**: short story beats that
each end at a stable screen ("Sign in", "Create project", "Export"). Scenes are the unit of retry, edits are
non-destructive, and every export checks itself. You talk to DemoTake through its MCP tools; every stateful call
takes an explicit handle (`take_…`, `scn_…`, `exp_…`, `ast_…`, `edt_…`), never hidden session state. Both
spellings of a handle work everywhere: `scene`/`scene_id`, `target`/`target_id`, `take_id`/`take`, `job_id`/`job`.
If you are unsure about anything below, call `demotake_guide` once: it returns the workflow for the edition that
is actually running.
## 0. Before you start
1. `permissions_status`. It reports the edition (DemoTake Agent or DemoTake Studio), the version, and the macOS
permissions:
- **Screen Recording** is required to record.
- **Accessibility** is required in DemoTake Agent for `observe_state` and for operating apps.
- If one is missing, call `permissions_request {permission}` and ask the user to approve it in
System Settings › Privacy & Security. You cannot grant it yourself. Screen Recording may need DemoTake to
relaunch; the app offers that.
- `licence` says whether recording and exporting work right now (`recording_blocked`, `export_blocked`,
`blocked_reason`, trial days left; trial exports are watermarked). `licence_status` returns the same; check it
before a long recording.
2. Check `ui_control_available` in the result:
- `true` (DemoTake Agent): DemoTake can operate the app for you through Accessibility, in the background.
- `false` (DemoTake Studio): DemoTake records and edits, but you operate the app with your own computer-use
tools and report each step with `take_log_event`.
3. `targets_list` (optionally `{app: "name or bundle id"}`) and pick the window of the app you just built.
Browser windows (Chrome, Edge, Brave, Arc, Safari) carry `url`; `tabs: "all"` lists every tab's title and URL
(DemoTake Agent). To record a web app, target the tab instead of a window title, which changes with the active
tab: `target: {url_contains: "example.com"}`.
`targets_capabilities {target}` tells you how the take will run: `background_semantic` (DemoTake operates it
without touching the user's mouse), `background_capture_only` (you operate it, DemoTake records) or
`foreground_required`.
Ask the user before anything that takes over their mouse or keyboard (`allow_foreground: true`), and whenever the
flow needs credentials, 2FA or payment details. Never type real secrets you were not given for this purpose.
## 1. Plan the take
`take_create` with 2–6 scenes. Each scene has a short `title` and an `intent` (what it must show). End every
scene on a screen that proves something happened.
```json
{
"name": "Invoice export",
"goal": "Show that a signed-in user can create an invoice and export it as PDF.",
"purpose": "marketing",
"target": "window:1234",
"scenes": [
{ "title": "Sign in", "intent": "Sign in with the demo account; the dashboard is visible" },
{ "title": "Create invoice", "intent": "Create an invoice for Acme; it appears in the list" },
{ "title": "Export", "intent": "Export the invoice as PDF; the success toast shows" }
],
"outputs": ["16:9", "9:16"]
}
```
- `purpose`: `marketing` (polished), `reviewer` (App Store or OAuth review: conservative edits plus a proof
manifest), `tutorial`, or `test` (DemoTest: assertions matter most).
- Web apps: `browser: {mode: "page", address_bar: "drawn"}` records only the page area (no tab strip, toolbar or
automation infobars) and draws a clean address bar from the tab's URL (domain and path, never the query string).
See section 5.
- `outputs`: `16:9`, `9:16`, `4:3`, `1:1`, `gif`, `screenshots`, `reviewer_pack`, `guide` (a written
step-by-step guide with screenshots).
- Pass `source_commit` when you know it; it goes into the proof manifest.
- Unfamiliar app or flaky flow? `take_rehearse`, walk the flow without recording, then
`take_rehearse_finish {findings}`.
## 2. Record, scene by scene
1. Put the app in the first scene's starting state.
2. `capture_start {take_id}`. By default the first pending scene starts immediately. The window may be covered or
off to the side while recording, but it must not be minimized or on another desktop. `pointer` defaults to
`auto`: when you drive the app with another tool (`background_capture_only`), DemoTake doesn't draw its own
pointer, so the video doesn't show two cursors. Pass `pointer: "on"` to draw it anyway.
3. For each scene:
1. `take_start_scene {take_id, scene}` (skip for the first scene if capture auto-started it).
2. Act:
- **DemoTake Agent**: `observe_state` for a compact UI outline (roles, titles, `#identifiers`, normalized
frames), then `pointer_click {element: {role: "button", title: "Export"}}`,
`keyboard_type {text, element}`, `keyboard_key {keys: "cmd+s"}`, `pointer_scroll`, `ui_perform_action`.
Prefer element queries over points. Use `keyboard_type {secure: true}` for anything secret.
`observe_wait_for {text | element | idle_seconds}` instead of sleeping; waits become events that
editing can shorten later.
- **Studio, or your own computer-use tools**: after each meaningful action call
`take_log_event {take_id, kind, label, element or screen_point}` so DemoTake can place the pointer,
zoom and edit semantically. Set `redact: true` for anything secret and never put passwords in `text`.
`source` says who acted: `agent` (default), `automation` (a browser or UI automation tool you drive) or
`human`. Reviewer notes list it. `take_relabel_events` fixes events already recorded, for example clicks
DemoTake observed as human input that your automation tool made.
3. Prove it: `assert_text {take_id, text}` or `assert_element {take_id, element, title}`; use
`assert_state {title, passed, evidence}` for things you verified another way (API, database). Be honest:
assertions appear in the proof manifest.
4. `take_checkpoint {take_id, description: "Invoice list shows Acme, $1,200"}`.
4. A scene went wrong? `take_retry_scene {take_id, scene, reason}`, restore that scene's starting state, then
`take_start_scene` again. Only that scene is re-recorded; the others keep their footage and edits.
5. `capture_stop {take_id}`, then `assert_success {take_id, passed, evidence}` for the whole flow. A take whose
assertions all pass is Proof Verified.
`capture_pause` / `capture_resume` exclude time you spend fixing app state. `events_poll {after}` returns
realtime events (scene_started, assertion_failed, handoff_ended, render_progress…) if your client doesn't show MCP
notifications.
### Steps that are the person's, and slow server work
- Signing in, 2FA, pressing Allow on a consent screen: that's the user's to do, not yours.
`take_handoff {take_id, message: "Sign in to TikTok and stop at the consent screen", resume_when: {text: "wants to
access your account", timeout: 600}}` pauses the recording and shows the message inside DemoTake with a Resume
button, on top of other windows. It resumes when that text appears on the target window (on-screen text
recognition, no Accessibility needed), when the person presses Resume, or on `capture_resume`. `blur: true` keeps
recording, blurred, instead of pausing. A scene must be recording. Watch `events_poll` for `handoff_ended`
(`text_appeared`, `resumed_by_person`, `resumed_by_agent`, `timed_out`).
- Uploads and background jobs: `take_wait {take_id, resume_when: {text: "Upload complete", timeout: 300}, card: "A
moment later"}` leaves the wait out of the video and resumes when the result shows. `capture_pause
{resume_when}` does the same without the card. Don't poll with screenshots.
### iOS Simulator apps
- DemoTake Agent: boot a simulator, install and launch the app, then use the `sim:<UDID>` target from
`targets_list`. DemoTake records the device screen itself, so the Simulator window may be covered or minimized.
- DemoTake doesn't tap on devices. Drive the device with your own tools (XCUITest, `xcrun simctl`, a computer-use
agent) and log every tap with `take_log_event {kind: "click", label, point: {x, y}}` where `point` is
normalized to the device screen (0…1, top-left), or `device_point` in device points. Taps render as touch
indicators; 9:16 exports get a phone frame (`device_frame`).
- DemoTake Studio: record the Simulator window and keep it visible; the Simulator stops drawing when covered
(blank stretches are cut automatically).
## 3. Edit
Every edit is non-destructive; the recording is never modified.
1. Long or slow recording? `edit_suggest_cuts {take_id}` reviews the footage and returns a cut plan: still
stretches to shorten (each keeps `keep_seconds`, default 4 s, plus context), **protected** moments that are
never cut (assertions, checkpoints, result states), `needs_review` items (consent screens, dense text, result
screens that need reading time), `planned_duration`, and framing problems.
2. Check doubtful items with `take_frame {take_id, scene, time}` (both sides of a cut).
3. Apply the reviewed plan atomically:
```json
{
"take_id": "take_…",
"operations": [
{ "op": "accept_suggestions", "ids": ["cut_m3ehv6n0e4pa9sjt", "cut_m3ehv6n1z7gq5wkb"] },
{ "op": "reject_suggestions", "ids": ["cut_m3ehv6n2c8td4hxm"] }
]
}
```
`edit_apply` returns an `edit_id`; `edit_revert {take_id, edit_id}` undoes it, `edit_history` lists them.
Keep consent, confirmation and result screens readable: when in doubt, reject the cut.
4. Anything else in plain words: `edit_command {take_id, text: "make it 45 seconds and remove waits over 1 s"}`.
It returns what it applied and any `retry_scenes` that need re-recording.
5. Precise tools: `edit_trim`, `edit_speed`, `edit_compress_waits`, `edit_camera`, `edit_pointer`,
`edit_redact {region: {x, y, width, height}}`, or `edit_apply` with `ripple_delete`, `shorten_range`, `hold`,
`caption`, `crop_scene {scene, region}` or `{scene, fit: true}` (fixes content recorded in a corner of a mostly
black frame), `device_frame`, `background`. `timeline_get` shows scene placement, events, where each caption
lands and every sped-up or removed range; `take_contact_sheet` shows sampled frames per scene, labeled with
output times ("out 1:04.5") or, with `edited: false`, recorded times ("rec 0:12.0").
- Regions (crop, camera, redact) are `{x, y, width, height}` normalized to the recorded frame: 0…1, top-left
origin, not pixels (`w`/`h` are accepted). Anything else is rejected with an error. A crop shows exactly that
region in every format and on every frame; `camera {mode: "focus", region}` frames exactly that region.
- `edit_apply` returns small preview frames of crop, camera and caption edits (`previews`) and `warnings` when an
edit has no visible effect. Read them.
- Check the result without exporting: `preview_frame {take_id, output_time}` is the exact frame the export
draws there (crop, camera, captions, overlays, cursor, redactions); `preview_clip {take_id, start, end}` is a
small MP4 of up to 60 s to check motion.
6. Captions. `caption {scene, text, start, end}` uses scene-local **source** seconds (as recorded), mapped through
the cuts, so after cuts it can start late or end early. Prefer anchored captions, which don't move when the cut
changes and last `duration` output seconds (default 3.5): `caption {scene, text, at: "scene_start"}`,
`at: "checkpoint"` (ends with the scene) or `event_id` (+ `offset`). `captions_from_intents` adds one scene-start
caption per scene from its intent (`replace: true` redoes its own).
7. Length. `target_duration {seconds}` only speeds material up, never cuts; it avoids visible pointer movement while
it can and reports exactly which ranges it sped up (`allow_speedup: false` forbids speed-ups).
`max_still_seconds: N` (on `target_duration` or `edit_suggest_cuts`) shortens every still longer than N seconds;
readable, consent and result screens and stills under a caption keep their reading time.
8. Redact anything sensitive you see (emails, API keys, card numbers, customer names) with `edit_redact` before
exporting. Secure fields are masked automatically.
## 4. Export and verify
1. Optional: `export_preflight {take_id, format}` test-decodes every clip the cut uses.
2. `export_render {take_id, formats: ["16:9", "9:16"], wait: true}`. Each video export preflights its clips,
reads a clip that won't decode from a compatible H.264 copy (listed in `fallbacks`), and validates the finished
file before the job is marked completed. `export_cancel {job_id}` stops a render.
- For upload forms and review portals: `quality: "upload"` (H.264, 30 fps, small files) and `max_mb: 45` keep
the MP4 under a size (MB of 1,000,000 bytes; DemoTake encodes again at a lower bitrate if needed). Jobs report
`file_size_mb`, `over_limit` and `platform_limits` (TikTok app review: MP4 or MOV, at most 50 MB).
3. `export_status {take_id}` lists every export with its output path. A failed job has a `diagnosis` (scene, clip
file, source/output time, codec, error); report it to the user rather than retrying blindly.
4. `export_validate {job_id}` re-checks a finished file on demand (opens, duration, size, first/middle/last
frames decode); with `max_mb` a bigger file is invalid.
5. For reviewers: `export_manifest {take_id}` (app version, macOS version, scenes and attempts, assertion results,
video SHA-256, source commit, the edits applied) and the `reviewer_pack` output.
6. Tell the user the output paths, durations and what you cut or redacted. During the free trial, exports carry
a "Made with DemoTake" watermark; say so if the user will publish the video.
## 5. Web apps and platform review videos
TikTok, Meta, Google and Apple ask for a video that shows the app working, often with strict rules (TikTok: the
domain in the video must match the website URL in the form; MP4 or MOV, at most 50 MB).
1. `take_create {purpose: "reviewer", platform: "tiktok" | "meta_app_review" | "google_oauth" | "apple_review",
app_url: "https://example.com", scopes: ["user.info.basic", "video.upload"], target: {url_contains:
"example.com"}, browser: {mode: "page", address_bar: "drawn"}, scenes: [... {title, intent, shows_scopes}]}`.
Mark the scene that shows each scope (usually its consent screen) with `shows_scopes`. Presets caption each scene
with its intent; TikTok exports default to `quality: "upload"`, `max_mb: 45`.
2. DemoTake Agent reads the page area and URL with Accessibility. DemoTake Studio finds them with on-screen text
recognition of the toolbar: keep the address bar visible, set `browser.page_region` if the page area is off, and
log `take_log_event {kind: "navigation", url}` when the address bar can't be read.
3. Hand sign-in and consent to the person with `take_handoff`, and leave slow server work out with `take_wait`.
4. After editing and exporting: `review_check {take_id}`. It checks that the domain shown matches `app_url` and the
address bar is visible, every scope has a scene in the cut, consent screens stay on screen at least 3 s, and the
latest export's format and size (numeric limit for TikTok only). Each check is pass, fail, warn or unknown with a
fix. `checklist` is paste-ready text for the review form; give it to the user. It never changes the take.
5. Be honest in the video: no cuts that make the product look different from how it behaves. DemoTake doesn't
guarantee approval.
## 6. Share
Share links are created in the app: **Share…** on the take (Mac) or **Share** in DemoTake Web. There is a public
link (a player page, optional download and expiry), a private link with an access code, or invitations by email.
With the app signed in to DemoTake Cloud, `share_list {take_id}` lists a take's links with their embed code,
`share_embed {share_id}` returns an `<iframe>` snippet, `share_update {share_id, cta}` adds a call to action and
`share_analytics {share_id}` reports views and where viewers drop off. `interactive_share` shares an interactive
demo (section 11).
To move a take elsewhere, use `take_export_package {take_id}` (a portable `.take` zip) and
`take_import_package {path}` on the other Mac.
## 7. Keep the demo current
Demos are code:
1. `take_to_spec {take_id, path: "demotake.json"}` saves the take as a `demotake.json` spec (steps with element
queries, assertions, style and edit presets; secrets become `secret_env` references). Commit it.
2. After a UI change: `take_replay {take_id, only_changed: true}` (DemoTake Agent) re-records only the scenes
whose UI changed; unchanged scenes keep their footage and edits. `take_diff {take_id}` shows which scenes
changed (accessibility state plus a perceptual diff of each checkpoint, redactions ignored).
3. `spec_validate {path}` checks a spec; `spec_run {path, record: false}` runs it as a DemoTest (no video,
pass/fail per scene); `spec_run {path, only_changed: true}` regenerates changed scenes. Pass secrets with
`secrets: {"DEMO_PASSWORD": "…"}`; they are used for that run only and never logged.
4. In CI the same runs through the `demotake` CLI: `demotake validate`, `demotake test --junit`,
`demotake run --only-changed`.
5. On the Team plan, let DemoTake Cloud schedule it: `schedule_create {take_id, cron: "0 7 * * 1-5", webhook: true,
publish_mode: "approval"}` re-records the synced take on a timetable or after each deploy (the trigger token is in
the result once: tell the person to store it). A runner records: DemoTake Agent with "Use this Mac as a runner",
or `demotake runner` (`runner_run`) on a Mac in CI. `schedule_runs {run_id}` shows what changed, with before/after
stills; `run_approve` publishes to the take's share links (same URLs and analytics), `run_rollback` undoes it.
## 8. Store screenshots
For App Store, Google Play, Mac and web screenshots:
1. `screenshot_formats` lists the presets with exact sizes (for example `iphone-6.9` 1320×2868, `ipad-13` 2064×2752,
`mac` 2880×1800, `play-phone` 1080×1920, `og` 1200×630). Short aliases: `iphone`, `ipad`, `mac`, `app_store`,
`play`, `web`.
2. `screenshot_set_create {name, formats}` starts a set. For each screen: get the app there (the steps you'd use in a
take; in DemoTake Agent `screenshot_capture` also accepts `steps`), then `screenshot_capture {set, target | display |
rect, shot, headline, redact: true}`. During a take, `take_checkpoint {…, screenshot: true, screenshot_set,
headline}` captures the checkpoint screen too.
3. `screenshot_compose {set, formats, frame, background, headline per shot}` previews the layouts;
`screenshot_export {set}` writes one folder per store and device plus a `manifest.json`. Store outputs have no
transparency, as the stores require.
4. Keep it as code: a `screenshots` section in `demotake.json` lists the shots, their steps, captions and formats.
`screenshot_run {path, only_changed: true}`, or `demotake screenshots run demotake.json --only-changed` in CI,
regenerates only the shots whose screen changed; identical input renders identical files.
## 9. Music and study-with-me videos
- Background music for any take: `music_generate {take_id, prompt: "calm, soft Rhodes", style: "lofi"}` (instrumental,
looped, loudness-matched to −16 LUFS, dipping under narration). Your own file: `music_add {take_id, path}`.
"Lower the music under my voice" = `music_add {take_id, duck: true, duck_db: -15}`; `music_remove {take_id}`;
`edit_revert` undoes any of them.
- Hosted plans have a monthly **song** allowance (separate from AI edits; a 30-second clip is half a song) and an
hourly cap; Local uses the user's own AI key. For several tracks, call `music_generate {…, tracks: 8, dry_run: true}`
first and tell the user what it will use before generating.
- Long-form videos without a recording (Compositions): `composition_create {request: "2.5-hour study-with-me video,
45/10 pomodoro, rainy cozy room, lofi music", background_path}` builds the schedule (whole focus sessions:
2.5 h at 45/10 = 2:35:00), a timer, synthesized royalty-free chimes and chapters, and returns the music estimate
(`music: "generate"` makes the playlist). `export_render {take_id, wait: true}` writes the YouTube MP4 (1080p/4K
HEVC) plus `.chapters.txt` and `.thumbnail.jpg` next to it.
- Generated music carries an inaudible AI watermark; YouTube asks creators to disclose AI music. Don't register
generated tracks with Content ID.
## 10. Overlays and 3D
Effects drawn over the video: timers, titles, charts, callouts, confetti, your own HTML/CSS, and 3D scenes. They are
ordinary edits (each call returns an `edit_id`; `edit_revert` undoes it), render frame-exactly and export in every
format.
- `overlay_templates` lists the templates with their params and returns the authoring guide: `pomodoro-timer`
(study-with-me: `focusMinutes`, `breakMinutes`, `cycles`, `style` minimal|glass|bold, `label`), `progress-bar`,
`lower-third`, `title-card`, `callout` (x/y point), `chart` (bar|line|donut from `labels`/`values`), `counter`,
`spotlight`, `keys`, `confetti`, `end-card`.
- `overlay_add {take_id, template, params, timing, placement}`. Timing: `{start, end}` (output seconds), `{scene: "2"}`
(a whole scene, by id, title or number), or `{event: "Publish", duration: 3}` (at an event). Placement:
`{anchor: "top-right", size: 0.26}` keeps its shape in 16:9, 9:16 and 1:1; `{rect: {x, y, width, height}}` (0–1);
or full frame. Example: `overlay_add {take_id, template: "pomodoro-timer", params: {focusMinutes: 50, breakMinutes: 10},
placement: {anchor: "top-right"}}`.
- Custom: `overlay_add {take_id, html, css}`. HTML/CSS only: scripts, event handlers, iframes and remote URLs are
removed (images as `data:` URLs). Size with container units (`cqw`, `cqh`, `cqmin`). Time drives it: CSS variables
`--t` (seconds), `--p` (0–1), `--scene`, and every `@keyframes` animation is seeked to the frame. Text bindings:
`data-bind="timer.display:mm:ss"`, `counter.value:0,0`, `scene.title`, `param.<name>`. No clock, no randomness
(`data-repeat="N"` gives seeded `--r1`…`--r4` for particles). A blank or broken overlay is rejected.
- Check the result with `overlay_preview {take_id, overlay_id}` (the exact export frame as a PNG); change it with
`overlay_update {take_id, overlay_id, params | timing | placement | opacity | enabled}`; `overlay_remove` deletes it.
- 3D: `scene3d_create {take_id, preset: "spinning-logo" | "floating-screen" | "bar-columns" | "snow", text, timing}`
or a full `scene` (objects, PBR materials, lights, camera, keyframe tracks; a `recording` object puts the video on a
plane). Then `scene3d_add_object`, `scene3d_update {patch}` (merge patch; per object via `objects_by_id`),
`scene3d_animate {camera: "orbit" | "dolly" | "push-in"}` or keyframe `tracks`, `scene3d_preview`, `scene3d_remove`.
Scenes are data; nothing you send runs as code.
- Compositions: an overlay added to a Composition is drawn on it; a `pomodoro-timer` follows the composition's
schedule and replaces the built-in timer.
## 11. Voiceover, languages and interactive demos
- Voiceover: `voiceover_script {take_id}` writes one short line per scene (by DemoTake AI when it's set up). Read
the lines back and improve them with `voiceover_update {take_id, scene, text}`. `voiceover_generate {take_id}`
speaks them with the Mac's own voices (`engine: "device"`, free, offline) or DemoTake AI voices (`engine:
"hosted"`, which use the plan's voice minutes: run `dry_run: true` first and tell the user how much it will use).
The voice is never sped up: a line too long for its scene is reported; shorten it or pass `fit: true` to hold the
scene. `voiceover_update {mute_microphone: true, sync_captions: true}` silences the recorded microphone under the
voice and turns the captions into the voiceover.
- Subtitles: `export_render {…, subtitles: ["srt", "vtt"], embed_subtitles: true}`, or `export_subtitles {take_id}`
for the files alone.
- Languages: `take_languages_set {take_id, add: ["de", "ja"], glossary: ["YourApp"]}`, then `translate_take
{take_id}` (`engine: "ai"` or `"device"` on macOS 26 with the languages installed). Check the result in `take_get`
(`localization.languages[].texts`), fix lines with `translation_update`, speak each language with
`voiceover_generate {take_id, language: "de"}`, and export with `export_render {…, languages: ["source", "de",
"ja"]}`. `onscreen_text_scan` picks text on screen to show translated; blurred text is never read.
- Interactive demo: `interactive_build {take_id}` makes a click-through demo from the cut (write captions or a
voiceover first: they become the tips). `interactive_get` lists the steps, `interactive_update` edits tips and
hotspots, `interactive_export` writes an offline website (folder + ZIP), `interactive_share` returns a link and an
embed code. Step pictures come from the edited, blurred video.
## One call
`demo_create {goal, target, outputs}` plans, rehearses, records, verifies and renders on its own (Director mode).
It needs DemoTake AI and DemoTake Agent to operate the app. Prefer the primitives above when you built the feature
and know the flow.
## Troubleshooting
| Symptom | Fix |
|---|---|
| `targets_list` is empty | Screen Recording is off: `permissions_status`, then `permissions_request {permission: "screen_recording"}`. |
| Capture won't start: window minimized or on another desktop | Restore the window to the current desktop. Covered is fine. |
| Blank or black stretches (Simulator, games, video, Metal apps) | Those apps stop drawing when covered. Keep the window visible, or record the Simulator device (`sim:<UDID>`). Blank spans are cut automatically (`keep_blank_frames` keeps them). |
| An action says it needs the real mouse or keyboard | Ask the user, then retry with `allow_foreground: true`, or do the step with your own tools and `take_log_event`. |
| `pointer_click` can't find the element | `observe_state`, then match `identifier`, `title` or `text`; use `index` for duplicates. |
| An assertion fails | Don't fake it. `take_retry_scene`, fix the app state, record the scene again, or report the failure. |
| Recording or exporting is refused (trial ended) | Tell the user; a license or subscription is needed. Editing and the library keep working. |
| An export failed | Read `diagnosis` from `export_status`, try `export_preflight`, and report the scene and clip. |
| Tool not found (`pointer_click`, `spec_run`, `take_replay`) | You are connected to DemoTake Studio, which can't operate apps. Use your own tools plus `take_log_event`. |
| Two cursors in the video | Your tool draws its own cursor. `capture_start {pointer: "auto"}` (the default) leaves DemoTake's off when you drive the app; afterwards, `edit_apply {op: "pointer", personality: "invisible"}`. |
| Browser window titles keep changing, or several windows look the same | Target the tab: `{url_contains: "example.com"}`. `targets_list {tabs: "all"}` lists every tab (DemoTake Agent). |
| Tabs, toolbar or an automation infobar in the video | Record with `browser: {mode: "page", address_bar: "drawn"}`. |
| A crop or camera edit seems to do nothing | Check `warnings` in the `edit_apply` result and look with `preview_frame`. Regions are normalized 0…1, not pixels. |
| Export too big for an upload form | `export_render {quality: "upload", max_mb: 45}`. |
| The connection dropped while DemoTake restarted | The `demotake-mcp` bridge reconnects on its own (about 30 s). A tool call that was running when it dropped isn't sent again: check state (`capture_status`, `export_status`) before repeating it. |
Docs: https://demotake.my/docs · Tool reference: https://demotake.my/api · Full docs for LLMs:
https://demotake.my/llms-full.txt
Claude Code: save it as ~/.claude/skills/demotake/SKILL.md (or .claude/skills/demotake/SKILL.md in a project). Other agents: put it wherever your agent loads skills or rules. More in The DemoTake skill.