ClaudeSublime
By
petr.jakub
Created
Installations minus removals
Upgrades
- 10 installs
Links
Versions
1.0.3
(>ST4106)
·
More
-
(>ST4106)
1.0.2
·
2026-07-28 11:03 -
1.0.1 ·
2026-07-23 11:43 -
1.0.0 ·
2026-07-23 11:01 -
0.1.6 ·
2026-07-20 14:25 -
0.1.5 ·
2026-07-15 12:57 -
0.1.4 ·
2026-07-14 14:39 -
0.1.3 ·
2026-07-10 10:57 -
0.1.2 ·
2026-07-03 12:39 -
0.1.1 ·
2026-07-03 09:05 -
0.1.0 ·
2026-07-03 08:50 -
0.0.2 ·
2026-06-30 11:58 -
0.0.1 ·
2026-06-29 14:05
ClaudeSublime
A Sublime Text plugin for Claude Code, written in Claude Code — the tool wrote its own editor integration. (Yes, it's turtles all the way down. And yes, that means you can now blame the AI for its own plugin.)
A Sublime Text plugin with two features:
- rsync sync — push/pull the project to/from a remote host over SSH, from the sidebar context menu, plus an optional watchdog auto-sync on change.
- Claude Code panel — run Claude Code in a Terminus output panel rooted at the project, with live highlighting of the files Claude changes, change navigation, and interaction notifications.
Requirements
- Sublime Text 4 (uses panels + the bundled Python 3.8 host).
- Terminus — for the panel. If it's missing when you open the panel, ClaudeSublime offers to install it via Package Control (it can't be a hard dependency — PC auto-deps are Python libraries, not packages).
- Claude Code CLI —
npm install -g @anthropic-ai/claude-code(must be in PATH). - rsync — on both the local machine and the remote host (just the binary —
rsync runs over SSH, no
rsyncddaemon needed). macOS/Linux only — rsync sync is not supported on Windows (see below); the Claude panel works there. watchdogPython library (optional) — only affects auto-sync: with it, auto-sync uses real OS file events and runs whenever Sublime is open; without it, auto-sync falls back to polling (only while the Claude panel is open) plus ST "sync on save". Highlighting never needs watchdog — it's driven by the Claude session log, not the filesystem.
Install
Via Package Control (recommended)
This repo isn't in the default channel, so add it as a custom repository once and Package Control then installs/updates it like any package:
- Package Control: Add Repository (Command Palette,
cmd/ctrl+shift+P), paste:https://gitlab.com/petr.jakub/claudesublime/-/raw/main/repository.json - Package Control: Install Package → pick ClaudeSublime.
Package Control installs the latest tagged release. Updates come with Package Control: Upgrade Package. If Terminus is missing, ClaudeSublime offers to install it on first panel open.
Private fork? If you point the repository at a private GitLab repo, Package Control's
http_basic_authwon't work (GitLab's API rejects basic auth), and the archive download can't be authenticated — so PC install only works with a public repo. For a private one, use the manual/dev install below.
Manual
Copy this folder into your Sublime Text Packages directory, named exactly
ClaudeSublime (open it via Preferences → Browse Packages…):
~/Library/Application Support/Sublime Text/Packages/ClaudeSublime (macOS)
%APPDATA%\Sublime Text\Packages\ClaudeSublime (Windows)
~/.config/sublime-text/Packages/ClaudeSublime (Linux)
Sublime loads it automatically. To verify, open the Command Palette and type
ClaudeSublime — the commands should be listed. To remove it, delete that folder
(or remove it via Package Control if installed that way).
Enabling watchdog (optional — only for auto-sync)
watchdog affects auto-sync only (highlighting is log-driven and never uses
it). Without watchdog, auto-sync runs only while the Claude panel is open (it
rides a polling loop) plus ST "sync on save". With it, auto-sync uses real OS
file events and runs whenever Sublime is open — and on macOS deletions/creations
(including files Claude writes in the terminal) are picked up promptly. If you
don't use rsync sync, you don't need watchdog at all.
The catch: Sublime Text 4 plugins run on a bundled Python 3.8, so the
library must be installed into ST's own Lib/python38 folder, and on macOS the
wheel must match Python 3.8 and your CPU. Use a watchdog 4.x wheel —
5.0+ drops Python 3.8 (a too-new watchdog simply fails to import and is ignored).
This package ships a
.python-versionfile (3.8) so ST runs it on the 3.8 host — that's also what putsLib/python38on the import path. Without it ST would use the legacy 3.3 host, where neither watchdog noros.scandirexist. If you ever seemodule 'os' has no attribute 'scandir'in the console, the package is running under 3.3 — make sure.python-versionis present and restart Sublime Text.
macOS (Apple Silicon shown; for Intel swap the platform — see note):
# 1. Locate ST's 3.8 lib folder
LIB="$HOME/Library/Application Support/Sublime Text/Lib/python38"
# 2. Download a 3.8 wheel for your arch (arm64 here; uname -m to check)
cd /tmp
pip3 download 'watchdog<5' --only-binary=:all: \
--python-version 3.8 --implementation cp --abi cp38 \
--platform macosx_11_0_arm64 -d watchdog-dl
# 3. Drop it into ST's lib (remove any older/mismatched copy first)
rm -rf "$LIB"/watchdog "$LIB"/watchdog-*.dist-info "$LIB"/_watchdog_fsevents*.so
unzip -o /tmp/watchdog-dl/watchdog-*.whl -d "$LIB"
# 4. Restart Sublime Text (required — Lib is read at startup)
Intel Mac: replace
--platform macosx_11_0_arm64with--platform macosx_10_9_x86_64. Rununame -m(arm64vsx86_64) if unsure.
Linux — watchdog uses inotify (pure Python, no compiled extension), so a
plain install into ST's lib works regardless of your system Python version:
LIB="$HOME/.config/sublime-text/Lib/python38"
pip3 install --target "$LIB" 'watchdog<5'
# then restart Sublime Text
Windows — watchdog uses ReadDirectoryChangesW (also pure Python). In
PowerShell:
$LIB = "$env:APPDATA\Sublime Text\Lib\python38"
pip install --target "$LIB" "watchdog<5"
# then restart Sublime Text
On Linux/Windows there's no per-CPU C extension to match (the compiled part,
_watchdog_fsevents, is macOS-only), so anywatchdog4.x is fine — keep the<5pin so it still imports under Python 3.8. Ifpippulls a.dist-infofor a newer dep that won't import, just reinstall with the pin.
Verify: restart ST, open View → Show Console, and run:
from watchdog.observers import Observer; print("watchdog OK:", type(Observer()).__name__)
An observer name — FSEventsObserver/KqueueObserver (macOS),
InotifyObserver (Linux), WindowsApiObserver (Windows) — means it loaded.
The ClaudeSublime status bar then shows Auto-sync 🟢 (instead of the panel-tied
polling fallback). On macOS, if FSEvents can't load, watchdog automatically falls
back to kqueue — still fine for normal projects.
Developing the plugin? Instead of copying, symlink your working copy into Packages so edits apply live — see
CLAUDE.md. The symlink is a dev convenience only, not the way end users activate the plugin.
Per-project configuration — ClaudeSublime.json
Put a ClaudeSublime.json at a project folder root (see
ClaudeSublime.example.json). // comments and trailing commas are allowed.
The fastest way to create one is the Command Palette entry
ClaudeSublime: Generate Project Config (also under Tools → ClaudeSublime
and in the sidebar right-click menu — there it targets the project folder of the
clicked item). It writes a ClaudeSublime.json with the required
fields (host, remote_path) left empty and the optional ones pre-filled with
their defaults, then opens it for editing. If the file already exists it just
opens it instead of overwriting.
{
"rsync": {
"enabled": true, // optional, set false to disable all rsync
"host": "server.example.com", // required (when enabled)
"remote_path": "/srv/www/app", // required (when enabled)
"user": "jakub", // optional (default: ssh config / current user)
"port": 22, // optional
"connect_timeout": 30, // optional
"keepalive": 300, // optional (ServerAliveInterval)
"ssh_key_file": "~/.ssh/id_rsa", // optional
"ssh_config_file": "~/.ssh/config",// optional
"extra_ssh_options": [], // optional, raw ssh -o flags
"extra_rsync_options": [], // optional, raw rsync flags (e.g. "--rsync-path=sudo rsync")
"ignore_regexes": [] // optional, merged with built-in defaults
},
"claude": {
"session": "" // optional session UUID to --resume
}
}
claude.session is filled in automatically: when you open the panel and a
new session is started — because none was pinned yet, or a --resume couldn't
find the saved one — the plugin writes the new session's UUID back here, so the
next open resumes right where you left off. You can still set/replace it manually
via ClaudeSublime: Save Session ID for This Project.
To use only the Claude Code panel without any remote sync, set
"rsync": { "enabled": false } (the other rsync fields can be omitted). All
sync commands — Sync ↑/↓ and Toggle Auto-Sync — then stay disabled, and
auto-sync never starts.
Windows
rsync sync does not work on Windows: the runner streams rsync through a
pseudo-terminal using Python's pty module, which is Unix-only, and Windows has
no native rsync. So on Windows Generate Project Config writes a minimal,
disabled rsync block:
{
"rsync": { "enabled": false },
"claude": { "session": "" }
}
rsync is treated as unavailable on Windows regardless of the config — even if
you hand-write a full rsync section, the sync commands stay disabled, auto-sync
never starts, and the indicator shows ⚪ (a manual trigger just says "not
supported on Windows"). No error spam. The Claude panel, highlighting and
auto-open all work normally. If you need remote sync there, run it yourself via
WSL (wsl rsync … with /mnt/c/… paths).
FreeIPA / JumpHost / ControlMaster
rsync uses your ~/.ssh/config verbatim, so the cleanest setup is to define the
JumpHost / ControlMaster there:
Host server.example.com
ProxyJump jump.example.com
ControlMaster auto
ControlPath ~/.ssh/cm-%r@%h:%p
ControlPersist 600
With ControlMaster the first connection authenticates once; subsequent syncs reuse the master socket and won't re-prompt. If rsync/ssh does ask for a password, passphrase, or host-key confirmation, ClaudeSublime shows it as a Sublime input panel (note: input is not masked, same as ST's rename input).
Ignore patterns
ignore_regexes are regexes matched against the project-relative path and
are also converted to rsync --exclude rules (so they apply in both sync
directions). Generate Project Config pre-fills a sensible default set — VCS
metadata (.git/, .svn/, .hg/, …), OS cruft (.DS_Store, Thumbs.db, …),
editor/IDE state (*.sublime-*, sftp-config.json, .idea/, .vscode/, vim
swap files, ClaudeSublime.json), and dependency/build caches (node_modules/,
__pycache__/, *.pyc, venv/, .pytest_cache/, .gradle/, …). Because they
live in the config (not hard-wired), you can delete any entry to start syncing
it — e.g. drop \.git/ to sync the .git folder — or add your own.
(If a config has no ignore_regexes key at all — e.g. a minimal hand-written
one — the same built-in defaults are used as a fallback. Setting the key, even
to [], takes over completely.)
Usage
Sidebar right-click → ClaudeSublime:
- Sync local → remote / Sync remote → local (selected files/dirs, or the whole project when nothing relevant is selected).
- Add File to Context → sends
@pathreferences into the Claude prompt.
Local and remote stay 1:1 (a true mirror), except ignored paths. With
sync_deleteon (the default),rsync --deleteis used so a file you remove on one side is removed on the other:
- Auto-sync pushes the whole project on every change and removes anything on the remote that no longer exists locally (deletions and renames of files and folders propagate). This includes files Claude creates/edits/deletes directly from the panel. With
watchdoginstalled it works whenever ST is running; without it, auto-sync falls back to polling the project and so only runs while the Claude panel is open.- Manual sync mirrors in both directions — whole project, or a selected folder (a selected single file never triggers deletions).
Ignored paths (
ignore_regexes, e.g..git/,node_modules/) are always protected — never pushed and never deleted just because they're missing on the other side. Setsync_deletetofalseto make every sync add/update only (stale files then linger, as in the old behaviour).
Editor right-click → ClaudeSublime:
- Add Selection to Context / Add File to Context (no submit).
- Send Selection to Claude (submits).
All commands (Command Palette — type "ClaudeSublime")
| Caption | Command | What it does |
|---|---|---|
| Show / Hide Claude Panel | claude_sublime_toggle |
Open the panel, or toggle its visibility |
| Toggle Focus (editor ⇄ panel) | claude_sublime_focus_toggle |
Move focus between the editor and the Claude panel (opens/shows it if needed) |
| New Claude Session | claude_sublime_new_session |
Stop the current session, start a fresh one (its id is auto-saved) |
| Save Session ID for This Project | claude_sublime_save_session |
Manually pin a session UUID into ClaudeSublime.json |
| Generate Project Config | claude_sublime_init_config |
Create a ClaudeSublime.json (also in the sidebar menu) |
| Enable Interaction Notifications | claude_sublime_enable_notifications |
Add the Notification + Stop hooks (globally, in ~/.claude) so you're pinged when Claude needs you / finishes |
| Go to Changed File | claude_sublime_goto_changed_file |
Quick-panel list of files with Claude marks (+/− counts); jump to one |
| Next / Previous Change (this file) | claude_sublime_goto_change {"direction": …, "scope": "file"} |
Jump between Claude's change blocks in the active tab |
| Next / Previous Change (all tabs) | claude_sublime_goto_change {"direction": …, "scope": "global"} |
Same, continuing across all open tabs (wraps) |
| Send Selection to Claude | claude_sublime_send_selection |
Send the selection/line to Claude and submit |
| Add File to Context | claude_sublime_add_context {"include_selection": false} |
Insert @file into the prompt (no submit) |
| Add File + Selection to Context | claude_sublime_add_context {"include_selection": true} |
Insert @file + the selection (no submit) |
| Sync local → remote | claude_sublime_sync_up |
rsync push (whole project, or selected paths) |
| Sync remote → local | claude_sublime_sync_down |
rsync pull |
| Toggle Auto-Sync | claude_sublime_toggle_autosync |
Turn auto-sync on/off for this window |
Sidebar-only: claude_sublime_add_context_sidebar (Add File to Context from the tree).
The status bar shows an auto-sync indicator: Auto-sync 🟢 (on), Auto-sync 🔴
(off), Auto-sync 🟠 (syncing now), or Auto-sync ⚪ (N/A — rsync disabled or not
configured). Sublime status items have no hover tooltip, hence the legend here.
Hide it with show_autosync_status: false.
After each successful sync, a short note appears next to it — Synced: file1, file2
(basenames, up to two) or Synced: 15 files — since rsync is often too quick to
catch the 🟠. Turn it off with show_synced_files: false.
Suggested keybindings (opt-in — nothing is bound by default)
ClaudeSublime ships no active key bindings, so it never clashes with keys
your other packages use. Every command is in the Command Palette (type
ClaudeSublime:). The bindings below are provided as a ready-to-copy template in
Example.sublime-keymap. Open Preferences → Package Settings → ClaudeSublime →
Key Bindings (a split view of the template and your user keymap) and copy the
ones you want into the right-hand pane. The ctrl+alt+… combos can clash with
AltGr on some keyboard layouts.
| Suggested shortcut | Action |
|---|---|
ctrl+alt+c |
Show / hide Claude panel |
ctrl+alt+j |
Toggle focus (editor ⇄ panel) |
ctrl+alt+shift+c |
New Claude session |
ctrl+alt+a |
Add file + selection to context |
ctrl+alt+shift+a |
Send selection to Claude |
ctrl+alt+s |
Sync local → remote |
ctrl+alt+shift+s |
Toggle auto-sync |
ctrl+alt+shift+o |
Go to changed file (quick panel) |
ctrl+alt+. / ctrl+alt+, |
Next / previous change (this file) |
ctrl+alt+shift+. / ctrl+alt+shift+, |
Next / previous change (all tabs) |
How highlighting works
Highlighting is driven entirely by the Claude session log
(~/.claude/projects/<enc>/<id>.jsonl), not by watching the filesystem. Each
Edit/Write Claude makes is recorded there (as a structuredPatch or full
content); the plugin tails the log and turns those into markers. Consequences:
- Only Claude's own edits are shown. Git checkouts, and edits from other tools or editors, are ignored — they never touch the highlights.
- A file's marks accumulate within a prompt turn (all of Claude's edits to it combine into one diff) and persist until Claude edits that file again in a later turn, at which point they're recomputed for the new turn. A file Claude doesn't touch keeps its marks across turns.
- Files Claude changes are auto-opened in the background (
auto_open_changed). A bulk batch overauto_open_max_files(default 10) at once is skipped.
Markers:
- Added lines → green gutter bar (default). Set
highlight_added_styleto"outline"to also draw a box around each changed block (colour viahighlight_outline_scope, default blueregion.bluish). - Deleted lines → red marker on the line above the deletion.
- Each affected tab scrolls to its first change (
scroll_to_first_change, default on) — without moving the cursor or stealing focus. - The status bar shows a summary, e.g.
Claude: 3 files +42 -7(show_round_stats). - Navigate changes: jump between change blocks with the Next/Previous
Change commands (this file, or across all open tabs) — see the keybindings
above. A run of consecutive changed lines counts as one block. Go to Changed
File (
ctrl+alt+shift+o) opens a quick-panel list of all changed files (with ± counts) — a substitute for a sidebar badge, which ST has no API for.
Interaction notifications (sound + focus)
Get pinged when Claude needs you (a permission prompt / idle wait) and when a
prompt finishes — like iTerm2's bell. Run ClaudeSublime: Enable Interaction Notifications once: it adds two Claude Code hooks to your user-global
~/.claude/settings.json (merged into any existing settings; idempotent):
Notification— Claude needs you → sound + brings up/focuses the panel.Stop— a prompt finished → sound only (no focus steal).
It's a personal, global setting: nothing is written into any project (so it
never lands in a repo or affects teammates who don't want it), and it applies to
every project you open. Each hook writes its event to a per-project sentinel file
under ~/.claude that the plugin watches on a fast ~250 ms loop
(notify_poll_ms), so the ping is near-immediate. (Enabling also removes any hook
an older version of the plugin had put in the project's .claude/settings.local.json.)
Settings:
notify_on_interaction— master switch.notify_sound— on macOS a sound file (afplay); on Linux/Windows an on/off toggle using a native sound (Linux:canberra-gtk-play/paplay; Windows:MessageBeep).false/""mutes everywhere.notify_sound_linuxsets the Linux file forpaplay.notify_focus_panel— focus the panel on the "needs you" event.notify_banner— also post an OS notification banner (off by default). Sublime can't put a number badge on its own Dock/taskbar icon from a plugin (unlike iTerm2, a native app), so this banner is the OS-level attention cue.- macOS — terminal-notifier
if on your
PATH(faster, labelled ClaudeSublime —brew install terminal-notifier), else built-inosascript(slower, labelled Script Editor; macOS asks to allow notifications once).notify_banner_toolforces a tool. Gotcha: terminal-notifier is a different app, so it needs its own notification permission — if the banner silently stops after installing it, grant it in System Settings → Notifications (or setnotify_banner_toolto"osascript"). - Linux —
notify-send(libnotify); no banner if it isn't installed. - Windows — a PowerShell balloon/toast (best-effort).
- macOS — terminal-notifier
if on your
notify_on_stop— include the prompt-finished ping (sound only).notify_coalesce— Claude fires a "waiting for input" notification ~60s after finishing; when the completion (Stop) already pinged, that redundant follow-up is suppressed until you send the next prompt (false= ring both).
Restart Claude (or send one prompt) after enabling so the CLI loads the hooks.
Platform support
Primarily developed on macOS. The core — Claude panel, live highlighting, change navigation, auto-open, status bar, session pinning, Generate Project Config, focus toggle — works the same everywhere. Platform differences:
| Feature | macOS | Linux | Windows |
|---|---|---|---|
| Claude panel, highlighting, navigation, auto-open | ✅ | ✅ | ✅ |
| Suggested keybindings (opt-in) | ✅ | ✅ | ✅ (ctrl+alt+… can clash with AltGr on some layouts) |
| rsync sync (manual + auto-sync) | ✅ | ✅ | ❌ not supported (needs the Unix-only pty; config generation disables it) |
| watchdog / auto-sync backend | FSEvents/kqueue | inotify | ReadDirectoryChangesW |
| Interaction notifications — hook fires | ✅ | ✅ | ⚠️ the hook is a POSIX shell command; works under Git Bash, likely not under cmd/PowerShell |
| Notification sound | afplay |
canberra-gtk-play/paplay |
MessageBeep |
Notification banner (notify_banner) |
terminal-notifier / osascript | notify-send (if installed) |
PowerShell balloon (best-effort) |
The macOS-specific bits are guarded, so nothing crashes on other platforms — worst case a notification degrades to just panel focus + status.
Known limitation — panel height
Sublime Text has no API to set output-panel height. The Claude panel opens at ST's default height; drag its top border to resize — ST remembers it per window.
Panel scrollback (history)
By default Claude Code runs as a full-screen TUI (the alternate screen
buffer, like vim/less), where terminals keep no scrollback — anything that
scrolls off is gone. To avoid that, the plugin launches Claude with
CLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1 (setting disable_alternate_screen,
on by default), so Claude renders inline and the conversation stays in
the panel's scrollback — scroll back through it with the mouse wheel like any
terminal. Terminus keeps the last scrollback_history_size lines (its own
setting, default 10000).
Set disable_alternate_screen: false to get the original full-screen TUI (no
scrollback). Either way, the full transcript is always on disk at
~/.claude/projects/<encoded-cwd>/<session-id>.jsonl (claude --resume).
Settings
See ClaudeSublime.sublime-settings (Preferences → Package Settings →
ClaudeSublime → Settings) for highlighting, auto-sync, and rsync flag options.
By default the sync does not preserve file owner/group: -a would copy the
local numeric uid/gid to the remote, where it usually maps to a non-existent
user or wrong group (e.g. uid 501 / group games). With sync_preserve_ownership
off (the default) rsync gets --no-owner --no-group, so remote files are owned
by the ssh user. Turn it on only if you sync as root on both ends.