Appearance
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://pane/p_19f6a…?line=1204" # …and scroll to one line of it
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 promptThe 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.
| URL | Selector 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 · add ?line=<n> for a line deeplink |
otty://run/<command> | one shell command, percent-encoded — see Run links |
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.
Line deeplinks
A pane link can carry the row as well as the pane:
otty://pane/p_19e630f19fe_21?line=1204Open one and Otty raises that window, switches to that tab, focuses that pane, and scrolls that line into view with a brief highlight. Without ?line= the link just focuses the pane and leaves the viewport where it was.
Where one comes from:
About This Line ▸ Copy Deeplink, from a right-click in the pane, the Shell menu, or the command palette — see Shell Menu.
otty pane linkprints one, so a script or a coding agent can hand you a way back to what it is talking about:bashotty pane link # the focused pane otty pane link "$OTTY_PANE_ID" --line 1204 # one line of a specific pane otty pane link --last-command # the pane's most recent commandotty pane focus 'otty://pane/…?line=…'follows one from anywhere, which is how a deeplink works on Windows and Linux without going through the system's URL handler.otty pane focus <pane> --line <n>does the same without a URL.
line is the live absolute scrollback line — rows above the viewport plus the row itself, counted from the top of the buffer as it stands now. That is the same coordinate a shell-integration command mark reports, which is what makes a link and a command comparable.
So a deeplink is a handle on a live session, not an archive reference:
- It drifts once that pane's scrollback overflows (the default 10,000-line buffer renumbers everything) or a resize re-wraps the rows above it. Following a stale one lands near the content rather than on it.
- It means nothing after the pane closes — an unknown pane is a no-op, and Otty just comes to the front.
- A non-numeric or negative
lineis dropped rather than clamped, so the link behaves like a plain pane link instead of jumping to line 0. - On the alternate screen (vim, htop, less) there is no scrollback row to pin, so Copy Deeplink hands out a pane-only link instead of naming the wrong line.
Paste one into a chat message, a commit note, or a bug report when the thing you're talking about is on screen but 300 lines up.
Run links
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=windowopens 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.
Notes
- The navigation links (
window/tab/pane,?line=included) never prompt: they only move focus, they never run a command or change your files.runis the one that does something, and it stops at your own prompt first. - 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
- CLI Reference — the
ottycommand and its--window/--tab/--paneselectors. - Using the CLI in your Shell — scenario-oriented examples, including deep links.