summaryrefslogtreecommitdiff
path: root/.agents
diff options
context:
space:
mode:
Diffstat (limited to '.agents')
-rw-r--r--.agents/skills/pardes-9p/SKILL.md86
1 files changed, 65 insertions, 21 deletions
diff --git a/.agents/skills/pardes-9p/SKILL.md b/.agents/skills/pardes-9p/SKILL.md
index 393b0b0f..0643e209 100644
--- a/.agents/skills/pardes-9p/SKILL.md
+++ b/.agents/skills/pardes-9p/SKILL.md
@@ -13,24 +13,29 @@ relative to that root unless linked.
## Find the session through the mount
-This machine keeps a FUSE mount of every posted session under `/mnt/9p`:
-`/mnt/9p/pardes/<pid>/` is one session's served root. Inside a pane,
+Check `$NINE_MOUNT` first. `9ns --mntgen` sets it for every process it starts
+(an interactive shell on this machine runs inside one), so a set `$NINE_MOUNT`
+means the posted-9P registry is mounted there, usually `/mnt/9p`, and each
+running editor is a directory `$NINE_MOUNT/pardes/<pid>/`. Inside a pane,
`$PARDES_9P` is that session's socket (`/run/user/1000/pardes-9p-<pid>.sock`),
-so its pid is the directory to use, and `$PARDES_PANE` is the calling pane's
-serial:
+which names the directory, and `$PARDES_PANE` is the calling pane's serial:
```sh
-m=/mnt/9p/pardes/$(basename "$PARDES_9P" .sock | sed 's/^pardes-9p-//')
+[ -n "$NINE_MOUNT" ] || echo 'no 9P mount: use the Python client below'
+s=${PARDES_9P##*/pardes-9p-}; m=$NINE_MOUNT/pardes/${s%.sock}
cat "$m/index"
cat "$m/pane/$PARDES_PANE/body"
```
+From there the editor is files: `cat`, `echo >`, `ls` and shell scripts are
+the whole interface, and nothing below needs more than they do.
+
Entries for dead sessions stay listed and answer `Input/output error` on any
access, so name the session you mean rather than globbing or taking the newest.
`cat "$m/index"` is the cheapest liveness check, and `cat "$m/status"` reports
the `pid`, `version` and `panes` of a session new enough to serve it.
-`/mnt/9p/pardes` is the registry of posted sessions, mounted once for the
+`$NINE_MOUNT/pardes` is the registry of posted sessions, mounted once for the
machine. It is not the per-pane kernel mount the `Tty9p` builtin makes, which
gives one pane's shell `$PARDES_MOUNT`; see [docs/v9fs.md](../../../docs/v9fs.md)
for that. Either mountpoint serves the same tree. A `9ns --unix SOCKET -- cmd`
@@ -51,7 +56,9 @@ $m/exec write a line = a middle click: an editor command word, or a shell
$m/pane/<n>/pty/run write one line, read `exit N` + its output, or `busy` / `error ...`, on the same open:
exec 3<>$m/pane/$n/pty/run; echo make >&3; cat <&3
(a fresh terminal: waits for its first prompt; if none comes, interrupt the read)
-$m/log recent events, then EOF: new|del|rename|save <serial> <name>, msg <serial|-> <text>
+$m/log recent events, then EOF: new|del|rename|save <serial> <name>, msg <serial|-> <text>,
+ run <serial> <line>, exit <serial> <N|?>, send <from> <to> <repl-id>,
+ dump|restore <path>, err <serial|-> <file>: <why>
(exec 3<>$m/log; echo follow >&3; cat <&3 waits for new ones; tail -f does not)
$m/screen the rendered screen as JSON, frozen per open
$m/listeners this session's dial addresses
@@ -59,11 +66,14 @@ $m/focus the serial of the pane with the keyboard (empty while a column/wor
echo a serial into it to move the keyboard (a folded pane stays folded)
$m/ctl the settings, one a line as a write takes them; write a setting or a session builtin
(Newcol, Dump, Theme x; Exit QUITS the editor, Kill [word...] stops the
- commands pardes typed into terminals; Exit and Restore refuse once per
+ commands pardes started (command panes, lines it typed into shells), a word
+ matching a command line's first word; Exit and Restore refuse once per
unsaved pane, `<name>: Modified (Exit again to discard)`, and the same
- word again DISCARDS that text -- not a retry, unlike lock's `file in use`); a pane's builtins (Del, Save f,
- and the column words Delcol, Collapse, which act on that pane's column) go to
- $m/pane/<n>/ctl
+ word again DISCARDS that text -- not a retry, unlike lock's `file in use`;
+ Kill signals only the foreground job, so of `sleep 30; echo done` the
+ echo still runs; Joincol needs a column to the right of the keyboard's);
+ a pane's builtins (Del, Save f, Collapse, which folds that pane, and the
+ column word Delcol, which closes that pane's column) go to $m/pane/<n>/ctl
$m/commands every builtin: `Word`, `Word arg`, then `root` or `pane` (which ctl takes it)
$m/pane/new open it to make a pane (a scratch named <dir>/+New), read names it;
rmdir $m/pane/<n> closes it; closing a column's last pane leaves a +New there
@@ -114,9 +124,22 @@ active pane from the root and at that pane from `$m/pane/<n>/look` and
made, or the pane it focused or acted on. A command that fails is reported in
the editor, not as a write error, so inspect the resulting pane, index, message
or screen; only a malformed line fails the write itself. A word no builtin
-knows (a typo included) is typed into a terminal -- the pane itself if it is a
-terminal at its prompt, else one in the pane's directory, made if need be --
-and is not reported as an error. Every refused 9P write adds an `err <serial|->
+knows (a typo included) is a command line: written at a terminal at its
+prompt it is typed into that shell; from anywhere else it runs as a command
+pane, a terminal whose child is the root ctl's `Shell` (fish unless set)
+running `-c` the line in the pane's directory, which ends showing `exit N` (a typo: `exit 127`) and logs `run
+<serial> <line>` and `exit <serial> <N|?>` -- `exec` reads back its serial,
+so follow `log` for the exit. The directory's next command reuses a finished
+command pane, below what it showed. A terminal bound as a REPL (`Repl
+python` on its ctl) takes the middle clicks made on a `.py` body instead,
+but never a 9P write: a script sends code by writing the REPL pane's
+`pty/data`, and runs a command from such a file with `Exec <text>` or the
+tag. A bound terminal's `ctl` line ends with its id (`python-a`); an event
+record written back from such a file's body goes to its REPL, as the click
+would. `Repl -` unbinds; a bare `Repl` says the binding. Multi-line code
+written to `pty/data` should be a bracketed paste, `\e[200~<code>\e[201~`
+then `\r`: sent line by line, a blank line ends a Python block, and Python
+3.14's REPL auto-indents each line it is typed. Every refused 9P write adds an `err <serial|->
<file>: <why>` record to `$m/log`; through a mount the write itself only says
`Invalid argument`.
@@ -147,9 +170,13 @@ is why copying one onto another is all that acme's `addr=dot`, `dot=addr` and
`/pattern/`, `2+1`), whose regexps are mvzr's searched as sam searches:
`^`/`$` match at any line's start and end, `.` and `[^...]` never match a
newline, the leftmost match wins (the first alternative there, not the
-longest), `/re/` wraps unless `limit` is set, and a search that backtracks
+longest). An expression is evaluated from the current address (the last one
+written, or just past the last `data` write): `.` is that address, not the
+selection, `/re/` searches on from its end and wraps unless `limit` is set,
+`?re?` or `-/re/` searches back, `#100,#50` fails `addresses out of order`,
+and a search that backtracks
past a step budget (about 300 ms) fails with `regular expression search
-took too long`. A failed address says
+gave up, ...`. A failed address says
why (`no match for regexp`, `address out of range`) and leaves no address:
`data` refuses until the next good one, so a missed target is never
written at the old one. Moving `dot` scrolls the pane to it. `limit` bounds a
@@ -209,11 +236,28 @@ For live terminal output or plugin events, use `open` / `read_fid` / `close`,
not the read-until-EOF helper. `pty/data` captures output while held open; it
is not a history replay. Both files are shared, consuming queues, not
per-client broadcasts, so a slow reader loses older data. Holding `event` open
-intercepts that pane's Look and Exec clicks, so it is not a passive logger: for
-Look/Exec records whose offsets identify the intended text, forward the short
-record `<origin><action><q0> <q1>\n`, not the whole report with flags and text.
-Expansion and chord reports need explicit handling, and terminal-body events
-can carry text only in the report, which a short writeback cannot reproduce.
+intercepts that pane's Look and Exec clicks -- and lines written to that pane's
+own `look`/`exec`, or to the root's while it has the keyboard, as `F` records
+at `0 0` with the text, and clicks in a terminal's body, also at `0 0` -- so
+it is not a passive logger: a helper holding `event` that writes its own
+pane's exec gets its command back as a record; run it through `ctl` or write
+the record back. To have a record done, write it back: the short form
+`<origin><action><q0> <q1>\n` acts on that range's text, and the whole record
+as read acts on its text when the range is empty (the only way for a record
+at `0 0`). Chord reports need explicit handling. A record is
+`<origin><action><q0> <q1> <flag> <n> <text>\n` and its text may hold
+newlines: read `n` bytes of text, never up to the next newline (acme counts
+runes; pardes counts bytes, as all its offsets are).
+A Restore puts a new editor under every client: the Restore write is
+answered, then every connection is hung up (their fids name the old
+editor's panes); dial again, and the new log names the restored panes then
+`restore <path>` -- the authority, since a slow client may see the cut
+before the answer. Through a 9ns mount the Restore write itself usually
+fails with ECONNRESET although the Restore went ahead: 9ns fails a request
+whose reply is already in when the hang-up breaks its next send. Trust the
+log. `Dump` writes `pardes-<date>-<time>.zon`, the time in UTC, under
+`DumpDir` (`$XDG_DATA_HOME/pardes`, else `~/.local/share/pardes`) and logs
+`dump <path>`.
Read the event implementation before building an interceptor. Close handles in
`finally`, and disconnect after a socket timeout. The service shares four
connection slots and 32 screen/terminal-history snapshot handles.