Files
hqt/docs/superpowers/specs/2026-06-11-tmux-window-index-reset-design.md
T

4.1 KiB

Reset tmux window indexes

Date: 2026-06-11 Status: Approved

Goal

Add reusable functionality that compacts tmux window indexes inside the hqt tmux session so keyboard shortcuts such as Alt+1, Alt+2, and Alt+3 stay useful after windows have been closed.

This reset affects only tmux window indexes. It does not change database session IDs, tmux_session_name, harness conversation IDs, nicknames, panes, or running processes.

Behavior

The reset operation works on the configured hqt tmux session:

  • The home/TUI window always ends at tmux index 0.
  • Every non-home window keeps its current name, pane, process, and content.
  • Non-home windows are sorted by their current tmux index.
  • Those non-home windows are moved into contiguous indexes starting at 1.

Example:

0: ⌂ HQT
1: hqt-foo
4: hqt-bar
9: hqt-baz

becomes:

0: ⌂ HQT
1: hqt-foo
2: hqt-bar
3: hqt-baz

If the home window is not already at 0, it is moved to 0 first, then the remaining windows are compacted after it in their original index order.

Architecture

Add the reset at the tmux layer rather than the session or database layer. Existing app and service code targets windows by name, so changing tmux indexes should not disturb attach, stop, delete, status polling, or label syncing.

Runner

Add a low-level method on TmuxRunner, for example:

async def reset_window_indexes(self, home_window: str) -> bool:
    ...

The method should:

  1. List windows for self.session_name with #{window_id}, #{window_index}, and #{window_name}.
  2. Find the row whose name matches home_window.
  3. Move the home window to index 0 if needed.
  4. Sort all other windows by their original index.
  5. Move each non-home window to 1..N in that order.

Use move-window with window_id as the source target so changing one index cannot make a later move target the wrong window. The destination should target the configured tmux session and explicit index.

The implementation should be idempotent: running it against an already compact session should return success without changing anything meaningful.

Manager

Add a thin delegate on TmuxManager, for example:

async def reset_window_indexes(self, home_window: str) -> bool:
    return await self.runner.reset_window_indexes(home_window)

No SessionService change is needed for the initial implementation. This is a tmux maintenance operation, not a session lifecycle operation.

Command Surface

Implement the reusable operation now and defer user-facing wiring. A command palette is planned separately, so this feature should expose a callable method that the future command can invoke.

Do not add a TUI keybinding or footer item in this change.

Error Handling

  • If the configured tmux session does not exist or cannot be listed, return failure and leave the database untouched.
  • If the home window is missing, return failure rather than guessing which window should become index 0.
  • If a move-window command fails, return failure. The operation may have partially moved tmux windows before the failure; this is acceptable because tmux indexes are maintenance metadata and no persisted hqt state is changed.
  • Log tmux stderr for failed operations to aid debugging.

Testing

Add focused tests in tests/test_tmux.py:

  • Missing home window returns failure and performs no moves.
  • Already compact windows return success.
  • Sparse indexes compact in current index order: 0 home, 1 foo, 4 bar, 9 baz moves bar to 2 and baz to 3.
  • Home initially not at 0 is moved to 0, and all other windows compact to 1..N in original order.
  • Moves target stable window identities, not mutable index-only targets.

The implementation must pass the project checks after code changes:

uv run ruff format src tests
uv run ruff check src tests
uv run ty check

Out of Scope

  • Changing database primary keys.
  • Changing Session.tmux_session_name.
  • Changing harness session IDs or resume behavior.
  • Adding command palette UI, keybindings, or footer labels.
  • Enabling permanent tmux automatic renumbering.