sparkecoder 0.1.113 → 0.1.115

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 (106) hide show
  1. package/dist/agent/index.js +57 -1
  2. package/dist/agent/index.js.map +1 -1
  3. package/dist/cli.js +213 -2
  4. package/dist/cli.js.map +1 -1
  5. package/dist/index.js +57 -1
  6. package/dist/index.js.map +1 -1
  7. package/dist/server/index.js +57 -1
  8. package/dist/server/index.js.map +1 -1
  9. package/dist/skills/default/computer-use.md +70 -2
  10. package/dist/skills/default/recording.md +196 -0
  11. package/package.json +1 -1
  12. package/src/skills/default/computer-use.md +70 -2
  13. package/src/skills/default/recording.md +196 -0
  14. package/web/.next/BUILD_ID +1 -1
  15. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  16. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  17. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  18. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  19. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  20. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  21. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  22. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  23. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  24. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/agents.html +1 -1
  34. package/web/.next/standalone/web/.next/server/app/agents.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents/__PAGE__.segment.rsc +1 -1
  36. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p/agents.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/agents.segments/!KG1haW4p.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/agents.segments/_full.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/agents.segments/_head.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/agents.segments/_index.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/agents.segments/_tree.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  43. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +1 -1
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +1 -1
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  52. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  61. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  69. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  70. package/web/.next/standalone/web/.next/server/app/docs.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  73. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +1 -1
  74. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  78. package/web/.next/standalone/web/.next/server/app/index.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  82. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  83. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/settings.html +1 -1
  86. package/web/.next/standalone/web/.next/server/app/settings.rsc +1 -1
  87. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings/__PAGE__.segment.rsc +1 -1
  88. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p/settings.segment.rsc +1 -1
  89. package/web/.next/standalone/web/.next/server/app/settings.segments/!KG1haW4p.segment.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  91. package/web/.next/standalone/web/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  92. package/web/.next/standalone/web/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  93. package/web/.next/standalone/web/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  94. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  95. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  96. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  97. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  98. /package/web/.next/standalone/web/.next/static/{mC7Yp8aJpCL22mrYVzIEG → pSGgtxBjN5_o0YHZgQzXm}/_buildManifest.js +0 -0
  99. /package/web/.next/standalone/web/.next/static/{mC7Yp8aJpCL22mrYVzIEG → pSGgtxBjN5_o0YHZgQzXm}/_clientMiddlewareManifest.json +0 -0
  100. /package/web/.next/standalone/web/.next/static/{mC7Yp8aJpCL22mrYVzIEG → pSGgtxBjN5_o0YHZgQzXm}/_ssgManifest.js +0 -0
  101. /package/web/.next/standalone/web/.next/static/static/{mC7Yp8aJpCL22mrYVzIEG → pSGgtxBjN5_o0YHZgQzXm}/_buildManifest.js +0 -0
  102. /package/web/.next/standalone/web/.next/static/static/{mC7Yp8aJpCL22mrYVzIEG → pSGgtxBjN5_o0YHZgQzXm}/_clientMiddlewareManifest.json +0 -0
  103. /package/web/.next/standalone/web/.next/static/static/{mC7Yp8aJpCL22mrYVzIEG → pSGgtxBjN5_o0YHZgQzXm}/_ssgManifest.js +0 -0
  104. /package/web/.next/static/{mC7Yp8aJpCL22mrYVzIEG → pSGgtxBjN5_o0YHZgQzXm}/_buildManifest.js +0 -0
  105. /package/web/.next/static/{mC7Yp8aJpCL22mrYVzIEG → pSGgtxBjN5_o0YHZgQzXm}/_clientMiddlewareManifest.json +0 -0
  106. /package/web/.next/static/{mC7Yp8aJpCL22mrYVzIEG → pSGgtxBjN5_o0YHZgQzXm}/_ssgManifest.js +0 -0
@@ -6,9 +6,36 @@ platforms: ["darwin"]
6
6
 
7
7
  # Computer Use Skill
8
8
 
9
- Anthropic's `computer` tool gives Claude direct control of the actual macOS desktop. You take screenshots, then click/type/scroll at pixel coordinates anywhere on screen — Finder, Safari, native apps, anything visible. This is real desktop automation, not a sandboxed browser.
9
+ Anthropic's `computer` tool gives Claude direct control of the actual macOS desktop take screenshots, click/type/scroll at pixel coordinates, drive any app. Real desktop automation.
10
10
 
