summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-21 16:56:35 -0300
committerGabriel Schneider <[email protected]>2026-09-21 16:56:35 -0300
commit534c084fb7ab8e3776b25017c901899964490a5d (patch)
tree8ea20896d1da46c63f6cba2f7de5603e17c06012
parentdddd556accea6b6ea7802cd3f622f8b3cf8eb43f (diff)
downloadcloud9-534c084fb7ab8e3776b25017c901899964490a5d.tar.gz
cloud9-534c084fb7ab8e3776b25017c901899964490a5d.zip
9harness: drop the zmxify script; the mount is the replacement
The script listed /active, ran fzf over it and wrote the chosen name into an agent's zmx. Everything in it but the picker, a free-name loop and the attach was `ls` and `cat` against the tree — 130 lines re-deriving what four lines of shell already read: ls /mnt/9p/harness/active/*/* cat /mnt/9p/harness/active/claude/345104/session echo mine > /mnt/9p/harness/active/claude/345104/zmx zmx attach mine zmxify was 307 lines of rc because there was no filesystem to ask. The answer to that is the filesystem, not a smaller script on top of it, which would only become a second and worse interface beside the real one. DESIGN.md keeps what a caller now arranges itself (a free name, the attach) and why the old script's own-ancestry rule is gone rather than moved.
-rw-r--r--9harness/docs/DESIGN.md48
-rw-r--r--9harness/src/active.zig4
-rwxr-xr-x9harness/zmxify176
3 files changed, 30 insertions, 198 deletions
diff --git a/9harness/docs/DESIGN.md b/9harness/docs/DESIGN.md
index 4868bc8..340f3da 100644
--- a/9harness/docs/DESIGN.md
+++ b/9harness/docs/DESIGN.md
@@ -390,29 +390,37 @@ Named, because they are choices rather than oversights:
### Replacing zmxify
-`9harness/zmxify` is the whole script now: it lists `/active`, offers
-the rows to fzf, and writes the chosen name into the agent's `zmx`.
-It parses no `/proc`, opens no fd table and queries no database — the
-307 lines that did become a `cat` of a few files, and the knowledge
-they held now lives in a daemon with tests around it.
+There is no replacement script, because the mount is the replacement:
-What the script still decides is which rows to offer and what to call
-the new session. It skips an agent already under zmx — that is what
-this moves things *into* — and one whose session did not resolve, which
-the daemon would refuse anyway. A free name is the caller's business
-too, and the registry already answers which are taken.
+```
+ls /mnt/9p/harness/active/*/* what is running
+cat /mnt/9p/harness/active/claude/345104/session what it is
+echo mine > /mnt/9p/harness/active/claude/345104/zmx
+zmx attach mine
+```
+
+`~/.local/bin/zmxify` was 307 lines of rc because there was no
+filesystem to ask: it scanned `/proc`, classified command lines, read
+fd tables and queried two sqlite databases to work out what the four
+lines above now read. All of that moved into the daemon, where it is
+tested. Writing a wrapper back on top would only re-derive what the
+tree already says, and would become a second, worse interface beside
+the real one.
+
+Two behaviours the old script had are worth knowing, because they are
+now the caller's to arrange and both are one line: pick a session name
+nothing holds (the registry, `$XDG_RUNTIME_DIR/9p/zmx`, says which are
+taken) and `zmx attach` afterwards.
-What it does **not** skip is the caller's own session, and that is the
-whole point of the daemon owning the action. The old script excluded
-its own ancestry because it did the killing itself: kill your own
+A third is gone rather than moved. The old script refused to act on
+its own ancestry, because it did the killing itself: kill your own
parent and the script dies before it can re-exec, losing the session it
-was rescuing. Now the script's only job is to get the `Twrite` out.
-The daemon kills, re-execs and waits for the new session to post, and
-it completes all of that whether or not the client is still there —
-verified by hanging up immediately after sending the write and watching
-the move land anyway. So zmxifying the terminal you are sitting in
-works; the shell drops, and `zmx attach <name>` is printed before the
-write, because there may be no script left to print it after.
+was rescuing. The daemon kills, re-execs and waits for the new session
+to post, and completes all of it whether or not the client is still
+connected — verified by hanging up immediately after sending the write
+and watching the move land anyway. So moving the terminal you are
+sitting in works, which is the common case; the shell drops, and you
+reattach with the name you wrote.
### Testability
diff --git a/9harness/src/active.zig b/9harness/src/active.zig
index 0a1a60d..fb55cf6 100644
--- a/9harness/src/active.zig
+++ b/9harness/src/active.zig
@@ -51,8 +51,8 @@ pub const Kind = enum(u8) {
/// How a session was resolved — reported, so a wrong guess is visible
/// rather than silent. `none` means the process is listed with what
-/// `/proc` knows and nothing more (codex and hermes keep their sessions
-/// in sqlite, which this round does not read).
+/// `/proc` knows and nothing more, and cannot be moved: hermes is the
+/// only harness that always lands here.
pub const Via = enum(u8) {
none,
registry,
diff --git a/9harness/zmxify b/9harness/zmxify
deleted file mode 100755
index 5512ffa..0000000
--- a/9harness/zmxify
+++ /dev/null
@@ -1,176 +0,0 @@
-#!/usr/lib/plan9/bin/rc
-# zmxify - move a live harness session into a zmx session
-#
-# Lists the agents 9harness serves under /active, offers them to fzf, and
-# writes the chosen zmx session name into that agent's `zmx` file. The
-# daemon does the rest: it kills the harness and re-execs it under zmx
-# with its session resumed.
-#
-# usage: zmxify [-n] [dir]
-# dir only agents running there; all of them if omitted
-# -n print the plan, write nothing
-#
-# This is the whole script now. Everything it used to work out for
-# itself - which processes are harnesses, which stored session each one
-# is writing, whether it already lives in zmx, and how to resume it -
-# is a file under /active, resolved by the daemon and covered by its
-# tests. Nothing here parses /proc, opens an fd table or queries a
-# database, and nothing here kills anything: a name written into `zmx`
-# is refused unless the session behind it was resolved first, so a move
-# always has somewhere to come back to.
-
-path=(/usr/bin /bin $path)
-
-nl='
-'
-tab=' '
-dry=()
-here=()
-
-if(~ $1 -n){
- dry=y
- shift
-}
-if(! ~ $#* 0){
- here=`$nl {readlink -f $1}
- if(~ $#here 0 || ! test -d $here){
- echo 'zmxify: '^$1^': not a directory' >[1=2]
- exit dir
- }
- shift
-}
-if(! ~ $#* 0){
- echo 'usage: zmxify [-n] [dir]' >[1=2]
- exit usage
-}
-
-mnt=$NINE_MOUNT
-if(~ $#mnt 0)
- mnt=/mnt/9p
-act=$mnt/harness/active
-if(! test -d $act){
- echo 'zmxify: no harness fs at '^$act >[1=2]
- echo ' start it with: zmx run harness -d 9harness --allow-move' >[1=2]
- echo ' and run this inside a 9ns mount (an interactive fish already is)' >[1=2]
- exit nofs
-}
-
-# A field that is absent (the harness does not publish it) and one that
-# is present but empty (`zmx` on an agent outside zmx) both answer `-`:
-# a null list would blow up the concatenations below.
-fn field { # field dir name: its contents, or -
- fv=()
- if(test -e $1/$2)
- fv=`$nl {cat $1/$2 >[2]/dev/null}
- if(~ $#fv 0)
- fv=-
- echo $fv
-}
-
-# An agent already under zmx has nowhere to go: that is what this moves
-# things into. Its own session is *not* excluded - moving the terminal
-# you typed this into is the common case, and it is safe, because the
-# daemon does the killing and the re-exec. This script only has to get
-# the write out; it may die the instant after, and the move still lands.
-# Ancestry is worked out only to know whether we will survive to attach.
-fn ancestry { # ancestry pid: it and every parent of it
- aup=$1
- while(! ~ $aup 0 1){
- echo $aup
- aup=`{sed -n 's/^PPid:[ ]*//p' /proc/$aup/status >[2]/dev/null}
- if(~ $#aup 0)
- aup=0
- }
-}
-mine=`$nl {ancestry $pid}
-
-lines=()
-for(h in `{ls $act >[2]/dev/null}){
- for(d in `{ls $act/$h >[2]/dev/null}){
- a=$act/$h/$d
- acwd=`$nl {field $a cwd}
- asess=`$nl {field $a session}
- azmx=`{field $a zmx}
- take=()
- if(~ $#here 0 || ~ $acwd $here)
- take=y
- # Already under zmx: there is nothing to move it into.
- if(! ~ $azmx -)
- take=()
- # Its session did not resolve, so the daemon would refuse
- # the write; offering it would only produce an error.
- if(~ $asess -)
- take=()
- if(! ~ $#take 0){
- short=$acwd
- if(! ~ $#home 0)
- short=`$nl {echo -n $acwd | sed 's,^'^$home^',~,'}
- avia=`{field $a via}
- atitle=`$nl {field $a title}
- lines=($lines $d^$tab^$h^$tab^$short^$tab^'via='^$avia^$tab^$asess^$tab^$"atitle)
- }
- }
-}
-
-scope=(all directories)
-if(! ~ $#here 0)
- scope=$here
-if(~ $#lines 0){
- echo 'zmxify: no movable harness session in '^$"scope >[1=2]
- exit 0
-}
-
-fzfopts=(--no-multi --reverse --height=40% --delimiter=$tab --prompt='zmxify ' --header='move under zmx ['^$"scope^']'^$nl^'pid harness dir via session title')
-sel=`$nl {{for(l in $lines) echo $l} | fzf $fzfopts}
-if(~ $#sel 0){
- echo 'zmxify: nothing picked' >[1=2]
- exit 0
-}
-
-pick=`{echo $sel | awk '{print $1}'}
-harness=`{echo $sel | awk -F$tab '{print $2}'}
-a=$act/$harness/$pick
-if(! test -d $a){
- echo 'zmxify: '^$harness^' pid '^$pick^' is gone' >[1=2]
- exit gone
-}
-pickcwd=`$nl {field $a cwd}
-
-# A zmx session name nobody is using yet. zmx posts every session into
-# the registry, so the registry is what says which names are taken.
-zbase=`{basename $pickcwd | tr -c 'A-Za-z0-9'^$nl -}
-if(~ $#zbase 0)
- zbase=session
-zname=$harness^-^$zbase
-reg=$XDG_RUNTIME_DIR^/9p/zmx
-if(~ $#XDG_RUNTIME_DIR 0)
- reg=/run/user/^`{id -u}^/9p/zmx
-n=()
-while(test -e $reg/$zname){
- n=($n x)
- zname=$harness^-^$zbase^-^$#n
-}
-
-if(! ~ $#dry 0){
- echo 'move ' $harness 'pid' $pick 'in' $pickcwd
- echo 'session' `{field $a via} `{field $a session}
- echo 'write ' $zname '>' $a/zmx
- echo 'then ' zmx attach $zname
- exit 0
-}
-
-echo 'zmxify: moving' $harness 'pid' $pick 'into zmx session' $zname
-# Moving something we hang off means this shell goes with it. Say the
-# attach line first, because there may be no `we` left to say it after.
-if(~ $pick $mine)
- echo 'zmxify: that is this terminal; it will drop. reattach with: zmx attach '^$zname
-# The write returns when the new session is up, or fails having changed
-# nothing it could avoid changing. The daemon owns the kill and the
-# re-exec, so the move lands even if this process dies mid-write.
-if(! echo $zname > $a/zmx){
- echo 'zmxify: the move was refused' >[1=2]
- exit move
-}
-if(~ $pick $mine)
- exit 0
-exec zmx attach $zname