Skip to content

URL Scheme

Otty registers the otty:// URL scheme, so any link — a bookmark, a menu-bar launcher, a script, or text printed into the terminal — can bring Otty forward, focus a specific window, tab, or pane, or hand it a command to type.

bash
open otty://pane/$OTTY_PANE_ID     # focus the pane this shell is running in
open otty://window/current         # bring Otty's active window forward
open otty://tab/t_19f6a…           # jump to a tab by id
open "otty://run/brew%20update"    # open a tab with `brew update` typed at the prompt

The links resolve from anywhere the system can open a URL — open otty://…, a browser, a note, a Raycast/Alfred action — and they are also clickable when printed inside a pane. On Linux the handler is registered by the desktop entry Otty installs, so xdg-open otty://… and a browser click both work; on Windows Otty claims the scheme on first launch.

Targets

A URL is otty://<kind>/<selector>. The selector after the kind is exactly the one otty --window / --tab / --pane accept.

URLSelector forms
otty://window/<sel>w_<id>, or current · last · a 1-based index · title:<pattern>
otty://tab/<sel>t_<id>, or a 1-based index
otty://pane/<sel>p_<id>, or a session id such as $OTTY_PANE_ID
otty://run/<command>one shell command, percent-encoded — see Run links
otty://sync/add/<tool>a tool id from dotfiles.otty.sh

Get the ids from otty pane list (or otty tab list / otty window list). The $OTTY_PANE_ID environment variable is exported into every pane's shell, so a running command always knows its own pane.

otty://run/<command> opens a new tab and types the command at the prompt. It does not press Enter — you read the line and run it yourself, or clear it with ⌫. Nothing about the link can change that: there is no parameter that makes Otty submit a command for you.

bash
# Build one in a shell:
python3 -c "import sys,urllib.parse; print('otty://run/'+urllib.parse.quote(sys.argv[1],safe=''))" \
  'curl -fsSL https://example.com/install.sh | sh'
  • The command is the whole path, percent-encoded — in JavaScript that is 'otty://run/' + encodeURIComponent(command), and in most other languages the "encode every reserved character" variant of URL quoting. Encoding # matters most: unencoded, everything after it is dropped.
  • Send one line. Wrap a long command for display if you like, but join it back into a single line for the link — Otty accepts an embedded newline only when the shell supports bracketed paste, and refuses the link otherwise rather than risk running the first lines of a script.
  • A command carrying a carriage return, an escape character, or a text-direction override is refused outright: each of those can make the staged line behave or read differently than it looks.
  • ?where=window opens a new window instead of a tab.
  • Clicking a run link printed inside a pane always asks first, showing the decoded command. That confirmation is never remembered — terminal output is not a trusted source of links.
  • Buttons like "Run in Otty" on dotfiles.otty.sh are ordinary run links.

otty://sync/add/<tool> adds one tool from the built-in dotfiles catalog to what Data Sync carries between your machines. Otty asks before adding anything, and opens the Data tab afterwards so you can see and undo it.

Two things it will tell you rather than guess about: a tool Otty cannot find on this machine is not added (it syncs a tool's config once the tool is there), and a build without Data Sync says so instead of doing nothing.

Notes

  • The navigation links (window / tab / pane) never prompt: they only move focus, they never run a command or change your files. run and sync are the two that do something, and both stop for you first — run at your own prompt, sync at a confirmation.
  • If Otty is not running, the link launches it first, then focuses the target once a window is available.
  • An unknown or stale selector is a no-op; Otty just comes to the front.

See also

Otty