11
- For most browser work, **prefer `agent-browser` with refs from `snapshot -i`** (see the Browser Automation skill). Refs are deterministic, much cheaper in tokens, and don't depend on visual coordinates that shift between screenshots. Reach for computer use when the task involves a native macOS app, a non-browser GUI, complex visual verification, or cross-app workflows.
11
+ ## ⚠️ Computer use is the LAST RESORT read this first
12
+
13
+ Computer use is the slowest, most token-expensive, most error-prone tool you have. Almost every task you're tempted to use it for has a better alternative:
14
+
15
+ | If you're trying to … | Use this instead |
16
+ |---|---|
17
+ | Read / write / search / edit files | `read_file`, `write_file`, `bash` (`grep`, `sed`, `cat`, etc.) |
18
+ | Run a command, build, test, script | `bash` |
19
+ | Use git / npm / brew / any CLI | `bash` |
20
+ | **Anything in a web browser** | **`agent-browser` skill (`load_skill browser`)** — refs from `snapshot -i` are deterministic and ~100× cheaper in tokens than pixel-coordinate clicks |
21
+ | Look up info on the web | `web_fetch` / `web_search` |
22
+ | Call an HTTP API | `bash` (`curl`) |
23
+ | Render an HTML page, screenshot it, scrape it | `agent-browser` (`load_skill browser`) |
24
+ | Drive a Slack/Linear/Jira/etc. workflow | The integration's API via `bash` + `curl`, OR an MCP server (`load_skill manage-mcp`) |
25
+
26
+ **Decision tree**:
27
+
28
+ 1. Is there a CLI for this? → `bash`.
29
+ 2. Is it in a web browser? → `load_skill browser`, then drive `agent-browser` via refs.
30
+ 3. Is it something visible only in a native macOS GUI app with no CLI / API / accessibility shortcut? → **only now** consider computer use.
31
+
32
+ Computer use is appropriate for:
33
+ - Native macOS apps with no CLI (e.g. driving System Settings, Calculator, Finder for tasks that can't be done via `defaults`/`open`/`launchctl`).
34
+ - Complex visual verification ("does this app look right?").
35
+ - Cross-app workflows that genuinely require the desktop (drag a file from app A to app B's window).
36
+ - Demo-style tasks where the user wants to *see* the screen action.
37
+
38
+ Computer use is **NOT** appropriate for browser work — `agent-browser` snapshots + refs are deterministic, don't depend on pixel coordinates that shift between screenshots, work cross-platform (no macOS dependency), don't need Accessibility/Screen Recording permissions, and use a fraction of the tokens. Always reach for the browser skill first.
12
39
 
13
40
  ## Requirements (macOS only)
14
41
 
@@ -125,6 +152,47 @@ Coordinates are in the **logical points** of the primary display — same coordi
125
152
 
126
153
  `enable_computer_use` auto-detects the size and stores it. Always look at the most recent screenshot to find positions before clicking — windows move, apps quit, the desktop re-flows.
127
154
 
155
+ ## Record what you're doing (default ON)
156
+
157
+ Computer-use sessions are *visual* — the user can't see the screen you're driving, only your text summary. **Record almost every computer-use task** so the user can replay it. Use the built-in `sparkecoder record` helper which manages start/stop properly so the recording covers the **entire task**, not just a fixed-time window:
158
+
159
+ ```bash
160
+ # 1. At the START of the task, BEFORE your first `computer` action:
161
+ REC=$(sparkecoder record start --name "calculator-demo")
162
+ # REC is JSON: {"id":"rec-abc123","path":"~/recordings/rec-abc123-calculator-demo.mov","pid":12345}
163
+ REC_ID=$(echo "$REC" | jq -r .id)
164
+ REC_PATH=$(echo "$REC" | jq -r .path)
165
+ echo "Recording started: $REC_PATH (id=$REC_ID)"
166
+
167
+ # 2. ... do all your computer-use actions (open apps, click, type, etc.) ...
168
+
169
+ # 3. At the END (success OR failure), stop the recording:
170
+ sparkecoder record stop "$REC_ID"
171
+ # → JSON: {"id":"...","path":"...","durationSec":42,"sizeMb":18.4,"ok":true}
172
+ ```
173
+
174
+ Why use `sparkecoder record` instead of `screencapture -V 60` directly:
175
+
176
+ - `-V <seconds>` is a fixed timeout — if your task takes longer than the guess, the recording ends mid-task and you get a partial. The helper has no timeout; it records until you explicitly stop it.
177
+ - The helper tracks PIDs in state so `sparkecoder record stop-all` can clean up if something crashes.
178
+ - Works on both macOS (screencapture) and Linux (ffmpeg x11grab) with the same command.
179
+ - Returns the file path as JSON, so you can include it in your final result without guessing.
180
+
181
+ Default behavior:
182
+
183
+ - **Always record** short / visually interesting tasks (open an app, click around, drag/drop, fill a form, demos, "show me X working").
184
+ - **Always announce** before starting: "Starting a screen recording — I'll send you the file when I'm done."
185
+ - **Include the file path in your final summary** (and in your `outputSchema` if you're a worker) so the orchestrator can post the file back via Slack/whatever channel.
186
+
187
+ Skip recording when:
188
+
189
+ - The task is **long-running and boring** (e.g. "every 15 minutes for the next hour, click Refresh"). A 60-minute screen video at full resolution gets huge fast.
190
+ - The screen contains **sensitive content** the user hasn't explicitly approved recording (1Password vaults, customer dashboards, banking, private DMs). Ask first.
191
+ - The user explicitly says "no recording" or "just describe what you did."
192
+ - The task is **purely keyboard-driven CLI work** that didn't need computer-use in the first place — that should be `bash`, not `computer`.
193
+
194
+ The auto-stop flag `-V 180` (3 minutes) is a generous default that prevents runaway recordings if you crash or forget to kill the process. For longer tasks, bump it or use a separate `asciinema` recording for the terminal half.
195
+
128
196
  ## Best practices
129
197
 
130
198
  1. **Screenshot before AND after each action.** Computer use is blind without screenshots. After clicking, re-screenshot to confirm the click had the expected effect before doing the next thing.
@@ -0,0 +1,196 @@
1
+ ---
2
+ name: Recording
3
+ description: Record terminal sessions (asciinema, anywhere) or screen video (macOS / Linux with X) while a task runs so the user can replay what happened. Useful for demos, debugging visual bugs, capturing computer-use sessions, and producing evidence the task actually did what it claims.
4
+ platforms: ["darwin", "linux"]
5
+ ---
6
+
7
+ # Recording Skill
8
+
9
+ Sometimes a task is best explained by *showing* it. This skill teaches you to record a **terminal session** or **screen video** while you work, then hand the file to the user.
10
+
11
+ ## When to record
12
+
13
+ Reach for this when:
14
+
15
+ - The user explicitly asks for a recording / demo / video / proof.
16
+ - You're using **computer use** to drive the desktop and the user will want to see what you did.
17
+ - You're running a long-running command (build, test suite, deploy) and the user might want to scrub through it later.
18
+ - You're debugging a flaky visual issue — recording lets you and the user re-watch frames.
19
+
20
+ Skip recording when:
21
+
22
+ - The task is purely textual (reading/writing files, code analysis). The chat transcript already has everything.
23
+ - Recording would capture sensitive content (passwords on screen, private DMs, customer data). Ask first.
24
+
25
+ ## Screen recording — use `sparkecoder record` (preferred)
26
+
27
+ The built-in helper handles start/stop reliably so the recording covers the WHOLE task, not a fixed time window. It tracks PIDs in state, works on macOS + Linux with the same interface, and returns JSON you can parse.
28
+
29
+ ```bash
30
+ # Start: returns {id, path, pid}
31
+ REC=$(sparkecoder record start --name "calculator-demo")
32
+ REC_ID=$(echo "$REC" | jq -r .id)
33
+ REC_PATH=$(echo "$REC" | jq -r .path)
34
+
35
+ # ... do work ...
36
+
37
+ # Stop: returns {id, path, durationSec, sizeMb, ok}
38
+ sparkecoder record stop "$REC_ID"
39
+ ```
40
+
41
+ Other operations:
42
+
43
+ ```bash
44
+ sparkecoder record list # list active recordings (auto-prunes dead pids)
45
+ sparkecoder record stop-all # stop everything (cleanup)
46
+ sparkecoder record start --dir /custom/path --name my-task
47
+ ```
48
+
49
+ Storage: defaults to `~/recordings/`. Files are named `rec-<id>[-<name>].<mov|mp4>`.
50
+
51
+ ### Why not `screencapture -V N` or raw `ffmpeg` backgrounded?
52
+
53
+ You can — but you have to:
54
+ - guess the right `-V` timeout (too short = partial, too long = wasted disk),
55
+ - track the PID yourself for `kill -INT`,
56
+ - pick the right tool per OS,
57
+ - and clean up zombie processes if you crash mid-task.
58
+
59
+ `sparkecoder record` does all of that. Reach for raw `screencapture` / `ffmpeg` only if you need specific flags the helper doesn't expose (custom display, rectangle crop, audio mux).
60
+
61
+ ## Terminal recording — asciinema
62
+
63
+ `asciinema` records the **content of a terminal session** as a tiny `.cast` text file. It's a fraction of the size of video, plays in any browser via [asciinema-player](https://github.com/asciinema/asciinema-player), and the output is also greppable.
64
+
65
+ ### Install (one-time per machine)
66
+
67
+ ```bash
68
+ # macOS
69
+ brew install asciinema
70
+
71
+ # Debian / Ubuntu
72
+ sudo apt-get install -y asciinema
73
+
74
+ # Other Linux
75
+ pip install asciinema
76
+ ```
77
+
78
+ ### Record
79
+
80
+ ```bash
81
+ # Start recording; everything you type and every command output goes into the cast.
82
+ asciinema rec ~/recordings/demo-$(date +%s).cast
83
+
84
+ # Run whatever you want to demo. Then exit the recording with Ctrl-D or `exit`.
85
+
86
+ # Replay locally:
87
+ asciinema play ~/recordings/demo-1700000000.cast
88
+
89
+ # Upload to asciinema.org (public, optional):
90
+ asciinema upload ~/recordings/demo-1700000000.cast
91
+ ```
92
+
93
+ ### Non-interactive recording (script-driven)
94
+
95
+ If you (the agent) are running a sequence of commands and want to record without sitting in an interactive prompt:
96
+
97
+ ```bash
98
+ # Record a single command's output:
99
+ asciinema rec --command "bash -c 'npm test; echo exit=$?'" out.cast
100
+
101
+ # Or record into a file while a script runs:
102
+ asciinema rec --idle-time-limit 2 --title "test run $(date)" out.cast \
103
+ --command "./scripts/run-the-thing.sh"
104
+ ```
105
+
106
+ `--idle-time-limit 2` collapses dead-air pauses longer than 2s so the playback isn't boring.
107
+
108
+ ### Hand the file to the user
109
+
110
+ When you're done:
111
+
112
+ 1. Move the `.cast` to a stable path under `~/recordings/` or the session workspace.
113
+ 2. Tell the user the path. If `agent-remote-server` is configured, you can upload via the storage API and give them a signed URL — see the bash example below.
114
+ 3. Mention they can either `asciinema play <file>` locally or open the URL.
115
+
116
+ ```bash
117
+ # Optional: upload to GCS via the storage route if configured
118
+ RECORDING=~/recordings/demo-$(date +%s).cast
119
+ curl -fsS -X POST "${SPARKECODER_REMOTE_URL}/storage/upload" \
120
+ -H "Authorization: Bearer ${SPARKECODER_AUTH_KEY}" \
121
+ -F "file=@${RECORDING}" | jq .url
122
+ ```
123
+
124
+ ## Advanced: raw `screencapture` / `ffmpeg` (use only when the helper isn't enough)
125
+
126
+ Prefer `sparkecoder record` (above) for almost everything. Reach for raw tools only when you need flags the helper doesn't expose: rectangle crop, specific display, audio mux, custom frame rate.
127
+
128
+ ### Requirements
129
+
130
+ - macOS: **Screen Recording permission** for the agent's parent process. `sparkecoder check-permissions` verifies; `sparkecoder request-permissions` opens the right System Settings pane.
131
+ - Linux: `ffmpeg` installed (`sudo apt-get install -y ffmpeg`), and a running X server with the right `DISPLAY` env var.
132
+
133
+ ### macOS `screencapture` flags
134
+
135
+ ```bash
136
+ # Crop to a rectangle (x,y,w,h):
137
+ screencapture -v -R 100,100,800,600 -C ~/recordings/clip.mov
138
+
139
+ # Pick a specific display (run `system_profiler SPDisplaysDataType` to list ids):
140
+ screencapture -v -G <displayID> -C ~/recordings/clip.mov
141
+
142
+ # Auto-stop after N seconds (avoid this for task-bounded recordings; use the
143
+ # helper instead so the recording covers the whole task):
144
+ screencapture -v -V 30 -C ~/recordings/clip.mov
145
+ ```
146
+
147
+ ### Linux `ffmpeg` x11grab
148
+
149
+ ```bash
150
+ # Capture the X display (size matches the screen):
151
+ ffmpeg -y -f x11grab -framerate 25 -video_size 1920x1080 -i :0.0 \
152
+ -c:v libx264 -preset veryfast -pix_fmt yuv420p \
153
+ ~/recordings/screen-$(date +%s).mp4
154
+
155
+ # Stop with Ctrl-C or kill the ffmpeg pid.
156
+ ```
157
+
158
+ On a headless server with no X, screen recording isn't meaningful — record the terminal with `asciinema` instead.
159
+
160
+ ## Quick recipes
161
+
162
+ | You want to … | Use |
163
+ |---|---|
164
+ | Show what a computer-use task did on the desktop | `sparkecoder record start` → work → `record stop <id>` |
165
+ | Capture a CLI demo, share a link | `asciinema rec → upload` |
166
+ | Capture a single command's output verbatim | `asciinema rec --command "cmd" out.cast` |
167
+ | Debug a flaky GUI test (any OS) | `sparkecoder record start` around the test run |
168
+ | Both terminal AND screen at once | `sparkecoder record start` + `asciinema rec` in parallel |
169
+
170
+ ## Best practices
171
+
172
+ 1. **Always announce.** Before starting a recording, post a short message to the user: "Starting screen recording for the Calculator demo." So they can intervene if it'd capture something sensitive.
173
+ 2. **Use `sparkecoder record` for screen video.** It removes every footgun the raw tools have (no fixed timeout that cuts the task off mid-way, no PID juggling, no per-OS branching). Reach for raw `screencapture` / `ffmpeg` only when you need flags the helper doesn't expose (region crop, custom display, audio).
174
+ 3. **Bracket the WHOLE task.** `record start` *before* your first work command; `record stop <id>` *after* the very last one. Don't bracket each step individually — you'll lose context between clips.
175
+ 4. **Stop on exit, success OR failure.** Always run `record stop <id>` at the end of your task, even on errors. Otherwise the recorder keeps writing until `record stop-all` (or a reboot) catches it. The duration / size returned by `stop` is also useful in your final summary.
176
+ 5. **Don't record secrets.** Refuse to record if the screen contains visible passwords, 1Password vaults, customer PII, etc. Ask the user to close those windows first.
177
+ 6. **Clean up after yourself.** If a recording is no longer needed, `rm` it — videos are big.
178
+ 7. **Always mention the file in your final message.** "Recording saved to `<path>`" or, better, upload via `/storage/upload` and post the `/f/<id>` URL so Slack/etc. unfurls it inline.
179
+
180
+ ## Returning the recording in your final task summary
181
+
182
+ For a **task worker** that captured a recording, include the structured fields below in your `result` so the orchestrator can route it back to the user:
183
+
184
+ ```ts
185
+ {
186
+ "summary": "Opened Calculator, typed 2+2, hit Return. Got 4.",
187
+ "recording": {
188
+ "path": "/Users/me/recordings/rec-abc123-calculator-demo.mov",
189
+ "durationSec": 42,
190
+ "sizeMb": 18.4,
191
+ "description": "Full screen recording of the Calculator interaction"
192
+ }
193
+ }
194
+ ```
195
+
196
+ The orchestrator can then upload that path via `/storage/upload` and post the `/f/<id>` URL into Slack (or whatever channel the original request came in on) — Slack unfurls it inline as a video preview.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sparkecoder",
3
- "version": "0.1.113",
3
+ "version": "0.1.115",
4
4
  "description": "A powerful coding agent CLI with HTTP API for development environments",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -6,9 +6,36 @@ platforms: ["darwin"]
6
6
 
7
7
  # Computer Use Skill
8
8
 
9
- Anthropic's `computer` tool gives Claude direct control of the actual macOS desktop. You take screenshots, then click/type/scroll at pixel coordinates anywhere on screen — Finder, Safari, native apps, anything visible. This is real desktop automation, not a sandboxed browser.
9
+ Anthropic's `computer` tool gives Claude direct control of the actual macOS desktop take screenshots, click/type/scroll at pixel coordinates, drive any app. Real desktop automation.
10
10
 
11
- For most browser work, **prefer `agent-browser` with refs from `snapshot -i`** (see the Browser Automation skill). Refs are deterministic, much cheaper in tokens, and don't depend on visual coordinates that shift between screenshots. Reach for computer use when the task involves a native macOS app, a non-browser GUI, complex visual verification, or cross-app workflows.
11
+ ## ⚠️ Computer use is the LAST RESORT read this first
12
+
13
+ Computer use is the slowest, most token-expensive, most error-prone tool you have. Almost every task you're tempted to use it for has a better alternative:
14
+
15
+ | If you're trying to … | Use this instead |
16
+ |---|---|
17
+ | Read / write / search / edit files | `read_file`, `write_file`, `bash` (`grep`, `sed`, `cat`, etc.) |
18
+ | Run a command, build, test, script | `bash` |
19
+ | Use git / npm / brew / any CLI | `bash` |
20
+ | **Anything in a web browser** | **`agent-browser` skill (`load_skill browser`)** — refs from `snapshot -i` are deterministic and ~100× cheaper in tokens than pixel-coordinate clicks |
21
+ | Look up info on the web | `web_fetch` / `web_search` |
22
+ | Call an HTTP API | `bash` (`curl`) |
23
+ | Render an HTML page, screenshot it, scrape it | `agent-browser` (`load_skill browser`) |
24
+ | Drive a Slack/Linear/Jira/etc. workflow | The integration's API via `bash` + `curl`, OR an MCP server (`load_skill manage-mcp`) |
25
+
26
+ **Decision tree**:
27
+
28
+ 1. Is there a CLI for this? → `bash`.
29
+ 2. Is it in a web browser? → `load_skill browser`, then drive `agent-browser` via refs.
30
+ 3. Is it something visible only in a native macOS GUI app with no CLI / API / accessibility shortcut? → **only now** consider computer use.
31
+
32
+ Computer use is appropriate for:
33
+ - Native macOS apps with no CLI (e.g. driving System Settings, Calculator, Finder for tasks that can't be done via `defaults`/`open`/`launchctl`).
34
+ - Complex visual verification ("does this app look right?").
35
+ - Cross-app workflows that genuinely require the desktop (drag a file from app A to app B's window).
36
+ - Demo-style tasks where the user wants to *see* the screen action.
37
+
38
+ Computer use is **NOT** appropriate for browser work — `agent-browser` snapshots + refs are deterministic, don't depend on pixel coordinates that shift between screenshots, work cross-platform (no macOS dependency), don't need Accessibility/Screen Recording permissions, and use a fraction of the tokens. Always reach for the browser skill first.
12
39
 
13
40
  ## Requirements (macOS only)
14
41
 
@@ -125,6 +152,47 @@ Coordinates are in the **logical points** of the primary display — same coordi
125
152
 
126
153
  `enable_computer_use` auto-detects the size and stores it. Always look at the most recent screenshot to find positions before clicking — windows move, apps quit, the desktop re-flows.
127
154
 
155
+ ## Record what you're doing (default ON)
156
+
157
+ Computer-use sessions are *visual* — the user can't see the screen you're driving, only your text summary. **Record almost every computer-use task** so the user can replay it. Use the built-in `sparkecoder record` helper which manages start/stop properly so the recording covers the **entire task**, not just a fixed-time window:
158
+
159
+ ```bash
160
+ # 1. At the START of the task, BEFORE your first `computer` action:
161
+ REC=$(sparkecoder record start --name "calculator-demo")
162
+ # REC is JSON: {"id":"rec-abc123","path":"~/recordings/rec-abc123-calculator-demo.mov","pid":12345}
163
+ REC_ID=$(echo "$REC" | jq -r .id)
164
+ REC_PATH=$(echo "$REC" | jq -r .path)
165
+ echo "Recording started: $REC_PATH (id=$REC_ID)"
166
+
167
+ # 2. ... do all your computer-use actions (open apps, click, type, etc.) ...
168
+
169
+ # 3. At the END (success OR failure), stop the recording:
170
+ sparkecoder record stop "$REC_ID"
171
+ # → JSON: {"id":"...","path":"...","durationSec":42,"sizeMb":18.4,"ok":true}
172
+ ```
173
+
174
+ Why use `sparkecoder record` instead of `screencapture -V 60` directly:
175
+
176
+ - `-V <seconds>` is a fixed timeout — if your task takes longer than the guess, the recording ends mid-task and you get a partial. The helper has no timeout; it records until you explicitly stop it.
177
+ - The helper tracks PIDs in state so `sparkecoder record stop-all` can clean up if something crashes.
178
+ - Works on both macOS (screencapture) and Linux (ffmpeg x11grab) with the same command.
179
+ - Returns the file path as JSON, so you can include it in your final result without guessing.
180
+
181
+ Default behavior:
182
+
183
+ - **Always record** short / visually interesting tasks (open an app, click around, drag/drop, fill a form, demos, "show me X working").
184
+ - **Always announce** before starting: "Starting a screen recording — I'll send you the file when I'm done."
185
+ - **Include the file path in your final summary** (and in your `outputSchema` if you're a worker) so the orchestrator can post the file back via Slack/whatever channel.
186
+
187
+ Skip recording when:
188
+
189
+ - The task is **long-running and boring** (e.g. "every 15 minutes for the next hour, click Refresh"). A 60-minute screen video at full resolution gets huge fast.
190
+ - The screen contains **sensitive content** the user hasn't explicitly approved recording (1Password vaults, customer dashboards, banking, private DMs). Ask first.
191
+ - The user explicitly says "no recording" or "just describe what you did."
192
+ - The task is **purely keyboard-driven CLI work** that didn't need computer-use in the first place — that should be `bash`, not `computer`.
193
+
194
+ The auto-stop flag `-V 180` (3 minutes) is a generous default that prevents runaway recordings if you crash or forget to kill the process. For longer tasks, bump it or use a separate `asciinema` recording for the terminal half.
195
+
128
196
  ## Best practices
129
197
 
130
198
  1. **Screenshot before AND after each action.** Computer use is blind without screenshots. After clicking, re-screenshot to confirm the click had the expected effect before doing the next thing.
@@ -0,0 +1,196 @@
1
+ ---
2
+ name: Recording
3
+ description: Record terminal sessions (asciinema, anywhere) or screen video (macOS / Linux with X) while a task runs so the user can replay what happened. Useful for demos, debugging visual bugs, capturing computer-use sessions, and producing evidence the task actually did what it claims.
4
+ platforms: ["darwin", "linux"]
5
+ ---
6
+
7
+ # Recording Skill
8
+
9
+ Sometimes a task is best explained by *showing* it. This skill teaches you to record a **terminal session** or **screen video** while you work, then hand the file to the user.
10
+
11
+ ## When to record
12
+
13
+ Reach for this when:
14
+
15
+ - The user explicitly asks for a recording / demo / video / proof.
16
+ - You're using **computer use** to drive the desktop and the user will want to see what you did.
17
+ - You're running a long-running command (build, test suite, deploy) and the user might want to scrub through it later.
18
+ - You're debugging a flaky visual issue — recording lets you and the user re-watch frames.
19
+
20
+ Skip recording when:
21
+
22
+ - The task is purely textual (reading/writing files, code analysis). The chat transcript already has everything.
23
+ - Recording would capture sensitive content (passwords on screen, private DMs, customer data). Ask first.
24
+
25
+ ## Screen recording — use `sparkecoder record` (preferred)
26
+
27
+ The built-in helper handles start/stop reliably so the recording covers the WHOLE task, not a fixed time window. It tracks PIDs in state, works on macOS + Linux with the same interface, and returns JSON you can parse.
28
+
29
+ ```bash
30
+ # Start: returns {id, path, pid}
31
+ REC=$(sparkecoder record start --name "calculator-demo")
32
+ REC_ID=$(echo "$REC" | jq -r .id)
33
+ REC_PATH=$(echo "$REC" | jq -r .path)
34
+
35
+ # ... do work ...
36
+
37
+ # Stop: returns {id, path, durationSec, sizeMb, ok}
38
+ sparkecoder record stop "$REC_ID"
39
+ ```
40
+
41
+ Other operations:
42
+
43
+ ```bash
44
+ sparkecoder record list # list active recordings (auto-prunes dead pids)
45
+ sparkecoder record stop-all # stop everything (cleanup)
46
+ sparkecoder record start --dir /custom/path --name my-task
47
+ ```
48
+
49
+ Storage: defaults to `~/recordings/`. Files are named `rec-<id>[-<name>].<mov|mp4>`.
50
+
51
+ ### Why not `screencapture -V N` or raw `ffmpeg` backgrounded?
52
+
53
+ You can — but you have to:
54
+ - guess the right `-V` timeout (too short = partial, too long = wasted disk),
55
+ - track the PID yourself for `kill -INT`,
56
+ - pick the right tool per OS,
57
+ - and clean up zombie processes if you crash mid-task.
58
+
59
+ `sparkecoder record` does all of that. Reach for raw `screencapture` / `ffmpeg` only if you need specific flags the helper doesn't expose (custom display, rectangle crop, audio mux).
60
+
61
+ ## Terminal recording — asciinema
62
+
63
+ `asciinema` records the **content of a terminal session** as a tiny `.cast` text file. It's a fraction of the size of video, plays in any browser via [asciinema-player](https://github.com/asciinema/asciinema-player), and the output is also greppable.
64
+
65
+ ### Install (one-time per machine)
66
+
67
+ ```bash
68
+ # macOS
69
+ brew install asciinema
70
+
71
+ # Debian / Ubuntu
72
+ sudo apt-get install -y asciinema
73
+
74
+ # Other Linux
75
+ pip install asciinema
76
+ ```
77
+
78
+ ### Record
79
+
80
+ ```bash
81
+ # Start recording; everything you type and every command output goes into the cast.
82
+ asciinema rec ~/recordings/demo-$(date +%s).cast
83
+
84
+ # Run whatever you want to demo. Then exit the recording with Ctrl-D or `exit`.
85
+
86
+ # Replay locally:
87
+ asciinema play ~/recordings/demo-1700000000.cast
88
+
89
+ # Upload to asciinema.org (public, optional):
90
+ asciinema upload ~/recordings/demo-1700000000.cast
91
+ ```
92
+
93
+ ### Non-interactive recording (script-driven)
94
+
95
+ If you (the agent) are running a sequence of commands and want to record without sitting in an interactive prompt:
96
+
97
+ ```bash
98
+ # Record a single command's output:
99
+ asciinema rec --command "bash -c 'npm test; echo exit=$?'" out.cast
100
+
101
+ # Or record into a file while a script runs:
102
+ asciinema rec --idle-time-limit 2 --title "test run $(date)" out.cast \
103
+ --command "./scripts/run-the-thing.sh"
104
+ ```
105
+
106
+ `--idle-time-limit 2` collapses dead-air pauses longer than 2s so the playback isn't boring.
107
+
108
+ ### Hand the file to the user
109
+
110
+ When you're done:
111
+
112
+ 1. Move the `.cast` to a stable path under `~/recordings/` or the session workspace.
113
+ 2. Tell the user the path. If `agent-remote-server` is configured, you can upload via the storage API and give them a signed URL — see the bash example below.
114
+ 3. Mention they can either `asciinema play <file>` locally or open the URL.
115
+
116
+ ```bash
117
+ # Optional: upload to GCS via the storage route if configured
118
+ RECORDING=~/recordings/demo-$(date +%s).cast
119
+ curl -fsS -X POST "${SPARKECODER_REMOTE_URL}/storage/upload" \
120
+ -H "Authorization: Bearer ${SPARKECODER_AUTH_KEY}" \
121
+ -F "file=@${RECORDING}" | jq .url
122
+ ```
123
+
124
+ ## Advanced: raw `screencapture` / `ffmpeg` (use only when the helper isn't enough)
125
+
126
+ Prefer `sparkecoder record` (above) for almost everything. Reach for raw tools only when you need flags the helper doesn't expose: rectangle crop, specific display, audio mux, custom frame rate.
127
+
128
+ ### Requirements
129
+
130
+ - macOS: **Screen Recording permission** for the agent's parent process. `sparkecoder check-permissions` verifies; `sparkecoder request-permissions` opens the right System Settings pane.
131
+ - Linux: `ffmpeg` installed (`sudo apt-get install -y ffmpeg`), and a running X server with the right `DISPLAY` env var.
132
+
133
+ ### macOS `screencapture` flags
134
+
135
+ ```bash
136
+ # Crop to a rectangle (x,y,w,h):
137
+ screencapture -v -R 100,100,800,600 -C ~/recordings/clip.mov
138
+
139
+ # Pick a specific display (run `system_profiler SPDisplaysDataType` to list ids):
140
+ screencapture -v -G <displayID> -C ~/recordings/clip.mov
141
+
142
+ # Auto-stop after N seconds (avoid this for task-bounded recordings; use the
143
+ # helper instead so the recording covers the whole task):
144
+ screencapture -v -V 30 -C ~/recordings/clip.mov
145
+ ```
146
+
147
+ ### Linux `ffmpeg` x11grab
148
+
149
+ ```bash
150
+ # Capture the X display (size matches the screen):
151
+ ffmpeg -y -f x11grab -framerate 25 -video_size 1920x1080 -i :0.0 \
152
+ -c:v libx264 -preset veryfast -pix_fmt yuv420p \
153
+ ~/recordings/screen-$(date +%s).mp4
154
+
155
+ # Stop with Ctrl-C or kill the ffmpeg pid.
156
+ ```
157
+
158
+ On a headless server with no X, screen recording isn't meaningful — record the terminal with `asciinema` instead.
159
+
160
+ ## Quick recipes
161
+
162
+ | You want to … | Use |
163
+ |---|---|
164
+ | Show what a computer-use task did on the desktop | `sparkecoder record start` → work → `record stop <id>` |
165
+ | Capture a CLI demo, share a link | `asciinema rec → upload` |
166
+ | Capture a single command's output verbatim | `asciinema rec --command "cmd" out.cast` |
167
+ | Debug a flaky GUI test (any OS) | `sparkecoder record start` around the test run |
168
+ | Both terminal AND screen at once | `sparkecoder record start` + `asciinema rec` in parallel |
169
+
170
+ ## Best practices
171
+
172
+ 1. **Always announce.** Before starting a recording, post a short message to the user: "Starting screen recording for the Calculator demo." So they can intervene if it'd capture something sensitive.
173
+ 2. **Use `sparkecoder record` for screen video.** It removes every footgun the raw tools have (no fixed timeout that cuts the task off mid-way, no PID juggling, no per-OS branching). Reach for raw `screencapture` / `ffmpeg` only when you need flags the helper doesn't expose (region crop, custom display, audio).
174
+ 3. **Bracket the WHOLE task.** `record start` *before* your first work command; `record stop <id>` *after* the very last one. Don't bracket each step individually — you'll lose context between clips.
175
+ 4. **Stop on exit, success OR failure.** Always run `record stop <id>` at the end of your task, even on errors. Otherwise the recorder keeps writing until `record stop-all` (or a reboot) catches it. The duration / size returned by `stop` is also useful in your final summary.
176
+ 5. **Don't record secrets.** Refuse to record if the screen contains visible passwords, 1Password vaults, customer PII, etc. Ask the user to close those windows first.
177
+ 6. **Clean up after yourself.** If a recording is no longer needed, `rm` it — videos are big.
178
+ 7. **Always mention the file in your final message.** "Recording saved to `<path>`" or, better, upload via `/storage/upload` and post the `/f/<id>` URL so Slack/etc. unfurls it inline.
179
+
180
+ ## Returning the recording in your final task summary
181
+
182
+ For a **task worker** that captured a recording, include the structured fields below in your `result` so the orchestrator can route it back to the user:
183
+
184
+ ```ts
185
+ {
186
+ "summary": "Opened Calculator, typed 2+2, hit Return. Got 4.",
187
+ "recording": {
188
+ "path": "/Users/me/recordings/rec-abc123-calculator-demo.mov",
189
+ "durationSec": 42,
190
+ "sizeMb": 18.4,
191
+ "description": "Full screen recording of the Calculator interaction"
192
+ }
193
+ }
194
+ ```
195
+
196
+ The orchestrator can then upload that path via `/storage/upload` and post the `/f/<id>` URL into Slack (or whatever channel the original request came in on) — Slack unfurls it inline as a video preview.
@@ -1 +1 @@
1
- mC7Yp8aJpCL22mrYVzIEG
1
+ pSGgtxBjN5_o0YHZgQzXm
@@ -1 +1 @@
1
- mC7Yp8aJpCL22mrYVzIEG
1
+ pSGgtxBjN5_o0YHZgQzXm
@@ -7,8 +7,8 @@
7
7
  "static/chunks/a6dad97d9634a72d.js"
8
8
  ],
9
9
  "lowPriorityFiles": [
10
- "static/mC7Yp8aJpCL22mrYVzIEG/_ssgManifest.js",
11
- "static/mC7Yp8aJpCL22mrYVzIEG/_buildManifest.js"
10
+ "static/pSGgtxBjN5_o0YHZgQzXm/_ssgManifest.js",
11
+ "static/pSGgtxBjN5_o0YHZgQzXm/_buildManifest.js"
12
12
  ],
13
13
  "rootMainFiles": [
14
14
  "static/chunks/651e187cc15d66de.js",
@@ -367,8 +367,8 @@
367
367
  "dynamicRoutes": {},
368
368
  "notFoundRoutes": [],
369
369
  "preview": {
370
- "previewModeId": "79c2ff3b3e0e05351c87d5ce707e28a6",
371
- "previewModeSigningKey": "c1e0783b8b9f89caf7a9a27d7b457e7b897d5ad98f3e75e27d39ed1ae0f2078e",
372
- "previewModeEncryptionKey": "8bb1e0f83531b92db30d127bc55ce5b3ab0ad1a4ac2728cda33424894dec3a1b"
370
+ "previewModeId": "4d4df0b08ac51f255c1fba959eff551a",
371
+ "previewModeSigningKey": "61a87433a4783d0b199c61d12ecf05a6503595b50fb2863e5e86ea9db1544061",
372
+ "previewModeEncryptionKey": "b4d0ec3479d75253ad48871374201d5a399ead8edb8cc23a194a5b2375eddfa9"
373
373
  }
374
374
  }