Extends Cap’s existing deeplink system with recording control actions and adds a complete Raycast extension.
| Action | URL Example |
|---|---|
| Pause Recording | cap-desktop://action?value=%22pause_recording%22 |
| Resume Recording | cap-desktop://action?value=%22resume_recording%22 |
| Toggle Pause | cap-desktop://action?value=%22toggle_pause_recording%22 |
| Set Camera | cap-desktop://action?value={%22set_camera%22:{%22camera%22:{%22ModelID%22:%22vid:pid%22}}} |
| Set Microphone | cap-desktop://action?value={%22set_microphone%22:{%22mic_label%22:%22Mic%20Name%22}} |
All new variants are added to the existing DeepLinkAction Rust enum with serde deserialization, reusing the established cap-desktop://action?value={json} URL scheme. Each action delegates to existing public functions:
pause_recording() / resume_recording() / toggle_pause_recording() from recording.rsset_camera_input() / set_mic_input() from lib.rsZero frontend changes required — the existing TryFrom<&Url> parser automatically deserializes the new variants via serde.
apps/raycast/)8 commands built with @raycast/api:
| Command | Mode | Description |
|---|---|---|
| Start Recording | Form | Configure capture mode, camera, mic, system audio |
| Stop Recording | Instant | One-click stop |
| Pause Recording | Instant | Pause current recording |
| Resume Recording | Instant | Resume paused recording |
| Toggle Pause | Instant | Toggle pause/resume |
| Set Camera | Argument | Switch camera by model name |
| Set Microphone | Argument | Switch mic by label |
| Open Settings | Instant | Open Cap settings |
apps/desktop/src-tauri/src/deeplink_actions.rs — 5 new enum variants + execute handlersapps/raycast/ — Complete Raycast extension (8 commands, README, TypeScript types)Closes #1540
/claim #1540
Extends Cap’s deeplink system with 5 new DeepLinkAction enum variants (pause, resume, toggle-pause, set-camera, set-microphone) and adds a complete Raycast extension with 8 commands that invoke these deeplinks. The Rust-side changes are clean and follow existing patterns well.
ModelID format mismatch causes panic — The Raycast set-camera and start-recording commands pass human-readable camera names (e.g., “FaceTime HD Camera”) as ModelID, but the Rust ModelID deserializer expects a "vid:pid" format string and calls split_once(":").unwrap(), which will panic if the input lacks a colon. This affects set-camera.tsx, start-recording.tsx, and the README examples.utils.ts — The repo convention (CLAUDE.md) prohibits all code comments. utils.ts contains a JSDoc block and a single-line comment that should be removed.apps/raycast/src/set-camera.tsx and apps/raycast/src/start-recording.tsx — both pass camera names where vid:pid format is required, causing a runtime panic| Filename | Overview |
|---|---|
| apps/desktop/src-tauri/src/deeplink_actions.rs | Adds 5 new DeepLinkAction enum variants (PauseRecording, ResumeRecording, TogglePauseRecording, SetCamera, SetMicrophone) with execute handlers that correctly delegate to existing crate functions. Clean, consistent with existing patterns. |
| apps/raycast/src/utils.ts | Core deeplink URL builder with TypeScript types mirroring the Rust DeepLinkAction enum. Contains code comments that violate repo conventions. The CameraId type definition is correct but the consuming commands misuse it. |
| apps/raycast/src/set-camera.tsx | Passes user-provided camera name directly as ModelID, but Rust ModelID expects “vid:pid” format — will cause a panic (unwrap on None) when the input lacks a colon separator. |
| apps/raycast/src/start-recording.tsx | Start recording form with capture mode, camera, mic, and system audio options. Same ModelID format mismatch issue as set-camera — camera name input will panic the Rust deserializer. |
| apps/raycast/package.json | Raycast extension manifest with 8 commands. Dependencies and configuration look standard for a Raycast extension. |
| apps/raycast/README.md | Documentation with deeplink reference. Contains misleading ModelID examples that show camera names instead of the required “vid:pid” format. |
sequenceDiagram
participant R as Raycast Extension
participant OS as macOS URL Handler
participant T as Tauri Deep Link Handler
participant DL as DeepLinkAction
participant Rec as recording.rs
participant Lib as lib.rs
R->>OS: open cap-desktop://action?value=json
OS->>T: handle(urls)
T->>T: parse URL and deserialize JSON
T->>DL: action.execute(app)
alt PauseRecording / ResumeRecording / TogglePauseRecording
DL->>Rec: pause/resume/toggle recording
end
alt SetCamera
DL->>Lib: set_camera_input(app, state, camera, None)
end
alt SetMicrophone
DL->>Lib: set_mic_input(state, mic_label)
end
alt StartRecording
DL->>Lib: set_camera_input + set_mic_input
DL->>Rec: start_recording(app, state, inputs)
end
This is a comment left during a code review.
Path: apps/raycast/src/set-camera.tsx
Line: 13
Comment:
**`ModelID` expects `vid:pid` format, not a camera name**
The Rust `ModelID` deserializer at `crates/camera/src/lib.rs:144` splits on `:` with an `unwrap()`:
```rust
let (vid, pid) = s.split_once(":").unwrap();
```
If a user enters a human-readable name like "FaceTime HD Camera" (which the placeholder text `"Camera name or model"` suggests), the deeplink will produce `{"ModelID": "FaceTime HD Camera"}`. Since there's no `:` in that string, `split_once(":").unwrap()` will **panic** and crash the desktop app.
The `ModelID` type requires a vendor-ID:product-ID string (e.g., `"0x1234:0x5678"`), not a friendly camera name. Either the Raycast command should explain this format requirement to the user, or it should use `DeviceID` instead if that accepts friendly names.
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: apps/raycast/src/start-recording.tsx
Line: 44
Comment:
**Same `ModelID` panic risk as set-camera**
This line has the same issue as `set-camera.tsx`: the form placeholder says "Camera name or model" but wraps the input in `{ ModelID: values.camera }`. The Rust `ModelID` deserializer expects a `"vid:pid"` format string and will **panic** (`unwrap()` on `split_once(":")`) if the user enters a human-readable camera name like "FaceTime HD Camera".
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: apps/raycast/src/utils.ts
Line: 1-14
Comment:
**Code comments violate repo convention**
Per the project's CLAUDE.md: "CRITICAL: NO CODE COMMENTS: Never add any form of comments to code." This file contains a JSDoc block (lines 1-8) and a single-line comment on line 14 (`// Unit variants serialize as plain strings`). These should be removed — the types and function names are already self-explanatory.
**Rule Used:** CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=9a906542-f1fe-42c1-89a2-9f252d96d9f0))
How can I resolve this? If you propose a fix, please make it concise.
---
This is a comment left during a code review.
Path: apps/raycast/README.md
Line: 45
Comment:
**Misleading `ModelID` example in docs**
The example shows `"ModelID": "FaceTime HD Camera"`, but in the Rust codebase `ModelID` actually deserializes from a `"vid:pid"` format string (e.g., `"0x1234:0x5678"`). This applies to both the "Start recording" and "Switch camera" examples (lines 45 and 56). Using a friendly camera name here would crash the desktop app due to an `unwrap()` panic in the `ModelID` deserializer.
How can I resolve this? If you propose a fix, please make it concise.
Last reviewed commit: ac714dc
Greptile also left 4 inline comments on this PR.
(2/5) Greptile learns from your feedback when you react with thumbs up/down!
Context used:
qiridigital
@qiridigital
Cap
@CapSoftware
Abhishek Verma
@w3Abhishek