A pane cannot be moved. Not by an agent, and not by the operator.
Workbench has insert(_:at:) for a new pane and moveFocus(_:) which moves the keyboard, not the pane. There is no reorder, no swap, no relocate, and no drag-and-drop anywhere in Sources/Helm/Workbench/. The only way to get a pane somewhere else today is to close it and make a new one — which loses the process inside it.
This is the operator's own ask, and it is the capability #269 was actually about: "helm-command was more about moving a pane from one position to another — I also want that for me."
Why it is one ticket and not two
The primitive is missing, not merely unexposed. Both surfaces need the same operation, and building it for one of them first means building the wrong shape:
- The operator wants a gesture — a keyboard shortcut, and probably a drag.
- An agent wants a request — a
helm-command kind naming a pane and a destination.
Workbench is a value type holding columns of slots, so the move itself is a data operation that is fully testable with no UI, no surface, and no display. That is where it belongs, and both callers should reach the same function.
It fits the focus rule exactly, which is why it belongs in the allowlist
#269 established: rearranging the bench is fine, taking focus is not. A move is the purest possible case of rearranging — and the four commands currently allowed (newTerminal, splitRight, splitDown, toggleRail) are the ones that happened to have non-seizing twins, not the ones anyone wanted most.
The ticket noted why the rest were refused: "every command still refused is one with no address at all — it acts on focusedSlot, so there is nothing for a policy to check." A move names its pane and its destination. It has an address, which is exactly what was missing. It is the first command that can be allowed on the rule rather than despite it.
The decisions worth making deliberately
Does focus follow the pane? These pull in opposite directions and both are defensible:
- The operator moving their own pane almost certainly wants their keyboard to go with it — they are looking at it.
- An agent moving a pane must not move the operator's focus, ever.
So focus-following is probably a property of who asked, not of the operation. That is the same shape as helm-close's force rule: what a request may assert depends on whether it owns the thing. Say it once, in a policy type, with the argument in its header.
What is the address? A pane uuid plus a destination. The bench snapshot already publishes both — pane id, column index, slot index — so an agent can compute a move from a file it already reads. Whether the destination is (column, slot), or relative (left, right, up, down), or both, is a real choice: relative is what a keyboard shortcut wants, absolute is what an agent wants.
What happens to an emptied column? And to a move that would create one? Whatever the answer, it should be the same one the close path already gives.
Scope: within a workspace. Moving a pane between workspaces is a different feature with a different set of questions, and it should not be smuggled in.
Acceptance
Workbench can move a pane, tested as a value operation — no UI, no display, no surface.
- The operator can do it by keyboard, and the shortcut lives in the Workbench slice with its neighbours.
- An agent can do it through
helm-command, and the result says what the bench looks like after.
- Focus behaviour is decided per caller, argued in a policy header, and tested both ways — an agent's move must leave
focusedSlot untouched, and there must be a control that fails if a move stops moving anything at all.
- An emptied column behaves the way closing the last pane in one already does.
- Driven against a live helm before it is believed. No gate can prove a pane moved.
Related
#269 (the command channel and the focus rule), #176 (ownership deciding what a request may assert), #39 (the workbench itself), #284 (an agent selecting a pane it created — the same ownership question one step over).
A pane cannot be moved. Not by an agent, and not by the operator.
Workbenchhasinsert(_:at:)for a new pane andmoveFocus(_:)which moves the keyboard, not the pane. There is no reorder, no swap, no relocate, and no drag-and-drop anywhere inSources/Helm/Workbench/. The only way to get a pane somewhere else today is to close it and make a new one — which loses the process inside it.This is the operator's own ask, and it is the capability #269 was actually about: "helm-command was more about moving a pane from one position to another — I also want that for me."
Why it is one ticket and not two
The primitive is missing, not merely unexposed. Both surfaces need the same operation, and building it for one of them first means building the wrong shape:
helm-commandkind naming a pane and a destination.Workbenchis a value type holding columns of slots, so the move itself is a data operation that is fully testable with no UI, no surface, and no display. That is where it belongs, and both callers should reach the same function.It fits the focus rule exactly, which is why it belongs in the allowlist
#269 established: rearranging the bench is fine, taking focus is not. A move is the purest possible case of rearranging — and the four commands currently allowed (
newTerminal,splitRight,splitDown,toggleRail) are the ones that happened to have non-seizing twins, not the ones anyone wanted most.The ticket noted why the rest were refused: "every command still refused is one with no address at all — it acts on
focusedSlot, so there is nothing for a policy to check." A move names its pane and its destination. It has an address, which is exactly what was missing. It is the first command that can be allowed on the rule rather than despite it.The decisions worth making deliberately
Does focus follow the pane? These pull in opposite directions and both are defensible:
So focus-following is probably a property of who asked, not of the operation. That is the same shape as
helm-close's force rule: what a request may assert depends on whether it owns the thing. Say it once, in a policy type, with the argument in its header.What is the address? A pane uuid plus a destination. The bench snapshot already publishes both — pane
id, column index, slot index — so an agent can compute a move from a file it already reads. Whether the destination is(column, slot), or relative (left,right,up,down), or both, is a real choice: relative is what a keyboard shortcut wants, absolute is what an agent wants.What happens to an emptied column? And to a move that would create one? Whatever the answer, it should be the same one the close path already gives.
Scope: within a workspace. Moving a pane between workspaces is a different feature with a different set of questions, and it should not be smuggled in.
Acceptance
Workbenchcan move a pane, tested as a value operation — no UI, no display, no surface.helm-command, and the result says what the bench looks like after.focusedSlotuntouched, and there must be a control that fails if a move stops moving anything at all.Related
#269 (the command channel and the focus rule), #176 (ownership deciding what a request may assert), #39 (the workbench itself), #284 (an agent selecting a pane it created — the same ownership question one step over).