Hide navigation sidebar
Hide table of contents sidebar
Back to top
Toggle table of contents sidebar

# The kitty remote control protocol

The kitty remote control protocol is a simple protocol that involves sending data to kitty in the form of JSON. Any individual command of kitty has the form:

    <ESC>P@kitty-cmd<JSON object><ESC>\

Where `<ESC>` is the byte `0x1b`. The JSON object has the form:

    {
        "cmd": "command name",
        "version": "<kitty version>",
        "no_response": "<Optional Boolean>",
        "payload": "<Optional JSON object>"
    }

The `version` above is an array of the form `[0, 14, 2]`. If you are developing a standalone client, use the kitty version that you are developing against. Using a version greater than the version of the kitty instance you are talking to, will cause a failure.

Set `no_response` to `true` if you don’t want a response from kitty.

The optional payload is a JSON object that is specific to the actual command being sent. The fields in the object for every command are documented below.

As a quick example showing how easy to use this protocol is, we will implement the `@ ls` command from the shell using only shell tools.

First, run kitty as:

    kitty -o allow_remote_control=socket-only --listen-on unix:/tmp/test

Now, in a different terminal, you can get the pretty printed `@ ls` output with the following command line:

    echo -en '\eP@kitty-cmd{"cmd":"ls","version":[0,14,2]}\e\\' | socat - unix:/tmp/test | awk '{ print substr($0, 13, length($0) - 14) }' | jq -c '.data | fromjson' | jq .

## Encrypted communication

New in version 0.26.0.

When using the `remote_control_password` option communication to the terminal is encrypted to keep the password secure. A public key is used from the `KITTY_PUBLIC_KEY` environment variable. Currently, only one encryption protocol is supported. The protocol number is present in `KITTY_PUBLIC_KEY` as `1`. The key data in this environment variable is Base-85 encoded. The algorithm used is Elliptic Curve Diffie Helman with the X25519 curve. A time based nonce is used to minimise replay attacks. The original JSON command has the fields: `password` and `timestamp` added. The timestamp is the number of nanoseconds since the epoch, excluding leap seconds. Commands with a timestamp more than 5 minutes from the current time are rejected. The command is then encrypted using AES-256-GCM in authenticated encryption mode, with a symmetric key that is derived from the ECDH key-pair by running the shared secret through SHA-256 hashing, once. An IV of at least 96 bits of CSPRNG data is used. The tag for authenticated encryption must be at least 128 bits long. The tag must authenticate only the value of the `encrypted` field. A new command is created and transmitted that contains the fields:

    {
        "version": "<kitty version>",
        "iv": "base85 encoded IV",
        "tag": "base85 encoded AEAD tag",
        "pubkey": "base85 encoded ECDH public key of sender",
        "encrypted": "The original command encrypted and base85 encoded"
    }

## close-tab

Fields are:

`match (default: None)`

  Which tab to close

`no_response (default: False)`

  Boolean indicating whether to wait for a response

`self (default: False)`

  Boolean indicating whether to close the tab of the window the command is run in

`ignore_no_match (default: False)`

  Boolean indicating whether no matches should be ignored or return an error

## close-window

Fields are:

`match (default: None)`

  Which window to close

`no_response (default: False)`

  Boolean indicating whether to wait for a response

`self (default: False)`

  Boolean indicating whether to close the window the command is run in

`ignore_no_match (default: False)`

  Boolean indicating whether no matches should be ignored or return an error

## create-marker

> marker_spec/list.str: A list or arguments that define the marker specification, for example: [‘text’, ‘1’, ‘ERROR’]

Fields are:

`match (default: None)`

  Which window to create the marker in

`self (default: False)`

  Boolean indicating whether to create marker in the window the command is run in

## detach-tab

Fields are:

`match (default: None)`

  Which tab to detach

`target_tab (default: None)`

  Which tab to move the detached tab to the OS window it is run in

`self (default: False)`

  Boolean indicating whether to detach the tab the command is run in

## detach-window

Fields are:

`match (default: None)`

  Which window to detach

`target_tab (default: None)`

  Which tab to move the detached window to

`self (default: False)`

  Boolean indicating whether to detach the window the command is run in

## disable-ligatures

strategy+/choices.never.always.cursor: One of `never`, `always` or `cursor`

Fields are:

`match_window (optional)`

  Window to change opacity in

`match_tab (default: None)`

  Tab to change opacity in

`all (default: False)`

  Boolean indicating operate on all windows

## env

env+/dict.str: Dictionary of environment variables to values. Empty values cause the variable to be removed.

## focus-tab

Fields are:

`match (default: None)`

  The tab to focus

`no_response (default: False)`

  Boolean indicating whether to wait for a response

## focus-window

Fields are:

`match (default: None)`

  The window to focus

`no_response (default: False)`

  Boolean indicating whether to wait for a response

## get-colors

Fields are:

`match (default: None)`

  The window to get the colors for

`configured (default: False)`

  Boolean indicating whether to get configured or current colors

## get-text

> extent/choices.screen.first_cmd_output_on_screen.last_cmd_output.last_visited_cmd_output.all.selection: One of `screen`, `first_cmd_output_on_screen`, `last_cmd_output`, `last_visited_cmd_output`, `all`, or `selection`

Fields are:

`match (default: None)`

  The window to get text from

`ansi (default: False)`

  Boolean, if True send ANSI formatting codes

`cursor (optional)`

  Boolean, if True send cursor position/style as ANSI codes

`wrap_markers (optional)`

  Boolean, if True add wrap markers to output

`clear_selection (default: None)`

  Boolean, if True clear the selection in the matched window

`self (default: False)`

  Boolean, if True use window the command was run in

## goto-layout

Fields are:

`layout (required)`

  The new layout name

`match (default: None)`

  Which tab to change the layout of

## kitten

> args/list.str: Arguments to pass to the kitten as a list

Fields are:

`kitten (required)`

  The name of the kitten to run

`match (default: None)`

  The window to run the kitten over

## last-used-layout

Fields are:

`match (default: None)`

  Which tab to change the layout of

`all (default: False)`

  Boolean to match all tabs

`no_response (default: False)`

  Boolean indicating whether to wait for a response

## launch

args+/list.str: The command line to run in the new window, as a list, use an empty list to run the default shell

  env/list.str: List of environment variables of the form NAME=VALUE type/choices.window.tab.os-window.overlay.background.clipboard.primary: The type of window to open location/choices.first.after.before.neighbor.last.vsplit.hsplit.split.default: Where in the tab to open the new window stdin_source/choices.none.@selection.@screen.@screen_scrollback.@alternate.@alternate_scrollback. @first_cmd_output_on_screen.@last_cmd_output.@last_visited_cmd_output: Where to get stdin for the process from spacing/list.str: A list of spacing specifications, see the docs for the set-spacing command

Fields are:

`match (default: None)`

  The tab to open the new window in

`window_title (default: None)`

  Title for the new window

`cwd (default: None)`

  Working directory for the new window

`tab_title (default: None)`

  Title for the new tab

`keep_focus (default: False)`

  Boolean indicating whether the current window should retain focus or not

`copy_colors (default: False)`

  Boolean indicating whether to copy the colors from the current window

`copy_cmdline (default: False)`

  Boolean indicating whether to copy the cmdline from the current window

`copy_env (default: False)`

  Boolean indicating whether to copy the environ from the current window

`hold (default: False)`

  Boolean indicating whether to keep window open after cmd exits

`allow_remote_control (default: False)`

  Boolean indicating whether to allow remote control from the new window

`remote_control_password (default: [])`

  A list of remote control passwords

`stdin_add_formatting (default: False)`

  Boolean indicating whether to add formatting codes to stdin

`stdin_add_line_wrap_markers (default: False)`

  Boolean indicating whether to add line wrap markers to stdin

`no_response (default: False)`

  Boolean indicating whether to send back the window id

`marker (default: None)`

  Specification for marker for new window, for example: “text 1 ERROR”

`logo (default: None)`

  Path to window logo

`logo_position (default: None)`

  Window logo position as string or empty string to use default

`logo_alpha (default: -1.0)`

  Window logo alpha or -1 to use default

`self (default: False)`

  Boolean, if True use tab the command was run in

## ls

Fields are:

`all_env_vars (default: False)`

  Whether to send all environment variables for every window rather than just differing ones

## new-window

args+/list.str: The command line to run in the new window, as a list, use an empty list to run the default shell

  window_type/choices.kitty.os: One of `kitty` or `os`

Fields are:

`match (default: None)`

  The tab to open the new window in

`title (default: None)`

  Title for the new window

`cwd (default: None)`

  Working directory for the new window

`keep_focus (default: False)`

  Boolean indicating whether the current window should retain focus or not

`new_tab (default: False)`

  Boolean indicating whether to open a new tab

`tab_title (default: None)`

  Title for the new tab

`no_response (default: False)`

  Boolean indicating whether to send back the window id

## remove-marker

Fields are:

`match (default: None)`

  Which window to remove the marker from

`self (default: False)`

  Boolean indicating whether to detach the window the command is run in

## resize-os-window

> action/choices.resize.toggle-fullscreen.toggle-maximized: One of `resize, toggle-fullscreen` or `toggle-maximized` unit/choices.cells.pixels: One of `cells` or `pixels`

Fields are:

`match (default: None)`

  Which window to resize

