Window management
Hocket includes a small tiling window manager for its terminal, agent, Git, process, and editor surfaces. It is built for a terminal: every operation has a keyboard path, directions follow what is visibly on screen, and ordinary keys continue to belong to the program running inside a terminal pane.
This guide describes the model first and the commands second. The distinction between a Panel and a pane is important:
- A pane is one tiled window: a terminal or agent, Git history, Processes, or the Editor group. Terminal-kind panes are instances (ADR-0020): a Panel can tile as many terminals and agents as you want, each showing its own session. Git, Processes, and the Editor group remain one-per-Panel.
- A Panel is one of four saved window arrangements. A Panel remembers which panes are open, their arrangement and sizes, focus, fullscreen state, and the File Tree/Editor division.
- The Sidebar and Status Bar are shell chrome. They are not tiles in the pane layout. The Sidebar can be resized with the mouse, but it cannot be moved, closed, or tiled among the panes.
The pastel 1 2 3 4 strip at the lower right identifies the active saved Panel. Panel 1 initially contains a terminal. Panels 2–4 initially provide an empty workspace that teaches the pane-creation keys.
The two interaction levels
Hocket separates working inside a pane from arranging panes.
PANE: work inside the selected surface
This is the normal state. Typing in a terminal goes to the embedded program; typing in the editor edits text; arrows navigate the focused list or buffer. The Status Bar labels this state PANE.
PANE interactions follow three rules:
- Unmodified keys belong to the focused surface. Arrows move its cursor or selection and stop at its edges; they never silently move focus to another pane.
alt+shift+arrowexplicitly moves focus to the closest pane in that direction. At an outside edge it is a no-op. This chord is reserved by Hocket even when a live terminal has focus.- Clicking a pane focuses the surface clicked. Dragging a shared border resizes it without entering PANEL.
Direct addresses are useful when the destination is known:
Window actions that do not require PANEL remain available from PANE:
alt+return is an alias)alt+wClose the focused surface — a live terminal/agent session detaches and keeps runningalt+zUndo the latest reversible application actionA live terminal owns ordinary terminal and application-looking chords, so shell and full-screen programs keep their normal controls. For example, ctrl+c, ctrl+d, ctrl+p, ctrl+t, ctrl+w, and Option word movement are forwarded to the embedded program. Hocket's global chords in the tables above remain reserved. In non-terminal panes, arrows, Enter, Escape, Backspace, printable filtering, and editor shortcuts act locally; the complete surface-by-surface list is in the Keyboard map.
PANEL: arrange the windows
Press shift+escape to move outward into panel-selection mode. The selected pane stays at full strength, the other selectable panes dim, and the Status Bar changes to PANEL. The selection belongs to the pane, not to a fixed position. Projects has no border, so as the selected stop it wears a full-height accent ▌ edge column instead, its row-level voice quieted.
While PANEL is active:
t/a always open a new pane and never displace one already on screenf, then arrow if absentSelect Files, or add it on that side when absentbackspaceClose the selected movable paneshift+1…4Jump to a saved Panelshift+left/rightMove to the adjacent saved Panel without wrappingshift+up/downSelect the previous/next visible worktree when Projects is selectedenter or escapeMove inward and work inside the selected paneSelection and focus are related but not interchangeable. Arrow keys in PANEL move the selection; they do not send input to pane contents. Leaving PANEL puts input focus inside the selected pane.
The adaptive tiling model
Panes are held in a tree of binary splits. Every split divides one rectangle into two child rectangles. This has a few user-visible consequences:
- Adding a pane splits one existing tile. It does not recompute a uniform grid or replace an unrelated pane.
- Closing a pane removes its tile and gives the vacated region to its sibling.
- Resizing moves a particular shared boundary. Other branches keep their geometry unless that boundary contains them.
- A nested group of panes can share one side of a larger pane.
The orientation is adaptive. A split is side by side when its available region is wide and top-to-bottom when it is tall. The stored relationship is still the same when the terminal changes size; only its most useful visual orientation changes. Press j to invert the adaptive choice for the selected pane's immediate split.
For example, this is one root split whose right child contains another split:
+--------------------+----------+ | | G | | T +----------+ | | P | +--------------------+----------+
The terminal shares a root boundary with the whole G/P group. Git and Processes also have a smaller boundary between themselves. Operations prefer the most local boundary that actually touches the selected pane.
The Editor is an attached group
The Editor occupies one tile in the outer split tree. Files and the text editor form an inner split inside that tile. Horizontal movement or resizing between Files and the buffer changes that inner split. An operation crossing the outside edge treats the complete Editor group as one pane, preserving the File Tree's order and width within it.
Moving panes
In PANEL, alt+arrow moves the selected pane by swapping it with the closest pane in that direction. The move is spatial: Hocket compares the rectangles currently drawn on screen, not creation order or pane type.
With two panes, the result is direct:
before alt+right after +----------+----------+ +----------+----------+ | T* | G | --> | G | T* | | terminal | git | | git | terminal | +----------+----------+ +----------+----------+
The * marks the selected pane. It remains selected after moving, so alt+left moves it back. Stacked panes behave the same way:
before alt+down after +---------------------+ +---------------------+ | T* | --> | G | +---------------------+ +---------------------+ | G | | T* | +---------------------+ +---------------------+
A moved pane carries its size
A move treats the selected pane's current width and height as constraints at the destination. The pane does not simply inherit the destination tile's old dimensions. Hocket adjusts the relevant split ratios so the pane keeps its size in terminal cells.
before: T is 70 columns alt+right after: T is still 70 columns +--------------+------+ +------+--------------+ | T* | G | --> | G | T* | +--------------+------+ +------+--------------+
Size preservation is a constraint, not a promise to overlap or hide another pane. Every visible pane must retain at least 18 columns and six rows. In a nested destination, the old dimensions may not fit alongside the destination pane's siblings. Hocket then chooses the closest legal size: it preserves as much of the moved pane's dimensions as possible while the minimum-size constraints win.
Alignment sits between those two forces: minimums, then alignment, then the carried size. When the carried dimensions would tear a boundary line that currently runs continuously across the workspace — two splits meeting in one line, or a line on the 2×2 grid — the alignment wins and the carried dimension yields, exactly as minimums already win today. In a freeform layout with no continuous lines, moves carry their size unchanged.
This rule makes repeated moves feel like moving a window rather than replacing the label on a slot:
- The moved pane carries its dimensions.
- The pane displaced from the destination receives the released region.
- Boundaries elsewhere in the tree remain unchanged unless they must move to satisfy the carried size.
alt+zrestores the complete pre-move tree and all of its ratios.
Choosing a neighbor in a nested layout
When one large pane borders several smaller panes, Hocket chooses the closest pane in the requested direction. Here, moving the terminal right chooses Git because Git is closest to the terminal's center:
before alt+right after +----------+----------+ +----------+----------+ | | G | | | T* | | T* +----------+ --> | G +----------+ | | P | | | P | +----------+----------+ +----------+----------+
The drawing shows the topological swap. The exact boundary after the move can shift because T also carries its prior width and height constraints.
Moving Processes up swaps only Processes and Git:
before alt+up after +----------+----------+ +----------+----------+ | | G | | | P* | | T +----------+ --> | T +----------+ | | P* | | | G | +----------+----------+ +----------+----------+
A move toward an outside edge is a no-op because no pane exists in that direction.
Some terminals encode Option+Left/Right as the traditional shell chords alt+b and alt+f. Hocket accepts those encodings as move-left and move-right while PANEL is active. Outside PANEL they remain available to the embedded program for word movement.
Adding panes with a directional split
When PANEL highlights a no session terminal tile, Enter opens an in-place pane chooser. On a focused no session pane, Enter does the same and the advertised f, t, a, g, and p keys choose directly; either path borrows PANEL semantics without changing PANE/PANEL mode. Press t for a terminal, a for an agent, g for Git history, or p for Processes; escape cancels and leaves PANEL active. Git and Processes replace the empty tile instead of adding a split. If the chosen utility pane is already open elsewhere, it moves into the empty tile and its old tile is removed — utility panes stay one-per-Panel. t and a fill the empty tile itself: the Panel's owned session of that kind if one exists, otherwise a fresh shell or the new-agent prompt.
When the followed worktree has running sessions the pane doesn't own, the chooser adds an or pick up section listing them — Status Glyph and name, newest visits first, up to five. Press the row's digit to pick one up: the session moves into this pane (transferring from any Panel that owned it, ADR-0018) with its screen and scrollback intact. The full list of sessions always lives in the Sidebar, Recent (cmd+e), and the palette.
The ctrl-n new-agent prompt speaks the same clause. When the target worktree has detached agents (bound to no Panel's pane), the prompt's recent-command digits continue into an or pick up section — Status Glyph and name, newest visits first, up to three — so starting "a new agent" never silently twins one that's parked. Enter on a highlighted pick-up row picks it up; enter anywhere else runs the typed command as before. Only truly detached sessions appear here: stealing a session another Panel still shows stays the pane chooser's job.
In PANEL, type a pane mnemonic and then the side on which it should appear:
g, then an arrow: Git historyp, then an arrow: Processest, then an arrow: a terminala, then an arrow: an agent terminal
A centered placement prompt names the pending pane and teaches arrows place and enter replace · esc cancel. The selected tile becomes the anchor: an arrow splits that tile and creates the pane on the requested side, while enter puts the new pane in the anchor's exact tile instead. The replaced pane closes with the pane-close contract — a live session detaches and keeps running.
before g, then down after +---------------------+ +---------------------+ | T* | --> | T | | | +---------------------+ | | | G* | +---------------------+ +---------------------+
The letters always enter make and place: every f, g, p, t, or a press opens the placement prompt before changing a pane or session. The one Panel state with nothing to place against is a naked Panel — no panes open at all — where the letter creates its pane directly into the empty workspace, no prompt. For t and a the placed tile is a new pane instance every time (ADR-0020): the arrow splits the anchor and the fresh shell — or the new-agent prompt, whose or pick up rows keep a parked agent from being twinned by accident — lands in the new tile. Sessions already on screen are never displaced by creation; enter replace is the one deliberate exception, closing the anchor under the pane-close contract (a live session detaches and keeps running). Utility panes remain unique per Panel; their placement choice confirms the existing tile. The 1…6 addresses remain the way to select any existing surface without creating. Press escape while the placement prompt is open to cancel without changing the layout or its content.
Spawns that arrive without a placement gesture — ctrl-n, the esc 3/ esc 4 addresses when the Panel owns nothing of that kind, the palette's "New terminal here" — fill the focused terminal pane only while it is empty or exited; otherwise they split beside it. Repeating ctrl-n grows a crew of agent panes rather than taking one over.
Flipping a split
Press j in PANEL to invert the selected pane's immediate split between the adaptive and opposite orientations:
side by side j stacked +----------+----------+ +---------------------+ | T* | G | --> | T* | | | | +---------------------+ | | | | G | +----------+----------+ +---------------------+
Only the immediate parent split changes. More distant branches retain their orientation and ratios. Pressing j again removes the inversion.
Resizing: push the box boundary
Resizing follows a push model. Think of the selected pane as a box with four boundaries. In PANEL, alt+shift+arrow pushes the boundary named by the arrow outward by one terminal cell:
alt+shift+leftpushes the left edge left.alt+shift+rightpushes the right edge right.alt+shift+uppushes the top edge up.alt+shift+downpushes the bottom edge down.
The pane grows into the space on that side; it does not move, and the opposite edge stays anchored. Hold the arrow to use normal keyboard repeat.
before alt+shift+right after +----------+----------+ +-------------+-------+ | T* | G | --> | T* | G | | | | | | | +----------+----------+ +-------------+-------+
Hocket only pushes an edge that actually bounds the selected pane. In a nested layout it tries the smallest matching boundary first, then a larger coincident boundary if the local one has reached its limit. Resizing stops before any pane becomes smaller than 18 columns or six rows. Resizing toward an exterior edge, past a size limit, or while the workspace is in overflow is a no-op.
The chord is deliberately contextual. In normal PANE use, alt+shift+arrow moves focus to the pane in that direction. After shift+escape enters PANEL, the same chord acts on the selected box and pushes its boundary. The Status Bar's PANE or PANEL label makes the active meaning visible.
One held-key resize gesture creates one undo entry, rather than one entry per repeated cell.
Boundaries are magnetic
Every boundary has a small set of snap targets on its axis: the workspace half-line (the 2×2 grid line), the position of every other parallel visible boundary — so two nested splits can meet in one continuous line — and, for the Files boundary, its default width. Targets are filtered through the same minimum-size rule as resizing itself: a landing that would crush any pane below 18 columns or six rows is never offered.
A discrete press still moves exactly one cell, always. During a held repeat, the boundary pauses for one repeat tick when it reaches a target — a detent you feel through the key repeat, so releasing on the grid is easy and single taps are never consumed.
Approaching a target shows a dim guide line across its extent; landing pulses the boundary briefly in the accent color, and the status bar's contextual slot reads ½ while a boundary sits on a grid line. A landed grid position is stored as an exact fraction, so an even layout stays even when the terminal window changes size.
Mouse resizing
Drag any shared pane border to resize it continuously. Drag the border between Files and the editor to resize the inner Editor split. The same minimum sizes apply to keyboard and mouse resizing. Drag the Sidebar's right edge to resize the fixed shell chrome independently. alt+z restores the size from before a completed drag.
Dragged boundaries share the keyboard's magnetism. Within two columns (or one row — the same visual distance) of a snap target, the boundary sits on the target; beyond that it follows the pointer exactly, so escaping a snap is just dragging on. The dragged position is always a pure function of the pointer — a snap never fights the hand holding it.
Evening out: = snaps to the grid
Press = in PANEL to even the layout out in one step: splits move to ½, parallel boundaries become collinear, and where a minimum size intervenes the boundary lands on the nearest legal cell instead. The result is the cleanest 2×2 the current panes allow.
before = +----------------+------+ +------------+------------+ | | G | | T | G | | T +------+ --> +------------+------------+ | | P | | Files ┆ editor | +------+---------+------+ +------------+------------+ | Files ┆ editor | +------+----------------+
Evening out is one reversible action: alt+z restores the exact prior tree and every ratio. When the layout is already even, = pulses the boundaries instead — confirmation, not silence.
The Editor group evens out as one window. Its outer rectangle takes the clean half or quadrant; inside it, Files keeps its width in cells and the buffer absorbs the change, mirroring how a moved pane carries its size. The inner Files boundary is a line other boundaries may align to, but evening out never moves it — inner geometry changes only by direct resize or when minimums force it. The same holds for every outer resize of the group: the tree's width is the stable part, the buffer is the elastic part.
Small terminals and stacked overflow
The tiling tree is not destroyed when the terminal becomes too small. If the available width or height cannot give every pane a useful body, Hocket switches to a temporary stacked presentation:
- The active pane receives the available body.
- Each inactive pane remains visible as a three-row identified header.
- Moving focus changes which pane receives the body.
- Pane resizing is disabled because the underlying tiled edges are not being presented.
The original split tree, pane order, flipped orientations, and ratios remain intact. Growing the terminal restores the tiled arrangement exactly.
Fullscreen
Press alt+escape from a focused pane to make it fill the workspace; alt+return is a compatibility alias. Fullscreen is a presentation state, not a destructive layout operation. Sibling panes remain in the saved split tree and return with their positions and sizes on restore.
The fixed Sidebar is hidden while fullscreen owns the workspace. A highlighted bar names the fullscreen pane and teaches the restore gesture. A fullscreen terminal also receives its new PTY dimensions so applications such as editors, pagers, and dashboards redraw at the full size.
Press alt+escape again, or use the taught shift+escape restore path, to return to the complete layout.
Closing panes
backspace in PANEL closes the selected movable pane. From ordinary PANE focus, alt+w closes the focused surface without first entering PANEL.
Closing is surface-aware:
- Terminal or agent: detaches a live session — it keeps running and stays in the Sidebar, Recent, and the palette; the tile closes with it and the status bar confirms
detached · <name> keeps running. Kill and Close remain explicit verbs (Sidebarbackspacekills and closes together after confirmation; the palette and context menu expose separate verbs). An exited session closes for good; a session-less pane (showing its placeholder) closes immediately. - Git or Processes: hides only that utility pane.
- Files: hides the File Tree without closing editor buffers.
- Editor: retains its buffer-level close behavior.
- Sidebar/Projects: fixed shell chrome; it cannot be closed through the pane manager.
cmd+backspace kills the live session in a focused Terminal or Agent pane without closing its tile. It has no effect when another surface is focused.
Removing a tile promotes its sibling subtree into the vacated region. Opening Git or Processes is additive: existing panes remain open until explicitly closed.
Four saved Panels
The four saved Panels are independent window arrangements over shared work:
- Each remembers open panes, split topology, ratios, flipped splits, focus, fullscreen state, and the Files/Editor split.
- Switching Panels does not kill sessions or duplicate editor buffers.
- Selecting a different worktree changes the content followed by Git, Files, Processes, and the active agent without rearranging the current Panel. When the followed worktree has no owned session, the tile stays in place as a generic empty pane — browsing never adds or removes panes, and the tile can be filled in place with Files, Terminal, Agent, Git, or Processes.
- Each terminal/agent pane exclusively owns its session per worktree (ADR-0018, pane instances per ADR-0020). Deliberately picking a session — spawning,
alt+ncycling, entering a session row,esc 3/esc 4— binds it to a pane of the active Panel and transfers it from any previous owner; selecting a session already tiled on screen focuses its pane instead of cloning it, andalt+ncycles only sessions not shown in a sibling pane. A new or unbound pane stays empty instead of cloning the session on screen in another pane or Panel. - Agent sessions are terminals with an agent in the foreground. Interrupting that foreground with
ctrl+creturns the same pane and session to the user's shell; its sidebar row remains under the worktree where it was created and changes from agent to terminal. Explicitly stopping the session still ends the whole terminal, while other agent exits remain visible for inspection. - Entering a Sidebar session explicitly selects that session and moves to its agent pane. If the active Panel has no agent pane, Hocket opens one there.
In PANEL, use shift+1…4 to jump directly. Use shift+left/right for the adjacent saved Panel; navigation stops at 1 and 4 rather than wrapping. The active number remains visible in the lower-right strip in both PANE and PANEL.
Panel arrangements are persisted under Hocket's state directory and restored on the next launch. Changing one saved Panel does not alter the other three.
Undo and persistence
alt+z undoes the most recent reversible application action, even while a live terminal has focus. Window-management actions participating in undo include:
- pane moves, including their carried size constraints;
- keyboard and mouse resizing;
- split flips;
- fullscreen changes; and
- Sidebar resizing.
Undo restores the captured layout rather than trying to calculate an inverse, so nested topology and exact ratios return together. It is a single-level last-in-first-out application history with no redo command. Destructive or external actions such as killing a process, saving a file, or quitting are not presented as undoable.
Saved Panel state is continuously updated. Undo therefore changes the saved arrangement too; the restored layout is the one that will appear after the next launch.
Quick reference
The complete application key map, including remapping syntax, is in Keyboard map.