On Disk and Not in the List
The sessions my phone starts through the always-on box do not appear when I ask the box for its sessions. Not the recent ones, not the old ones, none. The transcripts are on disk in the normal place, a direct resume by id opens any of them, and the picker, the list you get when you type the resume command with no argument, skips every one.
By design
The coding agent’s CLI, version 2.1.273 as I write this, drops from that picker every transcript whose entrypoint is one of a fixed set of programmatic ones. The set is hard-coded. There is no switch. The reasoning is sound for what those entrypoints were for: a session started by a script is not something a person sat in, so it has no business in a list of conversations to resume.
A session started from the phone runs through a host process on the box, and the host starts it as one of those programmatic entrypoints. So by the CLI’s reading, every conversation I have from the phone is a script’s, and the list of my conversations on the box is the list minus every conversation I have had away from the box.
The reason this matters is specific. A session read on the phone usually ends with a runbook: three or four commands to run on the box, because the phone cannot run them. The phone cannot paste them to the box either. So the thing I most often want from the box’s picker is exactly the session the picker will not show me.
The picker the tool withholds
So there is now a small tool for it. It lists those transcripts newest first, phone-started and phone-claimed alike, and the fleet’s own sessions behind a flag. It prints a session’s last turn, or only the fenced code blocks from that turn, ready to paste. It pages the conversation. It forks a session into the terminal interface, or resumes it in place if the phone has let go of it. Finding them meant mapping a phone-side session id to a local transcript through the host’s own bridge stream, which carries the local id in a record of its own.
A detail that cost an hour: when a session’s working directory moves into a different repository, the CLI re-keys its transcript under a new id in that project’s folder and copies the history across, timestamps and all. Two files, one conversation. The tool folds copies into one row and accepts any copy’s id as the name of the conversation, because otherwise the list showed two of everything I had done in two repositories.
Number four was a comment
Then I used it, and the first real use was wrong.
The listing numbers its rows, and the documentation I had just written recommended opening one as open #4. The shell reads an unquoted # as the start of a comment. So open #4 ran as open, with no selector, and the tool’s no-selector default is the newest session that is waiting on me, which is usually not the one I chose. It opened the wrong session, silently, and it had done exactly what I typed.
The second failure came right behind it. To take single keystrokes the tool puts the terminal into raw mode, which leaves the shared standard input non-blocking, and a child that inherits that descriptor reads the resulting error as end of input and exits at once. So the hand-off to the terminal interface opened and closed in the same instant.
Bare numbers now, and the usage text says why. The child gets a freshly opened terminal device as its input. And in a terminal the tool is an interactive picker rather than a command that takes arguments: arrows move, enter resumes, one key prints the commands, one pins, one filters. Its first scan of the transcripts takes five seconds; after that a cache keyed on each file’s size and modification time opens it in a sixth of a second.
The list I trusted
The thing I keep coming back to is not the bug in my own tool, which was mine and was dumb and was fixed in an afternoon. It is that I had been treating the picker as the list of my sessions on that machine for weeks, and it was a filtered view with a fixed filter, and the filter’s rule was written for a world where programmatic sessions and human ones were different things. The day the phone started making human sessions through a programmatic door, the rule stopped being true and the list stopped being what I thought it was, and nothing on the screen changed.
The picker opens now in a sixth of a second. The first row on it is the session that wrote the commands I am about to run.