`self (default: False)`

  Boolean indicating whether to close the window the command is run in

`incremental (default: False)`

  Boolean indicating whether to adjust the size incrementally

`width (default: 0)`

  Integer indicating desired window width

`height (default: 0)`

  Integer indicating desired window height

## resize-window

> axis/choices.horizontal.vertical.reset: One of `horizontal, vertical` or `reset`

Fields are:

`match (default: None)`

  Which window to resize

`self (default: False)`

  Boolean indicating whether to resize the window the command is run in

`increment (default: 2)`

  Integer specifying the resize increment

## scroll-window

amount+/list.scroll_amount: The amount to scroll, a two item list with the first item being either a number or the keywords, start and end. And the second item being either ‘p’ for pages or ‘l’ for lines or ‘u’

  for unscrolling by lines.

Fields are:

`match (default: None)`

  The window to scroll

`no_response (default: False)`

  Boolean indicating whether to wait for a response

## select-window

Fields are:

`match (default: None)`

  The tab to open the new window in

`self (default: False)`

  Boolean, if True use tab the command was run in

`title (default: None)`

  A title for this selection

`exclude_active (default: False)`

  Exclude the currently active window from the list to pick

`reactivate_prev_tab (default: False)`

  Reactivate the previously activated tab when finished

## send-text

Fields are:

`data (required)`

  The data being sent. Can be either: text: followed by text or base64: followed by standard base64 encoded bytes

`match (default: None)`

  A string indicating the window to send text to

`match_tab (default: None)`

  A string indicating the tab to send text to

`all (default: False)`

  A boolean indicating all windows should be matched.

`exclude_active (default: False)`

  A boolean that prevents sending text to the active window

`session_id (optional)`

  A string that identifies a “broadcast session”

## set-background-opacity

Fields are:

`opacity (required)`

  A number between 0.1 and 1

`match_window (optional)`

  Window to change opacity in

`match_tab (default: None)`

  Tab to change opacity in

`all (default: False)`

  Boolean indicating operate on all windows

## set-colors

colors+/dict.colors: An object mapping names to colors as 24-bit RGB integers or null for nullable colors

Fields are:

`match_window (optional)`

  Window to change colors in

`match_tab (default: None)`

  Tab to change colors in

`all (default: False)`

  Boolean indicating change colors everywhere or not

`configured (default: False)`

  Boolean indicating whether to change the configured colors. Must be True if reset is True

`reset (default: False)`

  Boolean indicating colors should be reset to startup values

## set-enabled-layouts

layouts+/list.str: The list of layout names

Fields are:

`match (default: None)`

  Which tab to change the layout of

`configured (default: False)`

  Boolean indicating whether to change the configured value

## set-font-size

> increment_op/choices.+.-: The string `+` or `-` to interpret size as an increment

Fields are:

`size (required)`

  The new font size in pts (a positive number)

`all (default: False)`

  Boolean whether to change font size in the current window or all windows

## set-spacing

settings+/dict.spacing: An object mapping margins/paddings using canonical form {‘margin-top’: 50, ‘padding-left’: null} etc

Fields are:

`match_window (optional)`

  Window to change paddings and margins in

`match_tab (default: None)`

  Tab to change paddings and margins in

`all (default: False)`

  Boolean indicating change paddings and margins everywhere or not

`configured (default: False)`

  Boolean indicating whether to change the configured paddings and margins. Must be True if reset is True

## set-tab-color

colors+/dict.colors: An object mapping names to colors as 24-bit RGB integers. A color value of null indicates it should be unset.

Fields are:

`match (default: None)`

  Which tab to change the color of

`self (default: False)`

  Boolean indicating whether to use the tab of the window the command is run in

## set-tab-title

Fields are:

`title (required)`

  The new title

`match (default: None)`

  Which tab to change the title of

## set-window-logo

Fields are:

`data (required)`

  Chunk of at most 512 bytes of PNG data, base64 encoded. Must send an empty chunk to indicate end of image. Or the special value `-` to indicate image must be removed.

`position (default: None)`

  The logo position as a string, empty string means default

`alpha (default: -1.0)`

  The logo alpha between `0` and `1`. `-1` means use default

`match (default: None)`

  Which window to change the logo in

`self (default: False)`

  Boolean indicating whether to act on the window the command is run in

## set-window-title

Fields are:

`title (optional)`

  The new title

`match (default: None)`

  Which windows to change the title in

`temporary (default: False)`

  Boolean indicating if the change is temporary or permanent

## signal-child

signals/list.str: The signals, a list of names, such as `SIGTERM`, `SIGKILL`, `SIGUSR1`, etc.

Fields are:

`match (default: None)`

  Which windows to send the signals to

`no_response (default: False)`

  Boolean indicating whether to wait for a response