feat: kitty-compatible keybindings via tmux extended-keys (CSI u)
All Ctrl+Shift shortcuts mapped to match kitty defaults: - Ctrl+Shift+T/W/Left/Right for tab management - Ctrl+Shift+Enter for splits, ]/[ for pane cycling - Ctrl+Shift+C/V for copy/paste, H for scrollback pager - Ctrl+Shift+1-9 for goto tab, F11 for fullscreen - Dvorak extras and Alt shortcuts preserved alongside
This commit is contained in:
@@ -1,16 +1,84 @@
|
|||||||
# sethmux
|
# sethmux
|
||||||
|
|
||||||
Mobile-first web terminal powered by [ttyd](https://github.com/tsl0922/ttyd) + [tmux](https://github.com/tmux/tmux). One persistent session, multiple tabs, accessible from any browser.
|
Mobile-first web terminal powered by [ttyd](https://github.com/tsl0922/ttyd) + [tmux](https://github.com/tmux/tmux). One persistent session, multiple tabs, accessible from any browser. Kitty-compatible keybindings.
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Single persistent tmux session** — shared across all connected clients
|
- **Single persistent tmux session** — shared across all connected clients, live-synced across devices
|
||||||
- **Mobile touch toolbar** — on-screen buttons for tabs, signals, navigation, splits, and text selection
|
- **Kitty keybindings** — `Ctrl+Shift+T/W/Left/Right` etc. via tmux extended-keys (CSI u)
|
||||||
- **Text selection mode** — tap `Sel` to select and copy text on touch devices
|
- **Mobile touch toolbar** — two-row on-screen buttons for all common actions
|
||||||
|
- **AI CLI optimized** — 200K scrollback, pane capture/logging, pre-built session layout
|
||||||
- **Push notifications** — `sethmux-notify "Build done!"` sends browser notifications
|
- **Push notifications** — `sethmux-notify "Build done!"` sends browser notifications
|
||||||
- **PWA installable** — add to home screen for app-like experience
|
- **PWA installable** — add to home screen for app-like experience
|
||||||
- **Dark theme** — Sethian dark + orange (#D35400) accent
|
- **Dark theme** — Sethian dark + orange (#D35400) accent
|
||||||
|
|
||||||
|
## Keybindings
|
||||||
|
|
||||||
|
### Kitty-compatible (Ctrl+Shift+key)
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|-----|--------|
|
||||||
|
| `Ctrl+Shift+T` | New tab |
|
||||||
|
| `Ctrl+Shift+W` | Close tab |
|
||||||
|
| `Ctrl+Shift+Right/Left` | Next / previous tab |
|
||||||
|
| `Ctrl+Shift+1-9` | Go to tab N |
|
||||||
|
| `Ctrl+Shift+. / ,` | Move tab forward / backward |
|
||||||
|
| `Ctrl+Shift+Enter` | New split (horizontal) |
|
||||||
|
| `Ctrl+Shift+] / [` | Next / previous pane |
|
||||||
|
| `Ctrl+Shift+L` | Cycle layouts |
|
||||||
|
| `Ctrl+Shift+Up/Down` | Scroll up / down |
|
||||||
|
| `Ctrl+Shift+PageUp/PageDown` | Scroll page |
|
||||||
|
| `Ctrl+Shift+Home/End` | Scroll to top / bottom |
|
||||||
|
| `Ctrl+Shift+H` | Show scrollback in pager |
|
||||||
|
| `Ctrl+Shift+C` | Enter copy mode (vi-style) |
|
||||||
|
| `Ctrl+Shift+V` | Paste |
|
||||||
|
| `Ctrl+Shift+Delete` | Clear terminal + scrollback |
|
||||||
|
| `F11` | Toggle fullscreen (zoom pane) |
|
||||||
|
|
||||||
|
### Dvorak extras (prefix Ctrl-A)
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|-----|--------|
|
||||||
|
| `Ctrl-A v / s` | Split vertical / horizontal |
|
||||||
|
| `Ctrl-A S` | Capture pane to `~/logs/` |
|
||||||
|
| `Ctrl-A L` | Toggle live logging to `~/logs/` |
|
||||||
|
| `Ctrl-A z` | Zoom pane |
|
||||||
|
|
||||||
|
### Alt shortcuts (no prefix)
|
||||||
|
|
||||||
|
| Key | Action |
|
||||||
|
|-----|--------|
|
||||||
|
| `Alt-T` | New tab |
|
||||||
|
| `Alt-W` | Close tab |
|
||||||
|
| `Alt-1` to `Alt-5` | Go to tab N |
|
||||||
|
| `Alt-Left/Right` | Previous / next tab |
|
||||||
|
|
||||||
|
## Mobile Toolbar
|
||||||
|
|
||||||
|
Two rows, appears on screens < 900px:
|
||||||
|
|
||||||
|
**Row 1:** `+Tab` `Next` `Prev` | `^C` `^D` `Clr` | `Esc` `Tab` `▲` `▼`
|
||||||
|
**Row 2:** `Sel` `Paste` `Zoom` `Save` | `V.Spl` `H.Spl` `Pane` `Kill`
|
||||||
|
|
||||||
|
## Session Layout
|
||||||
|
|
||||||
|
On startup, four named windows are created:
|
||||||
|
|
||||||
|
| Window | Purpose |
|
||||||
|
|--------|---------|
|
||||||
|
| **code** | Main working terminal |
|
||||||
|
| **git** | Git operations |
|
||||||
|
| **run** | Running services / builds |
|
||||||
|
| **logs** | Tailing logs, monitoring |
|
||||||
|
|
||||||
|
## Push Notifications
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sethmux-notify "Deploy complete!"
|
||||||
|
echo "done" | sethmux-notify
|
||||||
|
make build && sethmux-notify "OK" || sethmux-notify "FAIL"
|
||||||
|
```
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -29,6 +97,7 @@ chmod +x /usr/local/bin/ttyd
|
|||||||
# Deploy
|
# Deploy
|
||||||
sudo mkdir -p /opt/sethmux
|
sudo mkdir -p /opt/sethmux
|
||||||
sudo cp static/* /opt/sethmux/
|
sudo cp static/* /opt/sethmux/
|
||||||
|
sudo cp sethmux-start.sh /opt/sethmux/
|
||||||
sudo cp notify-server.py /opt/sethmux/
|
sudo cp notify-server.py /opt/sethmux/
|
||||||
sudo cp sethmux-notify /usr/local/bin/
|
sudo cp sethmux-notify /usr/local/bin/
|
||||||
sudo cp config/tmux.conf ~/.tmux.conf
|
sudo cp config/tmux.conf ~/.tmux.conf
|
||||||
@@ -37,46 +106,6 @@ sudo systemctl daemon-reload
|
|||||||
sudo systemctl enable --now sethmux sethmux-notify
|
sudo systemctl enable --now sethmux sethmux-notify
|
||||||
```
|
```
|
||||||
|
|
||||||
Open `http://YOUR_IP:7683` in a browser.
|
|
||||||
|
|
||||||
## Mobile Toolbar
|
|
||||||
|
|
||||||
Appears on screens < 900px. Buttons:
|
|
||||||
|
|
||||||
| Button | Action | tmux Key |
|
|
||||||
|--------|--------|----------|
|
|
||||||
| **+Tab** | New tab | `Ctrl-A c` |
|
|
||||||
| **Next/Prev** | Switch tabs | `Ctrl-A n/p` |
|
|
||||||
| **^C / ^D / Clr** | Interrupt / EOF / Clear | |
|
|
||||||
| **Esc / Tab / Up / Down** | Navigation | |
|
|
||||||
| **Sel** | Text selection mode | |
|
|
||||||
| **V.Spl** | Split vertical | `Ctrl-A v` |
|
|
||||||
| **H.Spl** | Split horizontal | `Ctrl-A s` |
|
|
||||||
| **Pane** | Cycle panes | `Ctrl-A o` |
|
|
||||||
| **Kill** | Kill pane/tab | `Ctrl-A x` |
|
|
||||||
|
|
||||||
## Push Notifications
|
|
||||||
|
|
||||||
```bash
|
|
||||||
sethmux-notify "Deploy complete!"
|
|
||||||
echo "done" | sethmux-notify
|
|
||||||
make build && sethmux-notify "OK" || sethmux-notify "FAIL"
|
|
||||||
```
|
|
||||||
|
|
||||||
## tmux Keybindings
|
|
||||||
|
|
||||||
Prefix: `Ctrl-A` (not the default Ctrl-B — easier on mobile).
|
|
||||||
|
|
||||||
| Key | Action |
|
|
||||||
|-----|--------|
|
|
||||||
| `Ctrl-A c` | New window |
|
|
||||||
| `Ctrl-A n / p` | Next / previous |
|
|
||||||
| `Ctrl-A v / s` | Split vertical / horizontal (Dvorak home row) |
|
|
||||||
| `Ctrl-A o` | Cycle panes |
|
|
||||||
| `Ctrl-A x` | Kill pane |
|
|
||||||
| `Alt-1` to `Alt-5` | Jump to window |
|
|
||||||
| Mouse scroll | History |
|
|
||||||
|
|
||||||
## Reverse Proxy (Caddy)
|
## Reverse Proxy (Caddy)
|
||||||
|
|
||||||
```
|
```
|
||||||
@@ -90,25 +119,6 @@ mux.example.com {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Files
|
|
||||||
|
|
||||||
```
|
|
||||||
sethmux/
|
|
||||||
static/
|
|
||||||
index.html # Custom ttyd page with toolbar injection
|
|
||||||
toolbar.js # Mobile touch toolbar
|
|
||||||
manifest.json # PWA manifest
|
|
||||||
icon-192.png # PWA icon
|
|
||||||
icon-512.png # PWA icon
|
|
||||||
config/
|
|
||||||
tmux.conf # Sethian-themed tmux config
|
|
||||||
systemd/
|
|
||||||
sethmux.service # ttyd + tmux systemd unit
|
|
||||||
sethmux-notify.service # Notification API unit
|
|
||||||
notify-server.py # Push notification HTTP API
|
|
||||||
sethmux-notify # CLI notification command
|
|
||||||
```
|
|
||||||
|
|
||||||
## License
|
## License
|
||||||
|
|
||||||
MIT
|
MIT
|
||||||
|
|||||||
+90
-19
@@ -1,12 +1,91 @@
|
|||||||
# sethmux — Sethian tmux config for AI CLI workflows
|
# sethmux — kitty-compatible keybindings for tmux
|
||||||
# Dvorak-optimized, mobile-friendly, built for long-running AI sessions
|
# Mirrors kitty's Ctrl+Shift+key shortcuts via extended-keys (CSI u)
|
||||||
|
# Dvorak-optimized, mobile-friendly, built for AI CLI workflows
|
||||||
|
|
||||||
# --- Prefix ---
|
# --- Extended keys (required for Ctrl+Shift detection) ---
|
||||||
|
set -g extended-keys on
|
||||||
|
set -g extended-keys-format csi-u
|
||||||
|
|
||||||
|
# --- No prefix for kitty-style bindings ---
|
||||||
|
# Kitty uses Ctrl+Shift+key directly, no prefix needed.
|
||||||
|
# We keep Ctrl-A as prefix for tmux-native stuff (capture, logging, etc.)
|
||||||
unbind C-b
|
unbind C-b
|
||||||
set -g prefix C-a
|
set -g prefix C-a
|
||||||
bind C-a send-prefix
|
bind C-a send-prefix
|
||||||
|
|
||||||
# --- Tab/Window management ---
|
# ============================================================
|
||||||
|
# Kitty-compatible keybindings (Ctrl+Shift+key)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
# --- Tab management ---
|
||||||
|
bind -n C-S-t new-window -c "#{pane_current_path}"
|
||||||
|
bind -n C-S-w kill-window
|
||||||
|
bind -n C-S-Right next-window
|
||||||
|
bind -n C-S-Left previous-window
|
||||||
|
|
||||||
|
# Ctrl+Shift+1-9 = goto tab (tmux base-index 1)
|
||||||
|
bind -n C-S-1 select-window -t 1
|
||||||
|
bind -n C-S-2 select-window -t 2
|
||||||
|
bind -n C-S-3 select-window -t 3
|
||||||
|
bind -n C-S-4 select-window -t 4
|
||||||
|
bind -n C-S-5 select-window -t 5
|
||||||
|
bind -n C-S-6 select-window -t 6
|
||||||
|
bind -n C-S-7 select-window -t 7
|
||||||
|
bind -n C-S-8 select-window -t 8
|
||||||
|
bind -n C-S-9 select-window -t 9
|
||||||
|
|
||||||
|
# Ctrl+Shift+. / , = move tab forward/backward
|
||||||
|
bind -n C-S-. swap-window -t +1 \; next-window
|
||||||
|
bind -n C-S-, swap-window -t -1 \; previous-window
|
||||||
|
|
||||||
|
# --- Window/split management ---
|
||||||
|
# Ctrl+Shift+Enter = new split (kitty calls these "windows")
|
||||||
|
bind -n C-S-Enter split-window -v -c "#{pane_current_path}"
|
||||||
|
|
||||||
|
# Ctrl+Shift+] / [ = next/previous pane
|
||||||
|
bind -n C-S-] select-pane -t :.+
|
||||||
|
bind -n C-S-[ select-pane -t :.-
|
||||||
|
|
||||||
|
# Ctrl+Shift+l = next layout (cycle through layouts)
|
||||||
|
bind -n C-S-l next-layout
|
||||||
|
|
||||||
|
# --- Scrolling ---
|
||||||
|
bind -n C-S-Up copy-mode \; send -X scroll-up
|
||||||
|
bind -n C-S-Down copy-mode \; send -X scroll-down
|
||||||
|
bind -n C-S-PageUp copy-mode \; send -X page-up
|
||||||
|
bind -n C-S-PageDown copy-mode \; send -X page-down
|
||||||
|
bind -n C-S-Home copy-mode \; send -X history-top
|
||||||
|
bind -n C-S-End copy-mode \; send -X history-bottom
|
||||||
|
|
||||||
|
# Ctrl+Shift+h = show scrollback in pager (like kitty's show_scrollback)
|
||||||
|
bind -n C-S-h capture-pane -pS - \; save-buffer /tmp/sethmux-scrollback.txt \; new-window "less +G /tmp/sethmux-scrollback.txt"
|
||||||
|
|
||||||
|
# --- Clipboard ---
|
||||||
|
# Ctrl+Shift+c = copy (enter copy mode, or copy selection if in copy mode)
|
||||||
|
bind -n C-S-c copy-mode
|
||||||
|
bind -T copy-mode-vi C-S-c send -X copy-selection-and-cancel
|
||||||
|
|
||||||
|
# Ctrl+Shift+v = paste from tmux buffer
|
||||||
|
bind -n C-S-v paste-buffer
|
||||||
|
|
||||||
|
# --- Clear terminal ---
|
||||||
|
# Ctrl+Shift+Delete = clear terminal + scrollback
|
||||||
|
bind -n C-S-DC send-keys C-l \; clear-history
|
||||||
|
|
||||||
|
# --- Fullscreen ---
|
||||||
|
# F11 = toggle pane zoom (closest to kitty's fullscreen)
|
||||||
|
bind -n F11 resize-pane -Z
|
||||||
|
|
||||||
|
# ============================================================
|
||||||
|
# Dvorak-friendly extras (prefix Ctrl-A)
|
||||||
|
# ============================================================
|
||||||
|
bind s split-window -v -c "#{pane_current_path}"
|
||||||
|
bind v split-window -h -c "#{pane_current_path}"
|
||||||
|
bind z resize-pane -Z
|
||||||
|
bind c new-window -c "#{pane_current_path}"
|
||||||
|
bind o select-pane -t :.+
|
||||||
|
|
||||||
|
# --- Alt shortcuts (no prefix, kept for mobile/quick access) ---
|
||||||
bind -n M-t new-window -c "#{pane_current_path}"
|
bind -n M-t new-window -c "#{pane_current_path}"
|
||||||
bind -n M-w kill-window
|
bind -n M-w kill-window
|
||||||
bind -n M-1 select-window -t 1
|
bind -n M-1 select-window -t 1
|
||||||
@@ -16,15 +95,10 @@ bind -n M-4 select-window -t 4
|
|||||||
bind -n M-5 select-window -t 5
|
bind -n M-5 select-window -t 5
|
||||||
bind -n M-Left previous-window
|
bind -n M-Left previous-window
|
||||||
bind -n M-Right next-window
|
bind -n M-Right next-window
|
||||||
bind c new-window -c "#{pane_current_path}"
|
|
||||||
|
|
||||||
# --- Dvorak-friendly splits ---
|
# ============================================================
|
||||||
bind s split-window -v -c "#{pane_current_path}"
|
# AI CLI workflow features
|
||||||
bind v split-window -h -c "#{pane_current_path}"
|
# ============================================================
|
||||||
|
|
||||||
# --- Pane navigation ---
|
|
||||||
bind o select-pane -t :.+
|
|
||||||
bind z resize-pane -Z
|
|
||||||
|
|
||||||
# --- Mouse ---
|
# --- Mouse ---
|
||||||
set -g mouse on
|
set -g mouse on
|
||||||
@@ -39,16 +113,15 @@ bind -T copy-mode-vi y send -X copy-selection-and-cancel
|
|||||||
bind -T copy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel
|
bind -T copy-mode-vi MouseDragEnd1Pane send -X copy-selection-and-cancel
|
||||||
|
|
||||||
# --- Capture & logging ---
|
# --- Capture & logging ---
|
||||||
# Ctrl-A S = save entire scrollback to file
|
|
||||||
bind S capture-pane -pS - \; save-buffer ~/logs/capture-#{session_name}-#{window_index}-#{pane_index}-#(date +%s).txt \; display "Pane captured to ~/logs/"
|
bind S capture-pane -pS - \; save-buffer ~/logs/capture-#{session_name}-#{window_index}-#{pane_index}-#(date +%s).txt \; display "Pane captured to ~/logs/"
|
||||||
|
|
||||||
# Ctrl-A L = toggle pipe-pane logging
|
|
||||||
bind L pipe-pane -o "cat >> ~/logs/live-#{session_name}-#{window_index}-#(date +%s).log" \; display "Logging toggled"
|
bind L pipe-pane -o "cat >> ~/logs/live-#{session_name}-#{window_index}-#(date +%s).log" \; display "Logging toggled"
|
||||||
|
|
||||||
# --- Clipboard ---
|
# --- Clipboard ---
|
||||||
set -g set-clipboard on
|
set -g set-clipboard on
|
||||||
# Copy on select (mouse)
|
|
||||||
bind -T copy-mode-vi MouseDragEnd1Pane send -X copy-pipe-and-cancel "cat"
|
# ============================================================
|
||||||
|
# Appearance
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
# --- Numbering ---
|
# --- Numbering ---
|
||||||
set -g base-index 1
|
set -g base-index 1
|
||||||
@@ -75,8 +148,6 @@ setw -g window-status-separator ""
|
|||||||
# --- Pane borders ---
|
# --- Pane borders ---
|
||||||
set -g pane-border-style "fg=#333333"
|
set -g pane-border-style "fg=#333333"
|
||||||
set -g pane-active-border-style "fg=#D35400"
|
set -g pane-active-border-style "fg=#D35400"
|
||||||
set -g pane-border-format " #{pane_current_command} "
|
|
||||||
set -g pane-border-status off
|
|
||||||
|
|
||||||
# --- Terminal ---
|
# --- Terminal ---
|
||||||
set -g default-terminal "tmux-256color"
|
set -g default-terminal "tmux-256color"
|
||||||
|
|||||||
Reference in New Issue
Block a user