caret command line
Open folders and files in Caret from any terminal, like VS Code's code.
caret # launch or focus Caret
caret . # open the current folder as the workspace
caret src/app.ts # open a file (its folder becomes the workspace when none is open)
caret -g app.ts:12:4 # open at line 12, column 4 — a bare app.ts:12:4 works too
caret -v | -h # version / help
caret serve # run Caret and serve its UI to browsers on your LAN / Tailscale (docs/REMOTE.md)-n/--new-window, -r/--reuse-window, -w/--wait and -a/--add are accepted for muscle-memory compatibility and
ignored (Caret is a single-window app and does not block). Unknown flags exit 2; a missing path prints
caret: no such file or directory and exits 1 after opening the others.
Install
Command palette → Shell Command: Install 'caret' command in PATH (also under Settings → General → Command line).
What it does, exactly what VS Code does:
- Renders
src-tauri/cli/caret.sh(embedded in the binary) with the bundle id, the app path and the version to~/.caret/bin/caret(mode 0755). - Links it as
caretfrom/usr/local/binwhen that is writable, otherwise from a user-writable directory already on your login shell's PATH (~/.local/bin,/opt/homebrew/bin,~/bin) so no password is needed. Only when none exists does macOS show the administrator dialog to link/usr/local/bin/caret(what VS Code does). Uninstall removes every such link and keeps the script.
The script is rewritten on every Caret start when its content is stale, so moving or updating the app never breaks the command. Uninstall removes the symlink and keeps the script.
How it works
The script resolves each argument to an absolute, symlink-resolved path and hands it to LaunchServices:
- plain paths →
open -b dev.caret.editor <paths…>(Apple's open-documents event; the bundle declares folders and text/source documents insrc-tauri/Info.plist), - positions →
open -b dev.caret.editor "caret://open?path=<url-encoded>&line=N&col=M"(the bundle registers thecaretURL scheme).
If the bundle is not registered yet (first run after a fresh build), it falls back to open -a <app path>.
In the app, tauri::RunEvent::Opened (src-tauri/src/core/cli.rs::on_opened) parses the URLs into
OpenRequest { path, line?, col? }, pushes them on the OpenQueue and emits caret://open-paths. The UI
(src/lib/cliOpen.ts) drains the queue — at boot and on every poke — so a cold start and a running app behave the
same: a folder becomes the workspace; a file opens in the editor, opening its folder as the workspace first when
none is open. Arguments passed directly to the binary (Caret.app/Contents/MacOS/caret .) are parsed the same way
at startup.
CARET_CLI_DRY_RUN=1 caret . a.ts:3 prints the open commands instead of running them (used by the Rust tests).
caret serve
caret serve [--host 127.0.0.1|0.0.0.0] [--port N] [--no-window] [--print-url] [paths...]Starts Caret and serves its UI to browsers (see REMOTE.md). Unlike plain caret, which hands paths to
the running app through LaunchServices, serve execs the app binary directly
(Caret.app/Contents/MacOS/caret serve …) so the URL and pairing code print in your terminal and Ctrl-C stops the
server together with the app:
Caret remote: http://192.168.1.20:17430 pairing code: 482913 (valid 5 min)
Caret remote: http://100.101.102.103:17430 pairing code: 482913 (valid 5 min)
Caret remote: http://127.0.0.1:17430 pairing code: 482913 (valid 5 min)--hostbinds127.0.0.1(default, this Mac only) or0.0.0.0(every interface: LAN and Tailscale);--portdefaults to 17430. Both overrideSettings.remotefor this process only.--no-windowhides the desktop window after start-up. The webview keeps running hidden (the relay needs it), so the window still exists; show it again from the Dock.--print-urlprints just the URL(s), one per line, without a pairing code (pair from Settings → Remote).- Any other arguments are paths and open like
caret <path>; the app's ownparse_open_argsskipsserveand its options. If Caret is already running,caret servestarts a second instance; quit the first one first.
In the app, remote::strip_serve_args (src-tauri/src/remote/mod.rs) parses the options at start-up and
remote::init starts the server during setup.
Command ids: cli.install, cli.uninstall, cli.status (hidden), cli.open (hidden; { path, line?, col? }).
Remote commands (api.remote.*) are listed in REMOTE.md.
Limitations: macOS only for now (Linux/Windows fall back to starting the binary with the paths as arguments); positions are honoured for files that exist; a brand-new file name is not created.