kittymux

Testing

Run the unit tests and the real-kitty rigs without touching your own kitty, config or state, and see which edge cases still need a person.

Do not use your everyday configuration, socket, state directory or provider credentials as test fixtures. A green unit suite is not proof of compositor support or of current vendor response formats.

The fast gate

python3 -B -m unittest discover -s tests
bash tests/test_mux_status.sh && bash tests/test_socket_lib.sh
git diff --check

Also run bash -n and shellcheck -S error on changed shell files, and python3 -m py_compile on changed Python. Continuous integration must call each shell test explicitly: passing a script as an argument to another script does not run it.

The real-kitty rigs

Each rig starts its own kitty, usually in a virtual display (Xvfb) with a private configuration, socket and state directory. They skip when a tool is missing. SKIP is not a pass. Record the reason and the kitty version.

RigWhat it proves
test_install.shA fresh home installs, reinstalls, validates, passes doctor and uninstalls.
smoke_state.shStates come from screens, the spinner rate on an idle window and a spacer-row click.
smoke_reload.shA kitty upgraded under itself draws cleanly after two reloads. SMOKE_KEEP_STALE=1 must fail.
smoke_sidebar.shThe collapse button, the right-click peek and an edge drag, with real mouse events.
smoke_drag.shTab drag-to-reorder with real pointer events.
smoke_click.shTab clicks with wobble and slowness. A middle-click spares an agent tab.
smoke_native.shThe native divider's pixels, the real X cursor name over it, a native drag and the single-pane fallback.
smoke_resize.shA fast pointer burst: the bar edge reaches the pointer and every tab re-flows on release.
smoke_panes.shPane numbers agree between ctrl+alt+e, ctrl+alt+1 to 9, ctrl+alt+0, resize and equalize. The scroll keys work.
smoke_place.shThe folder line: twins, hidden duplicates, worktrees, a split's room, each switch alone, and all off equals the old line.
smoke_panetitle.shThe folder line in pane title bars and the fallback when the switch is off.
smoke_titles.shWhat a tab is called through renames, restores, resumes, stale and hostile titles.
smoke_join.shA three-pane tab joins a two-pane tab: all panes present, the shape kept, no sliver, bad input harmless, other layouts, other OS windows and an overlay target.
smoke_join_ui.shThe join list with real key and mouse events: the chord, one esc, no stacking, filter, side, scope, hover, ⏎, left click and a right click that does nothing.
smoke_keys.shThe keymap overlay closes on one esc, q or the chord, never stacks, and filters as you type.
smoke_resume.shSave then restore: the prompt, resume flags, ambiguity, autosave and pruning.
smoke_spawn.shSpawn by CLI and by real keys, pick through a fake rofi, reopen, mute and snooze, with fake agents.
smoke_fanout.shOne prompt to three fake agents in three real worktrees, then compare and clean. The main checkout is untouched.
smoke_changes.shA fake agent edits a real repository: baseline, summary, exclusions, repository untouched.
smoke_socket.shsocket-only refuses a printed escape sequence while yes obeys it, and the runtime directory socket is found.
smoke_inbox.shReal OSC 99 notifications become typed inbox events, and focus acknowledges.
smoke_workflows.shTwo kitties with overlapping ids: scratch isolation, target pid checks and an attention jump.
smoke_demo.shkittymux demo opens every showcase tab.
smoke_openref.shctrl+shift+click on src/app.py:42:7 opens the editor at line 42.
smoke_extras.shkittymux screenshot, and kittymux dim when slangc exists.

Run display-sharing rigs one after another. Use SMOKE_SHOT=<absolute path prefix> with smoke_sidebar.sh to keep screenshots. To look at a visual change, render the bar with tests/shot_bar.sh in dark and light and at the narrowest width, then read the picture. For the panel use tests/shot_panel.sh dark|light OUT_DIR [COLS] [LINES] (KITTYMUX_USAGE_HOME=DIR points the usage collectors at the synthetic home it builds; unset, they read yours): it runs the real panel in a private kitty on a synthetic world (tools/demo_world.py), drives it with real key events, checks the text of the Agents, Usage and Inbox views and saves a PNG of each. Unit tests did not catch a hue palette of four near-identical greens.

The rules a rig must follow

  • Never touch another kitty on the machine. The author is usually typing in a live kitty while tests run, and kitty @ launch follows focus. A rig once spawned fake agents, and through a different PATH the real claude, into the live kitty. Set KITTYMUX_SOCKET_DIRS to the rig's own directory and end with a tripwire that compares the window count of every other kitty.
  • Run under socket-only. Never write a rig or a doc that needs allow_remote_control yes.
  • Use real events. A perfect scripted click hides whole bug classes. Click with wobble.
  • Keep modules as real copies in one configuration directory. A rig that mixes repository and configuration directories hides real bugs.
  • Remove only your own instances in cleanup. Never kill processes by name.

If your /tmp is full

The rigs write a few hundred megabytes under /tmp. If your temporary directory has a quota that is already used up, run them inside a private mount: unshare -rm sh -c "mount -t tmpfs tmpfs /tmp && bash tests/smoke_join.sh". Keep scripts and output elsewhere, such as ~/.cache.

The docs gate

python3 -m unittest tests.test_docs checks the published pages: frontmatter, navigation, links and anchors, the feature status table, that every ctrl+alt chord a page names is really bound, and that the CLI reference covers every command. See Docs maintenance.

Edge cases

BoundaryAutomated checksStill needs a person
Remote controlIn-band control refused under socket-only, with a positive control. Missing or foreign sockets fail closed.Custom runtime paths and restricted /proc.
Scratch tabsOverlapping instance ids, stale flags, the wrong OS window.Concurrent scratch commands.
Scanner and attentionDebounce, focus acknowledgement, hook-only completion, startup replay suppression, timer reload lifecycle.Agent wording changes. Verify a real screen before changing a pattern.
Previews and resizeSingle-flight work, reordered callbacks, shutdown, the final release past the throttle.Real layer-shell panel resizing on each compositor.
Usage HUDProvider failure, malformed responses, cooldown, exact counters, midnight and daylight-saving boundaries.Opt-in live responses from each vendor.
Restore promptHostile records, keys including a lone esc, no terminal, missing binary, through a real pty.Each real agent's resume against a real conversation. Run sessions check.
Folder lineLayout at every width, hue contrast on dark, light and grey themes, switch precedence, a real kitty drawing each case.Panel placement on Hyprland (tests/probe_panel.sh), looks on your own theme and font.
JoinPlanner properties on random layouts, placement in a real kitty, and the list with real keys and mouse.Your own tab layouts, and a real Wayland pointer.

Tests use fake credentials, temporary state and synthetic provider responses. Never turn a mocked response or a virtual-display run into a claim of live-provider or compositor verification.

Before applying a tested branch

  1. Check main and the worktree for unrelated edits. Do not stash or overwrite another person's work.
  2. Bring new main commits into your branch, resolve conflicts there and repeat the gates.
  3. A local edit to a file the branch changes is a blocker. Have its owner reconcile it first.
  4. Record the OS window, tab and pane counts for every live kitty socket you own, without dumping pane text.
  5. After a clean fast-forward, run the main checkout's bin/kittymux upgrade. Never restart.
  6. Compare the counts and check ~/.local/state/kittymux/tab_bar-error.log. If the counts differ, investigate. Do not close or recreate windows to make the numbers match.

On this page