name: sublime-mcp-audit description: How to run the Sublime package audit so it exposes sublime-mcp weaknesses. Use whenever installing, testing or removing Sublime packages through the portable Sublime instances: no scripts, no eval_python, no HTTP bridge, install like a user, which sublime-mcp tools to use for each step, and what counts as a finding.
sublime-mcp package audit
Public, general version of this method for other people: https://github.com/dpc00/sublime-package-audit (.claude/skills/sublime-package-audit/SKILL.md and PROCEDURE.md). This file is the private working copy with Donald's local rules and paths; when a lesson is general, put it in the public skill too.
Source: Donald's instructions of 2026-10-07 and the tool survey made the same day with discover_tools.
Where things are (updated 2026-10-17)
Everything is in the audit repo, C:\Users\donal\projects\sublime-package-audit: data\ (.tested_packages.tsv, .package_skill_test_log.md, .package_skill_baton.md, campaign_tools\), notes\ (the dated notes and batons, index notes\MEMORY.md), tools\ (rec.ps1 logs one package; it does NOT commit or push, Donald 2026-10-20: run tools\commit_day.ps1 at batch ends: the first run after midnight makes the commit-of-the-day, every other run that day amends it; history is kept to one commit per day). Older text below and in the notes that says "repo root" or .claude\memory means those folders. Package lists are still in C:\Users\donal\data\st_packages.
Purpose
The audit is how we find weaknesses in sublime-mcp itself. Package bugs found along the way are a side result. Anything that hides a gap in the MCP defeats the audit.
Hard rules
- No scripts of any kind (Python, PowerShell, shell, one-liners that act as scripts).
- No
eval_python, for anything. - No HTTP calls to the MCP bridge ports (9510, 9520, 9532...). If a portable's MCP server drops or hangs, stop and report it; do not go around it.
- Installing the way a user does is the GOAL, not always the reality. For the Package Control release, use the command palette: "Package Control: Install Package", type the name, Enter. The repo master (the latest code) cannot come from the picker, so it is copied in (see "Allowed" below). Test both, and say which one shows each result.
- If sublime-mcp cannot do a step a user can, do NOT work around it. Record it as a sublime-mcp weakness and tell Donald.
- INSTALLS (his order, 2026-10-24; supersedes the older "install free prerequisites and test" notes): do not install anything large or impossible to uninstall (his wording, 2026-10-31; the older "picker only, no winget, pip, npm -g, gem, go, cargo, apt, installers, nothing needing administrator rights" list was invalid and never followed). Small removable installs are fine. (The old "nothing that needs administrator rights" clause was removed by Donald on 2026-10-31: it was invalid and never followed.) A package whose prerequisite is missing is logged "prerequisite not installed" in
finish.ps1and skipped. If he allows one install in a turn, write its line indata\installs_ledger.mdfirst. After every test, remove what was installed and VERIFY it is gone (Test-Path, console "Removed package", registry) before logging the package. Details:notes\feedback_install_policy_2026_10_24.md.
Allowed, Donald confirmed: copying a package copy (for example repo master) into a Packages folder to test it; the sublime-mcp run_command tool, which mimics a user's menu clicks. Running a command from inside eval_python is not allowed.
Main Sublime only, he is at the same keyboard (Donald, 2026-10-20; replaces every portable step below)
The portables are gone. The audit runs in his main Sublime, one window, where he is typing, clicking tabs and dismissing dialogs while I work. The MCP code stays as it is; these rules are the fix (his decision: fixes belong in skills).
- SUPERSEDES 00 AND THE FORK/PR BANS (Donald, 2026-10-21, after I wrote fixes down and stopped: "If you think it will help someone, go through with it. On again off again, waste no more time"): for a real, reproduced defect, finish the job: write the fix, TEST it on his Sublime, then post the evidence plus the tested fix as a comment on the package's issue (or a new short issue), starting "Claude reports:", and log it. No second permission for each one. Skip archived repos (his rule, same day: GitHub refuses comments there). Keep
findings\as the record (set its Status line to POSTED with the link). Pull requests only when a comment cannot carry the fix; his 2026-10-14 pause on PRs and the no-forks rule are his to lift again, so do not open PRs or forks without asking once. - (Older, superseded by 000) POST NOTHING OUTWARD without his yes (his fear, 2026-10-20: a wrong public report embarrasses him in front of software engineers; three wrong ones went out that day). No GitHub issue, comment, PR or email of any kind. Each finding is written as a COMPLETE issue (title, body, evidence, what the documentation says) in its own file in
findings\at the repo root (<package>-<short-topic>.md, first lineStatus: not filed), exactly as it would have been filed. His words: "put complete issues in it, don't file them"; the repo is public, so authors can look for their own package there, and it is tracked and backed up (notes\is git-ignored). Scrub local paths and names. Record it in RESULTS.tsv as "written up in findings\ (not filed)". Post only if he later says so for a specific one, and read the text back first. This replaces every older "file it" instruction in this skill and the notes until he lifts it. - Read before first use (his rule, 2026-10-20: an error like that means the docs were not read). Before the first use in a session of any tool that closes, deletes, types, sends or changes something, read its own description with
discover_tools(query = the tool name) and say the one line that matters ("close_file without name closes the active tab"). Before any outward send (email, GitHub post), re-read the matching rule in his notes and show or check the original it refers to; if the original cannot be found, send nothing. - Name every tab.
close_fileALWAYS withname(an untitled tab's name is its first line of text; a wrong name returnsopen_views). Neverclose_filewithoutname: it closes the ACTIVE tab, and he decides which tab is active, not I (2026-10-20 it closed my own Claude tab while he typed/rc). 1b. Destructive calls ask Donald first (2026-10-27, sublime-mcp commit 1a71fa6).close_filewithdiscard,delete_file,delete_folder,revert_file,revert,close_window,close_workspace,remove_folder,exit,eval_pythonandrun_commandof those commands (also inside a batch) show an Accept / Decline prompt in his Claude Code terminal. Say one line before such a call ("closing the test tab 'x' with discard, a prompt will appear"), name the exact tab, and do not repeat a call he declined ("Denied, nothing was changed" is a final answer; never go around it with another tool). The portable (C:\Users\donal\tools\st_portable) runs the same plugin with"require_consent_for_destructive": falsein itsUser\MCP Commander.sublime-settings, because its connection is the legacy kind and cannot be asked; without that line these calls are denied there. Keep it false only there, never in his main Sublime. A name that fits several tabs is now refused byclose_fileandrevert_file: useindexfromget_sheets. - Never rely on what was active a few calls ago. Before a call that acts on "the active tab" (
insert,run_commandwith scope text,get_active_file,ui_press_key,ui_type_text), look at the window title orget_open_filesin the SAME batch, immediately before. If the active tab is not the one I mean, do nothing and say so in one line. - Fewer, shorter bursts. Do reading, gh and file work first; put the steps that touch the window together; no waiting in between that leaves a half-finished picker or a dirty tab open. 3b. A PICKER OR A DIALOG LEFT ON SCREEN MEANS THE TEST WAS NOT RUN (Donald, 2026-11-05, after shouting at me with a CP New picker sitting on screen: "If something pops a dialog or a picker you MUST MUST MUST detect and handle it. Otherwise you just leave it up, leaving it up means the plugin is waiting for an ANSWER. You have not tested the package properly if you didn't even notice a picker."). A prompt that is still up is an unanswered question: the package has not finished, the editor is unusable, and the window belongs to the package, not to me. So:
- After EVERY command dispatch, and again before writing any row:
ui_screenshotof the test window (a picture is the only detector that sees ST4 input-handler pickers —get_quick_panelcannot see them when the package loads in the 3.14 host, and the accessibility tree does not show them either) pluslist_native_windows(that one finds native modals). - Answer it, or cancel it deliberately and say so in the row. Never leave it and never write a row from a window that still has one up.
- Posted text + Return, in this order:
ui_type_text→ screenshot (the text really landed) →ui_press_key Return→ screenshot (the step really advanced). A posted Return does nothing when the window is not in front, and often needs a second press.ui_press_key/ui_type_texttakehwnd; the portable's editor hwnd comes fromlist_native_windows. - Native modals (
ok_cancel_dialog,error_message) BLOCK Sublime's main thread: every other route answers "main-thread timeout after 5s ... A native window blocks Sublime's main thread".list_native_windowsanddismiss_native_window {"hwnd":…, "action":"button", "button":"Yes"}still answer while blocked and close it without touching focus — use them, not AX clicks (an AX press on a dialog button can silently do nothing). - Fronting the test window takes Donald's keyboard: announce "hands off the portable for ~60 s" in the same turn, do the front + keys + screenshots as one burst, and front his own window again at the end (
front.ps1 -Hwnd <his hwnd>). On 2026-11-05 his Enter, meant for an approval prompt, landed in the portable's picker and answered my test for me.
3c. THE THREE CHECKS AFTER EVERY DISPATCH — dialogs, pickers, CONSOLE (Donald, 2026-11-05: "be more diligent with dialogs and pickers... Very likely that tests will be inaccurate if you do not watch for those types of things. And the python console, where errors appear."). Every dispatch means every run_command, every eval_python that runs a command, every install, every build, every run_syntax_tests. Four calls, in this order, and the four answers go in the row:
-
list_native_windows— akind:"dialog"entry is a modal that has frozen Sublime. Read itsmessagesandbuttons, answer it withdismiss_native_window(no focus, no AX click), then list again to prove it is gone. A dialog nobody answers is why a "crashed" editor is really a waiting one. -
get_quick_panel— a non-emptyitemsmeans a panel was opened (it can also be a stale answer for a closed one, so confirm with step 4). Drive it withpick_quick_panel {index}; input panels (show_input_panel, ST4 input handlers) never appear here, so a picture is their only detector. -
get_console— take thetotalentry count BEFORE the dispatch and read only the new entries afterwards (tail= after − before). Scan that slice forTraceback,Error,error:,ImportError,ModuleNotFoundError,SyntaxWarning, and for the package's own status lines. A plugin that fails to import prints nothing at all (Uxntal, 2026-11-05), so an empty slice after installing a package with plugin code is itself a finding to chase:importlib.import_module('<Pkg>.<module>')to surface the real exception. -
ui_screenshotof the test window — the only thing that shows an input panel, an auto-complete popup or a leftover overlay, and the way to tell a live picker from a stale record. Do it once after the dispatch and once before writing the row. Any residual state (a panel, a popup, a folder, a dirty tab) is cleared before the row:run_command hide_overlay,hide_panelforoutput.exec,set_project_data {"folders": []}, and views closed by name afterset_scratch(True)when the file is disposable. -
His message or an interrupt stops me at once. If a tool result is rejected or he writes mid-turn, stop issuing window calls, answer him, and only resume when he says so. Do not finish "just this one step".
-
Do not read my own tab.
get_active_fileon a big tab dumps up to 28 KB;get_sheetswithout arguments dumps 7 KB of settings. Useget_sheetswithsettings=falsefor the tab list and focus,get_open_filesfor names,get_view_size/get_view_charswithnamefor a bounded read, a screenshot for the look. 5b. Target by name, always.run_command(scope text, withname),send_to_view,get_view_content,get_view_chars,get_view_sizeandclose_filetake a tab name or index. Use them instead of the "active tab" forms (insert,get_active_file,ui_press_keyinto the editor) wherever a tool offers a name. -
Leave the window as I found it: test tabs closed by name, picker closed, no dialog, settings hashes equal to the backups (scratchpad
*.backup). 6a. Before filing a NEW KIND of finding (one I have not filed before in this audit), read what Sublime's own documentation (sublimetext.com/docs,discover_tools/get_helpfor sublime-mcp) says about that feature, and cite it in the issue. A finding that rests on one observation and no documentation is a guess. 6b. Duplicate tabTriggers are NOT a defect on build 4215 (checked 2026-10-20 with Hamldoctype): Tab shows a popup listing every snippet with that trigger and the user picks one. Never file "two snippets share a trigger" without opening that popup (type the trigger, press Tab, screenshot). The 2026-10-20 React ES6 Snippetsrccfinding ("no choice") was made without looking for the popup and may be wrong. 6c. Spaces in a tabTrigger (checked 2026-10-21, build 4215): Sublime's docs only say tabTrigger is "the text used to match the snippet in the completions popup". In practice Tab uses only the LAST word:progress danger+ Tab insertedAlert::dangerand leftprogressin the file (Laravel Bootstrapper Snippets, 21 of 24 snippets; CSS Media Query Snippets, 4 of 5 cases). My first Bootstrapper issue said "can never be completed", which was too strong; I retested with four inputs and edited the issue. Before filing any trigger finding, run at least four typed inputs (including one whose last word is unique) and report the observed table, not a mechanism. Underscore triggers (alert_warning) expand fully. 6d. Snippets for languages with$variables (SCSS, PHP, shell, Perl; found 2026-10-21 in SCSS Snippets Complete): expand every snippet that contains a$nameand read the inserted text, not just its size. An unescaped$namein snippet content is read as a snippet variable and vanishes (#{$i}becomes#{}). Sublime's docs: "literal $ characters must be written as $" (completions.html#escaping). 4215 ships no Sass/SCSS syntax, so install theSasspackage as the dependency before testing scopesource.scss. 6e. Never wait silently (his complaint 2026-10-21, a blank screen for 7 minutes on a stalled npm install): a wait over about 60 s gets a one-line message first, and a stalled npm/download is stopped and deferred indeferred_big_installs.md, not retried for minutes. 6f. Front the test window before any step that reads the screen (Donald, 2026-10-24: "you forgot to bring the window to front... redo some of those tests"): runtools\front.ps1 -Hwnd <hwnd>in the audit repo (hwnd fromlist_native_windows) and check it printsforeground now is target: True, again after anything that may have taken focus. A background window repaints late:ui_screenshotshowed the cursor and popup one step behind (MaterialUi 2026-10-24: status bar said line 10 whileget_selectionsaid line 8), and posted Tab keys can be dropped (Material Design Lite Snippetslogin2). For every screenshot, first confirm withget_selection/get_sheetsthat the state is what I mean, and compare the status bar; if they disagree, front the window and look again. computer-useget_window_state(image) is a second view. Text read withget_view_charsis reliable either way. 6f. FILING POLICY (final, Donald 2026-10-30: "there is a perfect logic which suits everyone's needs; find it and make it policy"). There is NO age or install gate (tools\file_gate.ps1is deleted); the only test of "is anyone there" istools\is_alive.ps1, and any older note that says it "works again" is wrong (I followed such a baton line on 2026-10-30 and withheld real defects from batches 72-81). The logic keeps two acts apart. RECORD is always done: every finding goes into RESULTS.tsv, which is public, so nothing is ever lost or hidden. FILE is done when a real person can act on it, and it costs the reader almost nothing. A finding is filed when ALL of these hold, and the check takes seconds: -
Real: reproduced on 4215 in this session (or read from source with the line quoted), with the Python or build it needs named. Odd values, typos and Python 3.10+/3.14-only breakage count; his 2026-10-08 order is that maintainers need the warning.
-
Alive (his order 2026-10-30: "do the right thing; if it is dead, find out and skip it"): run
tools\is_alive.ps1 <owner/repo>. It prints ALIVE or DEAD. DEAD = archived, issues off, not found, or (last commit older than 3 years AND no comment or issue by the owner in 3 years). A DEAD repo is NOT filed: record the finding in RESULTS.tsv only (the audit repo is public, so nothing is lost). Popularity and package age do not matter, only whether a person is still there to read it. -
Welcome: the owner and repo are NOT in
data\do_not_file.tsv(owners who blocked us, asked us to stop, or rebuked us; plus sublimehq/package_control). Add a line there the moment anyone asks us to stop, and do it in the same turn. -
New: no open or closed issue already reports it (rule 000,
gh issue list --state all). Duplicates are a cost to the maintainer, so do not file them. -
Small: one issue per finding, "Claude reports:" body of a few lines, what was run, what happened, the fix as text, which version was checked (rule 6i). No PR, no fork, no second comment unless the maintainer asks something. After filing on an ALIVE repo: record
repo: last commit YYYY-MM, N open, last human reply YYYYin the RESULTS note (rule 6i) and then stop: never chase, never reply to an autoresponder, never write a PR, never fork. If a maintainer objects, stop at once, add them todo_not_file.tsv, tell Donald in one line, and post nothing back. Mail about our issues arrives in Donald's trash; the weekly closed-issue sweep (reconcile_issues.ps1) is how we learn outcomes. 6g. HIS ORDER (2026-10-28): he reads the main Sublime to keep up, so focus will be taken away from the test window all the time. Taking it back is MY job; never fail or skip a test because of it. Before EVERY step that needs the test window (a posted key, a click, a screenshot, a picker), runtools\front.ps1 -Hwnd <hwnd>and checkforeground now is target: True; if the step then does nothing (a posted Return landing in the editor, no picker response,no_viable_candidate,interrupted), front again and retry the same step, at least 3 times, before trying another route. Prefer routes that need no focus (run_command install_package/remove_package,get_quick_panel,pick_quick_panel,set_setting, tools addressed by name or index) and use the real-input route only where nothing else exists. After a posted key, verify withget_open_filesthat no stray untitled tab appeared; close it by index if one did. Never answer "could not test" for this reason. NEVER leave a test window (or WSL's msrdc) always-on-top (his word, 2026-10-28: "obnoxious and thwarts me"): no HWND_TOPMOST, and after each burst runtools\front.ps1 -Hwnd <test hwnd> -Back <hwnd of his main Sublime>(clears the topmost flag and gives the foreground back to his window; main hwnd fromlist_apps, process sublime_text.exe under Program Files; front.ps1 also clears topmost by itself on every call). Do the real-input steps in one short burst, then hand back. 6h. DIALOGS: sublime-mcp tools FIRST, computer-use only if the text is still empty (Donald, 2026-10-30; supersedes the "always computer-use for dialogs" notes of 2026-10-07 and 2026-09-25, whose reason,dismiss_native_windowignoring the button name, was fixed in sublime-mcp 1.12.x). Tested 2026-10-30 on build 4215: (1)run_commandwithsettle_ms: 800returns any dialog it raised, with its buttons AND its message text (messages), in the same reply; since sublime-mcp commit 39c20b8 (bug log B12) the message of a task dialog is read through UI Automation, so Package Control's "needs to be restarted" text comes back; (2)list_native_windowsalso lists dialogs ofplugin_host-3.14.exe, and answers while a dialog blocks the main thread (commit f1ba650, B13); (3)dismiss_native_windowwithaction: "button"andbutton: "<name>"clicked the named button and reportedclosed: true; (4)ui_screenshotwithhwndshows a dialog, also one behind other windows; (5)ui_press_keywithmethod: "post"works in pickers without focus. A computer-useclickanswered "done" while the dialog was still open, so verify withlist_native_windows, not with computer-use. Use computer-useget_window_stateonly whenmessagesis still empty, and for the Windows file-copy progress window, whichdismiss_native_windowdoes not see (untested). If a sublime-mcp dialog tool fails where computer-use succeeds, record it as a sublime-mcp weakness (rule 5). Also:close_filewith nopath,nameorindexnow refuses (B1), and theinstall_packageandsearch_packagestools no longer exist: install and remove through the palette picker, as before. 6i. LOOK BEFORE YOU FILE: record whether anyone will read it (Donald, 2026-10-30, after Gutter Color: filed on a repo with no code change since 2016, 46 open issues, no owner reply in years, and only a mail autoresponder answered). This is NOT the retired gate (rule 6f): it never stops a real defect from being filed. It makes the filing decision visible. Before filing on a repo, run once:gh api repos/<owner>/<repo> --jq '{pushed:.pushed_at,open:.open_issues_count,archived,has_issues,forks:.forks_count}'andgh api "repos/<owner>/<repo>/commits?per_page=1" --jq '.[0].commit.author.date'(date of the last code change;pushed_atcan be a fork sync or a tag) andgh api "repos/<owner>/<repo>/issues/comments?sort=updated&direction=desc&per_page=10" --jq '.[]|[.created_at,.user.login]|@tsv'(who answered lately; an account that answers within seconds every time is an autoresponder, not a maintainer). Put the three facts into the RESULTS.tsv note of the row, in this form:repo: last commit YYYY-MM, N open, last human reply YYYY. Then follow rule 6f: a DEAD repo (tools\is_alive.ps1) is recorded only and not filed; an ALIVE repo gets the short factual issue. Do not write a pull request, do not chase a reply, and do not count a mail autoresponder as an answer. Also state in the issue which version was checked (a Package Control release tag can differ frommaster; GutterColor#128 gave line numbers of tag v0.3.3, andmasterhas a different line 207): say "release vX.Y.Z" or "master", and if the two differ on a cited line, say so. -
Any halt, stall or wrong-tab action goes into the "Bug log" section at the end of
sublime-mcp\.claude\memory\reference_condensed_all_notes_2026_10_31.md(the one notes file) at once, with the state, the exact call and what he was doing.
What was already tested: use the small file, not the log
data\.tested_packages.tsv (in the audit repo, about 250 KB) lists every tested or skipped package: name, date, the line of its entry in the log, and a note (packages recovered from the queue order, for example "queue v1 #12 (done through #707)", or skip reasons). It was rebuilt on 2026-10-07 from the log headings plus queue v1 positions 1-707 and queue v2 positions 1-181; v2 positions after 181 and later-phase packages that have no log entry may still be missing. Search it (for example Grep for the package name) to decide whether a package is done. When you finish or skip a package, append one row with the same columns and a short note for skips.
TWO CATALOGS NOW (Donald, 2026-11-05: "note to self: add https://packages.sublimetext.io/ packages"). The audit is no longer only Package Control's community channel (the aggregated cache under Data\Cache\Package Control\http_cache, 5,452 names). Sublime HQ publishes its own channel at https://packages.sublimetext.io/channel.json (schema 4.0.0, 4,843 packages across 59 repositories, libraries_cache included); a channel file is also what the site's search reads. Both were compared on 2026-11-05: data\st_io_packages.tsv holds every st.io package with name, release date, version, issues URL and a tested/pending column, and data\st_io_pending.txt is the pending list (245 on that date, sorted newest first). Regenerate both with .scratch\pending.py after a batch. Rules for the comparison: a package counts as tested only when a RESULTS row for it has a note that is not a disposition (no link, not offered, not installable, repo gone, static check, queue v…, skipped, duplicate), the test must be a prefix test and not a substring one ("read-only" inside a real note must not disqualify it), and recorded names are compared with any trailing (…) qualifier stripped, because several rows are stored as Lean (syntax) or Translate-CN (issue #9 withdrawn).
data\.package_skill_test_log.md (over 1 MB) is Donald's record of how the audit is done. Keep adding entries to it, but do not read it whole and do not use it to look up what was tested; read only the lines you need, using the line number from the tsv.
Check "already tested" before EVERY package (Donald, 2026-10-11: "you missed some")
Do all four, not just the tsv name column:
.tested_packages.tsv: search the name anywhere in the row, with word boundaries (names carry version suffixes likename 1.2.5and queue prefixes like#681 name)..package_skill_test_log.md: search the WHOLE text, not only##headings. Old entries are also dated lines without a heading (2026-10-03 SublimeLinter-contrib-codespell (kaste): tested ...) and grouped headings (## LSP-some-sass, LSP-pyproject, LSP-taplo).- Transcripts in
C:\Users\donal\.claude\projects\C--Users-donal-projects-sublime-mcp\*.jsonl: searchInstalled packageplus the name (the Grep tool does 730 MB in seconds). - Judge each hit by eye: a substring hit is not a match (Bicep syntax vs LSP-Bicep, "Mar" inside "Make Bookmarklet",
LeanvsLSP-leanare different packages). When a miss is found, add a retroactive row to the tsv at once.
How the check failed on 2026-10-24 (MarkdownGlance, row 833; Donald: "tested some days ago, repeatedly"): I searched only the tsv by name and a repo-wide Grep with a glob. Grep (ripgrep) SKIPS HIDDEN FILES, and both .tested_packages.tsv and .package_skill_test_log.md start with a dot: pass their full path, never a folder glob. For transcripts search the bare package name (MarkdownGlance), not Installed package \"Name\" (the quotes are JSON-escaped in the .jsonl, so that pattern matches nothing), across C:\Users\donal\.claude\projects (all project folders, not just sublime-mcp). A package with no row can still have been installed and tested earlier (it had sat on portable 4200 until 2026-10-18); when the transcripts mention it, read the hit before installing, and ask Donald when the record is thin. His word that it was tested counts as the record.
Which sublime-mcp tools to use
Call get_help first. The tool usage (packages, menus, command palette, input panels, native dialogs) is documented in sublime-mcp's own AGENT_GUIDE.md and skills/sublime-mcp/SKILL.md; do not duplicate it here. Note: install_package is not the user picker flow, so it does not replace rule 4.
Known gap (to confirm)
No tool reads the items of an open quick panel (such as the Install Package picker) or picks one. That step is done with computer-use: type the package name, press Enter. Report it as a sublime-mcp gap.
Dialogs and windows (computer-use)
- Click dialogs with computer-use (
get_window_state, thenclickthe button by element index), every time, even after a "stopped by Escape" error (a false stop; retry, and ask Donald to run/mcpif it persists). - Keys and modifier chords fail on a window that has never been focused. Focus it first.
- Do not leave a test window always-on-top, and do not minimize it; put it back as it was. computer-use foreground steps on the WSL Sublime (msrdc window) left it topmost on 2026-10-28 (Donald: "wsl window is stuck on top"): after such steps check
GetWindowLong(hwnd, -20) & 0x8and clear withSetWindowPos(hwnd, HWND_NOTOPMOST = -2, 0,0,0,0, SWP_NOSIZE|SWP_NOMOVE|SWP_NOACTIVATE = 0x13). - Never loop commands that raise modal dialogs: run one, check with
list_native_windows.
Dialogs in the WSL Sublime (found 2026-10-28)
sublime-mcp has no dialog tools off Windows, so a dialog there shows as "main-thread timeout after 5s". Use computer-use: list_apps lists the WSLg windows (app Microsoft.AutoGenerated.{...}, name Ubuntu); the editor window's title ends "Sublime Text (UNREGISTERED) (Ubuntu)", each dialog is another window titled " (Ubuntu)". get_window_state with capture_mode=image shows the message (read it and write it down: it is the finding), then click with the x, y of its button in the picture. Then check with get_sheets. Only with Donald at the keyboard (the 2026-09-29 WSLg launch froze it); computer-use must be reconnected after the launch (type /mcp reconnect computer-use-mcp into my own tab). Install in WSL with the install_package tool (the picker is in the other host), run_command with name for text commands, and make folders with wsl.exe first: save_file answers ok even when the save fails for a missing folder.
Project windows and moved folders (2026-10-28): a WSL test that opens a .sublime-project (new window) must be closed BEFORE its folder is moved to ~/removed_packages; otherwise closing the window raises "Unable to write workspace .../p.sublime-workspace", and SublimeLinter uses a missing project folder as cwd (Errno 2). Close that window first, then move the folder. Also: pkill -x thunar can need -9; installing GUI packages with apt (nautilus) can restart WSL and kill the WSL Sublime: relaunch it with setsid nohup ~/.local/sublime/sublime_text/sublime_text & and type /mcp reconnect sublime-mcp-wsl-4200 into my own tab. Packages not in the Linux picker install by repository URL (run_command add_repository, drive_input_panel the URL; the name is then the repo name); back up and restore Package Control.sublime-settings around it.
Real-input steps and Donald's own keyboard (policy, 2026-10-20)
Computer-use answers interrupted ... user input was detected in Sublime Text when Donald (or anything) is using that window. Failing a package test over it is a skill bug, not an answer. Rules:
- Never stop on
interrupted. Callget_window_statefor that window (this clears the block) and retry the SAME call. Up to 3 tries, each at least 5 s apart. Only after 3 tries say so, in one line, and wait for his word; do not switch toui_press_key,drive_input_panelorui_type_textas a substitute for a click that needs focus (they land in the editor buffer, not the panel). - Announce a burst before it starts: one line in chat, "hands off the 4200 portable for about 2 minutes", and keep the real-input steps (click the panel, type, Return) together in as few calls as possible, so there is a short window instead of a long drift. Do the reading, writing and gh steps before and after, not in between.
- Mark the window. Before a burst, make the portable's status bar say it (
set_status/status message: "TEST RUNNING - hands off") so he can see it on screen; clear it after. - Click, then type, both with computer-use (
clickthe input panel, thentype_text/press_key).ui_clickis refused whenever another window (his main Sublime) is in front of the point; posted keys go to the editor view even when an input panel is showing. - A package that raises an input panel from a thread (Python Debugger) cannot be driven by
drive_input_panelalone: the box fills, the callback does not run. Treat that as a sublime-mcp finding and keep the package on the revisit list (sublime-mcp note trouble-in-testing-is-the-goldmine-2026-10-20).
Per-package procedure
- Say "Testing: ".
- Install through the palette picker. Wait until the package is indexed (a command from it shows up) before running anything; running commands too early produces false "Unable to find ..." dialogs.
- Check dialogs (
list_native_windows), the Package Control Messages tab and the console after every step. - Exercise the package's commands. Look at the window after each command.
- Repeat with the repo master copy.
- Clean up: reset any theme or setting that points at the package before removing it; close the tabs and panels you opened; recycle test files.
- Log the result in the test log and file one short, plain issue per finding (check existing issues first).
Driving the pickers (learned 2026-10-07)
- Focus: a never-focused portable window ignores keys. Click its title bar (element index of AXTitleBar) first, then single key presses work (letters,
minus,space,Down,Return);type_textand chords do not. - Install:
run_command show_overlay {overlay: command_palette, text: "Package Control: Install Package"}, click title bar,Return, wait until the package list is on screen (it takes a moment), type the name key by key, check the screenshot shows the right single match,Return. - Remove: use
run_command remove_package, not the palette text (the palette ranks "Remove Channel" first). The list containsLSP,MCP CommanderandPackage Control: filter by typing the package's name and check the highlighted entry beforeReturn. Never remove MCP Commander or Package Control. Wait for "successfully removed" in the status bar before reopening the list, because a list opened too soon is stale. - LSP-* wrappers installed during a session start their server only after a Sublime restart (
run_command exit, then start the portable with computer-usestart_app; its MCP server reconnects by itself or after the user runs /mcp). Many also need a separate syntax package (see the wrapper's README) and download Node or a binary, so "(installing...)" can last minutes. - The app name for the portable in computer-use changes between listings: always take it from
list_appsand use theprocess:D:\...\sublime_text.exeentry, never your real Sublime. - Console: use
get_console(mode="visible", tail=N, force_focus=true)for a complete read, on every call (tested 2026-10-11 on 4200 and 4215: no crash,complete: true; the window does not stay in front, and a title-bar click does not raise it). Withoutforce_focusvisible mode fails at once;autoandget_output_panel(which now also takesforce_focus; tested, gives a complete read with it) fall back to captured text (complete: false, with awarning).captured/get_console_logmiss startup output. Do not open the console panel and read the screen. Details:skills/sublime-mcp/SKILL.md. delete_file/delete_folderraise a Windows "permanently delete" confirmation per item on this drive and can stall; confirm each in computer-use.- Learned 2026-10-11 (AI package audit, portable 4200):
- After
show_overlay(or anyrun_commandthat changes the UI) the next computer-use key press can come back "interrupted: user input detected" for every key until you callget_window_stateonce; do that, then type. A freshly started portable answers "no_viable_candidate" to keys until its title bar is clicked. - Order that works for the Install picker:
run_command show_overlay->get_window_state(image) ->Return-> wait about 6 s for the list ->get_window_state(image) and confirm the package list is on screen (not still the palette text "Package Control: Install Package") -> one key press per letter of the name ->get_window_state(image) to see the match ->Return. Donald's rule (2026-10-11): never send the name letter by letter until a screenshot shows the Enter took effect. A press_key result ofno_viable_candidateorinterruptedmeans the keys did NOT land: click the title bar (element index of AXTitleBar), callget_window_state, and retry the Return first. - The Remove picker highlights its first row, which is often MCP Commander or Package Control: type the package's name first and check the screenshot shows the single right entry before
Return. - Dialogs: read them with
list_native_windows; ifmessagesis empty (a task dialog with custom button text) read the text with computer-use. A click byelement_indexon those buttons did nothing; click the pixel position from acapture_mode="image"snapshot. A message box may need a second or two to close after the click, so list again before clicking twice. - Use
run_commandwithsettle_ms=300when a command may show a dialog; it returns the new dialog indialogs. - A package linked in as a junction does not get its
dependencies.jsonlibraries: runrun_command satisfy_libraries, then restart the portable before testing. Libraries installed that way are not removed with the package; list them as leftovers. - Close a pathless tab with
close_file(name=...);run_command closewith scope view does nothing. - After a portable restart its MCP server may reconnect by itself: test with a call before asking for
/mcp. - Settings files written from outside Sublime are picked up late (about one command later). Run something harmless first, or check the console for "reloading settings Packages/User/...".
- After
Portable instance not connected (fixed procedure, 2026-10-07)
- Start the instance with computer-use
start_app(the .exe path), unless it is already up. - Ask Donald to run
/mcpand reconnect that server. Then wait for his word; do nothing else. - Test with one call. Connected: continue the task through sublime-mcp tools only (
remove_package, never shell recycling or another server's tools). Not connected: ask again, or read the console on screen. Never substitute another route (PowerShell, a different portable's server, HTTP) while the server is down.
Testing repo master after the release (learned 2026-10-07)
Remove the release with remove_package, copy master into Packages, then QUIT the portable (run_command exit) and start it again with start_app. Swapping a package in a running Sublime can fail with "No module named '.'" when the Python host differs between the release (3.3) and master (3.8): it is an artifact, not a package bug. After the restart a Package Control "restart for libraries" dialog may appear: click OK. The sublime-mcp server usually reconnects by itself (ToolSearch waits for it); ask Donald for /mcp only if it does not. The first key press after a restart needs a title-bar click first.
Where the package fails: build matters
Test Python plugins on 4200 first (reportable). A failure only on 4215 is build age: log it, do not file (Donald's rule). Read a package's whole traceback before deciding who is at fault; if only the last lines are visible, say so in the log.
After one failure, diagnose; do not retry
Read the package's code path and check that the command it calls exists, before trying the same action again (the niceDarkTheme Install button calls the nonexistent advanced_install_package; Package Control 4.2.8 has install_package and install_packages).
Current practice, 2026-10-13 (supersedes older lines above where they differ)
Where the older text says computer-use is needed for pickers or that scripts are forbidden: since 2026-10-08 the sublime-mcp tools get_quick_panel / pick_quick_panel / drive_input_panel / list_native_windows / dismiss_native_window / ui_press_key exist and are used. Small helper scripts that only read data outside Sublime (zip contents, gh API calls, file hashes, simulating a user's file add) are fine and always written with the Write tool, never inline shell.
Steps for one package on portable 4200 (D:\st_portable_4200)
- Build the "untested" list with a CHECKED filter. Never trust a column guess: the 2026-10-13 filter read the tier column as the name and listed already-tested packages (ACP was retested by mistake). Look at the header, print a few rows, and test the filter on a package known to be done. Then check each candidate with the four-point check above (tsv by name AND by repo owner/name, log text, transcripts).
1b. BEFORE installing, read the package repo's issues (
gh issue list --repo <owner/repo> --state all --limit 10, thengh issue viewfor any about install, Python or compatibility) and say in one line what they already report (2026-10-13: Donald asked why I tested without reading GitHub first). A known defect gets a comment with new evidence only, never a refile. - Back up
Data\Packages\User\Preferences.sublime-settingsandPackage Control.sublime-settingsto the scratchpad (Preferences.backup,PC4200.backup). Add one line toC:\Users\donal\data\misc\test_installs_to_remove_2026_10_11.txtBEFORE installing. - Launch:
Start-Process 'D:\st_portable_4200\sublime_text.exe', wait for port 9522. Then reconnect through the MAIN Sublime:ai_terminal_send_stringwas REMOVED 2026-10-19 (it now returns ok and types nothing; two reconnects were lost that way on 2026-10-19 evening). Type it like a person with the MAIN Sublime's sublime-mcp (my own tab must be the focused sheet, checkget_sheetsis_focused):ui_type_textwith/mcp reconnect sublime-mcp-portable-4200and NO newline, thenui_press_keyReturnmethodpostas a separate call. Do not read the tab back withget_sheet_content(notailargument, dumps about 20 KB; use a screenshot orget_sheets). The tools return a moment later:ToolSearch select:mcp__sublime-mcp-portable-4200__batch. Never ask him to run/mcpfor this: do it yourself. If computer-use was stopped by Escape:/mcp reconnect computer-use-mcpthe same way, immediately; do not drop it. - Install via palette:
show_overlaycommand_palette text "Package Control: Install Package",ui_press_key Return, thenpick_quick_panel text=<name> wait_ms 30000. If the palette picks a different command (Remove Package once opened "Remove Channel"), quit and delete the package the fallback way instead of retrying. - Inspect the package source first (zip in
Data\Installed Packages; read withpython -I -X utf8); then run real commands; read the console and any plugin log panel; use the REAL external tool when the package needs one (install the free one in its own folder undertools, own package.json), never a stub. - Prove before filing: reproduce, find the cause in the source, try the fix on an unpacked copy in
Data\Packages\<name>(restart first, a package folder added while Sublime runs may not load its Preferences), check existing issues, one short factual issue per finding, text starts "Claude reports:", say plainly whether a visible effect was seen. - Cleanup, in this order: close all tabs (set_scratch + close) so no Save dialog blocks;
exitthe portable; wait until no process remains; recycle the zip, the unpacked copy, user settings files the test created, the downloaded tools and clones with therecycle-deleteskill (admin throughrun-as-adminwhen Windows asks for it); restore both settings from the backups and compare file hashes; append the log section, the.tested_packages.tsvrow and thetest_installs_to_removeline.
Age is not a reason; python-version is not a reason (Donald, 2026-10-13)
Old packages are still worth testing and filing: test every package and file real defects whatever the age (the earlier "maintained only, ~4 years dead are logged, not filed" rule is retired). Never skip or stop at a package whose only problem is a missing .python-version: add one containing 3.8 to the unpacked copy, restart, and retest (DXMate: loads and registers 21 commands with it; jtowers/DXMate#2). That works only where the build has a plugin_host-3.8.exe (it did on 4200); portable 4215 has only the 3.3 and 3.14 hosts, so there a 3.8 marker makes the plugin silently not load. On 4215 test the default 3.14 host, and if a Python 3.12+ removal (distutils, imp, asyncore) is the cause, test a small fix on the unpacked copy (AGSBS Markdown Helper, AgsbsMarkdownPlugin#21). Leave package-metadata.json out of an unpacked copy: Package Control deletes such a folder at the next startup. Packages marked Sublime Text 2 only or deprecated are installed and tried too.
Paywalled prerequisites (Donald, 2026-10-13)
If a package needs something behind a paywall (paid tool, paid account), install and test everything that does not need it, say plainly what was not tried, and send the maintainer a short request to run our test technique themselves (link: https://github.com/dpc00/sublime-package-audit, PROCEDURE.md). Ideally; how anyone responds is unknown. Show him the text before it goes (an issue where issues are enabled; NO emails about ST2-only / ST2-era packages since 2026-10-27, Donald: "No st2 emails", so findings for those with issues disabled go to findings\ only), start with "Claude reports:", no pressure, no promises.
Console reads and the clipboard (2026-10-13)
get_console(mode="visible", ...) reads the console through Donald's clipboard (sentinel, copy, read, restore); his clipboard syncs to his phone, so each visible read put console text on his phone. Default to mode="captured". When a traceback or startup line is needed that captured misses (plugin load errors do show only in the visible read), tell him first and keep it to one read per package, with a small tail. A traceback can also be found by reading the package source and the library versions, or from a tee log if one exists.
When in doubt, search GitHub issues first (2026-10-13)
Before judging odd behaviour as a package defect, a Sublime quirk or a sublime-mcp gap, search issues: the package's own repo, sublimehq/sublime_text, sublimehq/package_control_channel, sublimelsp/LSP, and for harness questions anthropics/claude-code (gh search issues --repo <owner/repo> "<words>" --limit 8 --json number,title,state). Cite what you used in the log entry (ERB Snippets: matthewrobertson/ERB-Sublime-Snippets#32 already reported the scope problem). Keep the output small.
Findings that change how to judge
- 2026-10-14 (Theme - Kronuz): sublime-mcp
set_settingis VIEW-scoped (scope: "view"), so it does not touch Preferences. For theme/scheme tests editPreferences.sublime-settingsas bytes (script in the scratchpad) and restore from the ff5a4fcc baseline. A view-levelcolor_schemeleft pointing at a removed package raises one modal per redraw ("Error loading colour scheme"), which disables the editor window and makes pickers and the palette silently fail; the next package then installs but is never indexed (find_resourcesempty) until 4200 is restarted. When a picker or palette fails, runlist_native_windowsFIRST.dismiss_native_windowmay list stale dialogs; confirm with a screenshot. Never list a whole zip: filter or count (the Kronuz zip is 600 files). - A package's
Preferences.sublime-settingsadded while Sublime runs is NOT merged until restart (sublimehq/sublime_text#7012, tested 2026-10-13; ownFoo.sublime-settingsfiles load at once). A theme or package that "ignores its defaults" right after install: restart before judging. Edits to a file Sublime already knew at startup are live. eval_pythonruns on the main thread: atime.sleepin it freezes the editor and trips the tool's 5 s timeout. Never sleep in it.- ACP-style permission prompts are quick panels: read with
get_quick_panel, answer withpick_quick_panel(index or text, pass the argument insideargs). - An input panel (prompt box) is filled and submitted with
drive_input_panel. - The user's global instructions (memory scans) make Claude-based agents start with file-read permission prompts; decline them, they are not part of the package.
- 2026-10-13 (LSP-R, FileTabRename, simpleifdef, LanguageTool): (a) when you remove a package zip by hand, restore
Package Control.sublime-settingsfrom the backup BEFORE the next launch, otherwise Package Control sees the package ininstalled_packagesand downloads it again at startup, and the Install list no longer offers it. (b) PowerShellExpand-Archiverefuses.sublime-package; unpack with pythonzipfile. (c) PowerShell variable names are case-insensitive:$poverwrote$Pand a cleanup script half-ran; use distinct names. (d) Passing a single path torecycle.ps1through@itemssplats a string into characters: always@(...)-wrap the list. (e) A freshly installed LSP helper may not start until the window config is updated (sublimelsp/LSP#3074, only packages that register two plugins such as LSP-R); checkwindows.lookup(w).get_config_manager().allbefore judging a "server never starts". (f) The R language server skips diagnostics for files inside the Windows temp folder: never put R test files in the scratchpad. (g)eval_pythonselection changes (sel().add) do not fireon_selection_modifiedhere; a realmovecommand does. (h) Plugins on build 4200 need real build-4215 scope names sometimes (Simple Ifdef 0.4.0 does nothing on 4200): test on the 4215 portable and do not report it as a bug. (i) Look inside the package code for a PATH/config assumption first (LSP-R callsRfrom PATH: launch the portable with the tool's bin folder in PATH for that process only). - pick_quick_panel index is the position in the FULL picker list (the indexes that get_quick_panel returns for a filtered list), not the position in the filtered result. Pick by ext (exact name) to be safe. 2026-10-13: index 0 after a filter installed an unrelated package.
Learned 2026-10-19 (full list: audit repo notes/reference_audit_tool_findings_2026_10_19.md)
- Do not stop between packages (his rule). Stop only for an alarming error (anything touched outside the test copy) or when the reports overrun him. Keep logging with rec.ps1.
- Ctrl+C and other chords:
ui_press_keywithkey: "c",mods: ["ctrl"],method: "input",wait_idle_s: 30(real keys, brings the window forward; only when he is idle). The string "ctrl+c" fails; methodposthas no modifiers. - Exact picker index:
pick_quick_panel text=takes the first substring match (installed Jimbly's Clipboard History instead of Clipboard History). Useget_quick_panel text=<name> limit=5for the index, thenpick_quick_panel index=. Arguments are flat, not underargs. - Wait for the plugin: 20-60 s after install; commands before the "reloading python 3.3 plugin" console line do nothing silently.
open_fileis async: checkget_active_filebefore editing. - Save Changes dialogs after tests that type into pathless tabs:
dismiss_native_window button "No". - recycle.ps1: one argument per path, not an array.
Start-Sleep25 s is blocked. - ST2-only packages are not in the picker: download the zipball with
Invoke-WebRequest -OutFile(not>), extract into Data\Packages, test, recycle. - npm, pip or git on save/open: put a package.json (or a git repo) in the test folder first (npm-install emptied C:\Users\donal\node_modules again). Browser packages: scratch
--user-data-dirChrome, stop only its processes; Chrome 111+ needs--remote-allow-origins=*. - MCP reconnect (
/mcp reconnect <server>typed into the main tab) happens at once; only the message waits for the turn end. Do not stop and wait. - Later 2026-10-19: in
batch,get_quick_panel/pick_quick_panelargs went nested underargs;get_command_palettefilters bypackage/caption/command(notext; unfiltered = 200+ entries). Sublime's own pickers (Select Theme, Select Color Scheme) are invisible to get_quick_panel: screenshot, type the filter with single-letter post keys, Return. Hand copies of packages not in the channel are removed with the remove picker ("remove unknown version"), not by recycling a watched folder (UAC prompt for nothing). A command can be in the palette andrun_commandreturn ok while nothing runs (class never loaded): read the console after "reloading python 3.3 plugin". A folder swapped in under a name the package had before fails with "No module named": use a fresh name. PowerShellSet-Content -Encoding utf8writes a BOM: use[IO.File]::WriteAllTextwithUTF8Encoding($false). Package Control may leave a removed package's name in installed_packages: compare the PC settings hash after every removal.open_fileis async: check the buffer content before a command that reads it.
Keeping the public audit repo current (2026-10-16, his order 'keep that sublime-package-audit repo up-to-date')
Repo: C:\Users\donal\projects\sublime-package-audit (public dpc00/sublime-package-audit). After each batch: (1) append rows from .tested_packages.tsv to RESULTS.tsv (columns package, date, result; scrub local paths, scratchpad names, 'his word', 'Donald'; skip names already there under another date: match by prefix); (2) refresh ISSUES.tsv: run export_issues.py in this folder (gh search issues --author dpc00 in 2-day windows, about 2 minutes), then rebuild keeping the OLD row order, open issues get an empty closed date (GitHub returns 0001-01-01), append only issues on Sublime packages/tools (the export also finds claude-code, qwen-code, jcode and other non-Sublime repos: leave those out); (3) update the counts in README.md (records, distinct package names by exact lower-case name, issues, repos, open, closed); (4) add new traps to PROCEDURE.md and .claude\skills\sublime-package-audit\SKILL.md; (5) commit with the usual attribution lines and push (he said keep it up to date, so push). Last refresh: commit 76b1bce, 1058 records / 969 packages / 1091 issues / 755 repos / 809 open / 282 closed.
-
Snippet Tab tests need a fresh state (2026-10-25, NSIS Plug-in Completions #2 was first filed wrongly): after a snippet with fields expands, Tab in the same tab moves to the next field, so a second trigger typed there does nothing. Run clear_fields before each trigger, or use a new tab per trigger, and compare the snippet file contents before claiming a trigger does not expand.
-
Rule 6h (2026-10-30): a native dialog (Error loading syntax file, No file found, Save Changes) blocks window commands AND plugin loading in that window, with no console line. Before blaming a package for commands that do nothing or plugins that do not load, run list_native_windows and dismiss_native_window; I wrongly wrote that caniuse_local froze window commands (leecade/caniuse_local#12, corrected) when a Butane error dialog was open. Also read the dialog text: it held the real cause for Butane (sublime-butane#2).
6i. A dialog raised by a package command I ran can surface minutes later (2026-10-30: Grunt's 'Gruntfile.js not found!' appeared during the next batch and disabled the window, so that batch's plugins did not load until it was dismissed). After running any package command, and again before reading a plugin-load console, run list_native_windows and read the dialog text; if a dialog shows up for an earlier package, correct that package's row. A guessed syntax path in set_file_type also raises an 'Error loading syntax file' dialog: list the package's real syntax files first.
- Stale sys.path in the portable host (found 2026-10-30, batches 87-90). After a package that ships its own libs (Poster, ITDCHelper) is removed, the 3.14 host keeps its zip path on sys.path; a later package that imports a missing or Python 2 module then dies with FileNotFoundError for the removed package's .sublime-package instead of ImportError, and a ry/except ImportError does not catch it. Do not record an import failure from such a trace: read the source (is the import guarded?) and, if in doubt, restart the portable (
run_command exit,start_appon sublime_text.exe, type/mcp reconnect sublime-mcp-portable-4215into my own tab, then Return as a separate call) and retest. JSCS-Formatter was wrongly recorded as a load failure this way and corrected. - Install picker index (2026-10-30). In the Install Package picker
pick_quick_paneltakes the GLOBAL index returned inindexesbyget_quick_panel, not the position in the filtered list (picking 0 installed0x0). In the Remove Package pickerindexesare the positions in the installed list (they shift after each removal). Log a mistaken install in the ledger like any other. - README figures (2026-10-30).
tools\rec.ps1recomputes every number in the README from RESULTS.tsv and ISSUES.tsv (records, packages, static-only count, issues, open/closed/unreadable, time to close, merged PRs). After filing issues add them with-Issues(or append to ISSUES.tsv) and runrec.ps1 -RefreshOnly; refresh ISSUES.tsv from GitHub withtools\reconcile_issues.ps1and copydata\ISSUES.reconciled.tsvover it now and then. Never type a figure into the README by hand.