Kitty's remote control system allows external programs to control kitty terminal instances through a JSON-based protocol. This enables programmatic control over windows, tabs, colors, text, and more.
Source References:
Remote control must be explicitly enabled. There are three methods:
kitty --allow-remote-controlallow_remote_control yes
kitty --listen-on unix:/tmp/mykittyThen connect from any terminal:
kitten @ --to unix:/tmp/mykitty lsremote_control_password "mypassword" *
Commands are sent as JSON wrapped in escape sequences:
<ESC>P@kitty-cmd<JSON><ESC>\
Where <ESC> is byte 0x1b.
{
"cmd": "command_name",
"version": [0, 14, 2],
"no_response": false,
"payload": { ... }
}| Field | Description |
|---|---|
cmd |
The command name (e.g., ls, send-text, launch) |
version |
Array [major, minor, patch] of kitty version you're targeting |
no_response |
Set true to skip waiting for response |
payload |
Command-specific JSON object |
# Start kitty with socket
kitty --listen-on unix:/tmp/mykitty &
# Send ls command via raw protocol
printf '\x1bP@kitty-cmd{"cmd":"ls","version":[0,14,2]}\x1b\\' | socat - UNIX-CONNECT:/tmp/mykittyWhen using remote_control_password, communication is encrypted using:
- Key Exchange: Elliptic Curve Diffie-Hellman (X25519)
- Encryption: AES-256-GCM with authenticated encryption
- Key Data: Base-85 encoded in
KITTY_PUBLIC_KEYenvironment variable - Nonce: Time-based (commands >5 minutes old are rejected)
Encrypted command structure:
{
"encrypted": "<base64 encrypted data>",
"iv": "<base64 IV>",
"tag": "<base64 auth tag>",
"pubkey": "<base64 client public key>"
}For commands requiring user interaction (e.g., select-window):
{
"cmd": "select-window",
"version": [0, 14, 2],
"async": "unique-random-id",
"payload": { ... }
}Cancel with:
{
"cancel_async": "unique-random-id"
}For large data transfers (e.g., set-background-image):
{
"cmd": "set-background-image",
"version": [0, 14, 2],
"stream": true,
"stream_id": "unique-stream-id",
"payload": { "data": "<chunk>" }
}Send empty chunk to signal end of stream.
List all OS windows, tabs, and windows as a JSON tree.
kitten @ lsPayload fields:
| Field | Default | Description |
|---|---|---|
all_env_vars |
false |
Include all environment variables |
match |
None |
Window match expression |
match_tab |
None |
Tab match expression |
self |
false |
Only list current window |
output_format |
json |
Output format: json or session |
Get text from a window's screen or scrollback.
kitten @ get-text --match id:1Payload fields:
| Field | Default | Description |
|---|---|---|
match |
None |
Window to get text from |
extent |
screen |
One of: screen, all, selection, first_cmd_output_on_screen, last_cmd_output, last_visited_cmd_output |
ansi |
false |
Include ANSI formatting codes |
cursor |
None |
Include cursor position/style |
wrap_markers |
None |
Add wrap markers |
clear_selection |
false |
Clear selection after getting |
self |
false |
Use current window |
Create new windows, tabs, or OS windows.
kitten @ launch --type=tab --title="My Tab" bashPayload fields:
| Field | Default | Description |
|---|---|---|
args |
[] |
Command line as array |
type |
window |
One of: window, tab, os-window, overlay, overlay-main, background |
match |
None |
Tab to open window in |
window_title |
None |
Window title |
tab_title |
None |
Tab title |
cwd |
None |
Working directory |
env |
[] |
Environment variables (NAME=VALUE) |
keep_focus |
false |
Don't switch focus to new window |
hold |
false |
Keep window open after command exits |
location |
default |
Position in tab layout |
copy_colors |
false |
Copy colors from source window |
copy_env |
[] |
Copy environment from source |
Returns: Window ID of newly created window.
Close a window.
kitten @ close-window --match id:1Focus a specific window.
kitten @ focus-window --match title:vimResize a window.
kitten @ resize-window --increment 2 --axis horizontalSend text to a window's terminal.
kitten @ send-text --match id:1 "Hello, World\n"Payload fields:
| Field | Default | Description |
|---|---|---|
data |
required | Text as text:... or base64:... |
match |
None |
Target window |
match_tab |
None |
Target tab |
all |
false |
Send to all windows |
exclude_active |
false |
Skip active window |
bracketed_paste |
disable |
Wrap in bracketed paste codes |
session_id |
None |
Broadcast session identifier |
Send key presses to a window.
kitten @ send-key --match id:1 ctrl+cPayload fields:
| Field | Default | Description |
|---|---|---|
keys |
required | List of key names |
match |
None |
Target window |
all |
false |
Send to all windows |
Change terminal colors dynamically.
kitten @ set-colors foreground=white background=blackPayload fields:
| Field | Default | Description |
|---|---|---|
colors |
required | Object mapping color names to RGB integers |
match_window |
None |
Target window |
match_tab |
None |
Target tab |
all |
false |
Apply everywhere |
configured |
false |
Change configured colors |
reset |
false |
Reset to startup values |
Set window background image.
kitten @ set-background-image /path/to/image.pngPayload fields:
| Field | Default | Description |
|---|---|---|
data |
required | Base64 PNG chunks (max 512 bytes each) or - to remove |
match |
None |
Target window |
layout |
configured |
Image layout |
all |
false |
Apply to all windows |
Set window margins and padding.
kitten @ set-spacing margin=20 padding-left=10Send signals to child processes.
kitten @ signal-child --match id:1 SIGTERMPayload fields:
| Field | Default | Description |
|---|---|---|
signals |
required | List of signal names (e.g., SIGTERM, SIGKILL) |
match |
None |
Target windows |
Run a command and capture output.
kitten @ run ls -laHighlight text patterns in a window.
kitten @ create-marker --match id:1 text 1 ERRORRemove markers from a window.
kitten @ remove-marker --match id:1Reload configuration.
kitten @ load-configPayload fields:
| Field | Default | Description |
|---|---|---|
paths |
[] |
Config file paths to load |
override |
[] |
Individual config overrides |
ignore_overrides |
false |
Skip previous overrides |
Set environment variables for future child processes.
kitten @ env MY_VAR=valueThe --match and --match-tab options use a powerful query syntax:
field:query
| Field | Type | Description |
|---|---|---|
id |
numeric | Window ID (negative counts from newest: -1 = most recent) |
title |
regex | Window title |
pid |
numeric | Process ID |
cwd |
regex | Current working directory |
cmdline |
regex | Command line of running process |
num |
numeric | Window position in tab (0-indexed, clockwise from top-left) |
env |
regex | Environment variables (format: VAR=value) |
var |
regex | User variables |
state |
enum | Window state (see below) |
neighbor |
enum | Neighbor direction: left, right, top, bottom |
session |
regex | Session name |
recent |
numeric | Recently active (0 = current, 1 = previous, ...) |
| State | Description |
|---|---|
active |
Active window in its parent tab |
focused |
The window receiving keyboard input |
needs_attention |
Window requesting attention |
parent_active |
Window's tab is active |
parent_focused |
Window's tab is focused |
focused_os_window |
All windows in focused OS window |
self |
Window where command is run |
overlay_parent |
Window under an overlay |
Combine conditions with:
and- Both must matchor- Either must matchnot- Negate condition
# Match by ID
kitten @ focus-window --match id:1
# Match by title regex
kitten @ send-text --match title:vim "Hello"
# Match by command line
kitten @ close-window --match cmdline:python
# Match neighbor
kitten @ focus-window --match neighbor:left
# Match by state
kitten @ ls --match state:focused
# Boolean combination
kitten @ focus-window --match "title:vim and state:active"
# Match all windows
kitten @ send-text --match all "broadcast message"
# Recent window
kitten @ focus-window --match recent:1Kitty Instance (singleton)
└── OS Windows (operating system windows)
└── Tabs (groups of kitty windows)
└── Windows (terminal panes)
├── Screen (visible content)
├── Scrollback buffer
└── Child process
An OS Window is a native operating system window. Each kitty process can have multiple OS windows.
Key Properties:
| Property | Description |
|---|---|
id |
Unique numeric identifier |
is_focused |
Whether this OS window has focus |
is_active |
Whether this is the active OS window |
platform_window_id |
Native window ID (X11/Wayland/macOS) |
tabs |
List of tabs in this OS window |
background_opacity |
Window opacity (0.0-1.0) |
A Tab contains one or more kitty windows arranged in a layout.
Key Properties:
| Property | Description |
|---|---|
id |
Unique numeric identifier |
title |
Tab title (usually from active window) |
is_focused |
Whether this tab is focused |
is_active |
Whether this tab is active |
layout |
Current layout name (tall, grid, splits, etc.) |
layout_opts |
Layout-specific options |
enabled_layouts |
List of available layouts |
windows |
List of windows in this tab |
groups |
Window groupings |
active_window_history |
Stack of recently active window IDs |
A Window is a single terminal pane running a child process.
Key Properties:
| Property | Description |
|---|---|
id |
Unique numeric identifier |
title |
Window title |
is_focused |
Whether this window is focused |
is_active |
Whether this window is active in its tab |
is_self |
Whether this is the window running the command |
pid |
Process ID of child |
cwd |
Current working directory |
cmdline |
Command line of running process |
env |
Environment variables (diff from parent) |
columns |
Terminal width in columns |
lines |
Terminal height in lines |
at_prompt |
Whether shell is at prompt (requires shell integration) |
created_at |
Creation timestamp |
foreground_processes |
List of foreground process info |
A Layout arranges windows within a tab. Available layouts:
| Layout | Description |
|---|---|
tall |
Main window left, others stacked right |
fat |
Main window top, others side-by-side bottom |
grid |
Windows in a grid |
horizontal |
All windows side-by-side |
vertical |
All windows stacked |
splits |
Arbitrary horizontal/vertical splits |
stack |
Only active window visible (others hidden) |
[
{
"id": 1,
"is_focused": true,
"is_active": true,
"platform_window_id": 25176,
"background_opacity": 1.0,
"tabs": [
{
"id": 1,
"title": "fish - ~/projects",
"is_focused": true,
"is_active": true,
"layout": "tall",
"layout_opts": {
"bias": 50,
"full_size": 1,
"mirrored": "n"
},
"enabled_layouts": ["tall:bias=50", "fat:bias=50", "grid", "splits"],
"active_window_history": [1, 2],
"windows": [
{
"id": 1,
"title": "fish",
"is_focused": true,
"is_active": true,
"is_self": true,
"pid": 12345,
"cwd": "/Users/alice/projects",
"cmdline": ["/opt/homebrew/bin/fish"],
"columns": 120,
"lines": 40,
"at_prompt": true,
"env": {
"KITTY_WINDOW_ID": "1"
},
"foreground_processes": [
{
"pid": 12345,
"cwd": "/Users/alice/projects",
"cmdline": ["fish"]
}
]
}
]
}
]
}
]| Variable | Description |
|---|---|
KITTY_WINDOW_ID |
Current window's numeric ID |
KITTY_PID |
Kitty process ID |
KITTY_PUBLIC_KEY |
Public key for encrypted remote control |
KITTY_LISTEN_ON |
Socket path (when enabled) |
TERM |
Terminal type (xterm-kitty) |
TERMINFO |
Path to terminfo database |
COLORTERM |
Set to truecolor |
| Variable | Description |
|---|---|
KITTY_CONFIG_DIRECTORY |
Config file location |
KITTY_CACHE_DIRECTORY |
Cache directory |
KITTY_RC_PASSWORD |
Remote control password |
Create Python scripts that respond to window events.
- Create
~/.config/kitty/mywatcher.py:
def on_resize(boss, window, data):
# Called when window is resized
pass
def on_focus_change(boss, window, data):
# Called when focus changes
pass
def on_close(boss, window, data):
# Called when window closes
pass
def on_set_user_var(boss, window, data):
# Called when user variable is set
pass
def on_title_change(boss, window, data):
# Called when title changes
pass
def on_cmd_startstop(boss, window, data):
# Called when command starts/stops (requires shell integration)
pass- Launch with watcher:
kitten @ launch --watcher mywatcher.pyOr set global watcher in kitty.conf:
watcher mywatcher.py
def on_focus_change(boss, window, data):
boss.call_remote_control(window, ('set-colors', '--match', f'id:{window.id}', 'background=#000000'))# Launch window, run command, get output
win_id=$(kitten @ launch --type=window --keep-focus --hold -- sh -c 'your_command')
sleep 1
kitten @ get-text --match "id:$win_id"
kitten @ close-window --match "id:$win_id"kitten @ send-text --all "Message to all windows\n"# Dark mode
kitten @ set-colors --all background=#1a1a2e foreground=#eaeaea
# Light mode
kitten @ set-colors --all background=#ffffff foreground=#1a1a1a#!/bin/bash
# Create development layout
# Launch editor in main window
editor_id=$(kitten @ launch --type=tab --title="Editor" nvim)
# Launch terminal below
term_id=$(kitten @ launch --type=window --location=hsplit fish)
# Launch log viewer on right
log_id=$(kitten @ launch --type=window --location=vsplit tail -f /var/log/app.log)# Check if socket exists
if [ -S /tmp/myproject-kitty ]; then
kitten @ --to unix:/tmp/myproject-kitty focus-window
else
kitty --listen-on unix:/tmp/myproject-kitty --session ~/.config/kitty/sessions/myproject.session &
fi| Feature | tmux Control Mode | Kitty Remote Control |
|---|---|---|
| Protocol | Line-based text | JSON over escape sequences |
| Activation | tmux -C flag |
Config option or socket |
| Security | None built-in | Password-based with encryption |
| Streaming | Output notifications | Chunked streaming with stream_id |
| Object model | Sessions → Windows → Panes | OS Windows → Tabs → Windows |
| Matching | Window/pane IDs | Rich query DSL with regex |
| Events | Push notifications (%output, etc.) |
Python watchers |
- Version compatibility: Always specify a
versionarray matching or below the target kitty version - Handle async: Some commands (like
select-window) require async handling with unique IDs - Streaming large data: Use
streamandstream_idfor large payloads, send empty chunk to end - Encryption: When using passwords, implement ECDH key exchange and AES-256-GCM encryption
- Time sensitivity: Encrypted commands have a 5-minute validity window
- Match syntax: Use the query DSL for flexible window targeting
- Environment detection: Check
KITTY_WINDOW_IDto detect if running inside kitty
# List everything
kitten @ ls
# Get text from screen
kitten @ get-text --extent screen
# Send text to window
kitten @ send-text --match id:1 "Hello\n"
# Create new tab
kitten @ launch --type=tab --cwd current
# Focus window by title
kitten @ focus-window --match title:vim
# Change colors
kitten @ set-colors background=#1a1a2e
# Signal child process
kitten @ signal-child --match id:1 SIGINT
# Interactive shell
kitten @