summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGabriel Schneider <[email protected]>2026-09-28 16:59:45 -0300
committerGabriel Schneider <[email protected]>2026-10-01 00:12:15 -0300
commit04e4323a27237bc886e92ce20c02c42c6f594d1f (patch)
treed4b3e0ae6e19d03e86d38c153ccc542f8d2a14c9
parent84b04c8ea7f04ba7569628e49ca900622c8d7858 (diff)
downloadpardes-04e4323a27237bc886e92ce20c02c42c6f594d1f.tar.gz
pardes-04e4323a27237bc886e92ce20c02c42c6f594d1f.zip
The docs say which shell a command runs in, what Kill's word matches, where dumps go and in what time, and how to send code to a REPL
Dogfood found the docs saying $SHELL -c where commands run the root ctl's Shell, the README's log line missing run, exit, send, dump and restore, Kill's argument unexplained, and nothing on Repl - and bare Repl, on bracketed paste for multi-line code over pty/data, or on the UTC dump time. The Restore write's ECONNRESET through a mount is documented rather than fixed: pardes sends the answer before the hang-up, and 9ns drops it when its next send fails first. The REPL decision is recorded with the others, and the fs guide says a builtin's word still runs first. Co-Authored-By: Claude Opus 5.5 <[email protected]>
-rw-r--r--.agents/skills/pardes-9p/SKILL.md21
-rw-r--r--docs/fs.md26
-rw-r--r--docs/open-questions.md19
-rw-r--r--src/fs-help.txt8
4 files changed, 55 insertions, 19 deletions
diff --git a/.agents/skills/pardes-9p/SKILL.md b/.agents/skills/pardes-9p/SKILL.md
index 7cc3aeb1..0643e209 100644
--- a/.agents/skills/pardes-9p/SKILL.md
+++ b/.agents/skills/pardes-9p/SKILL.md
@@ -57,6 +57,7 @@ $m/pane/<n>/pty/run write one line, read `exit N` + its output, or `busy` / `e
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>,
+ 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
@@ -65,7 +66,8 @@ $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 started (command panes, lines it typed into shells); 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`;
Kill signals only the foreground job, so of `sleep 30; echo done` the
@@ -124,8 +126,8 @@ 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 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 `$SHELL -c` the line in the pane's
-directory, which ends showing `exit N` (a typo: `exit 127`) and logs `run
+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
@@ -134,7 +136,10 @@ 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. Every refused 9P write adds an `err <serial|->
+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`.
@@ -247,8 +252,12 @@ 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. `Dump` writes `pardes-<date>-<time>.zon` under `DumpDir`
-(`~/.local/share/pardes` by default) and logs `dump <path>`.
+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.
diff --git a/docs/fs.md b/docs/fs.md
index 58c57867..86f44501 100644
--- a/docs/fs.md
+++ b/docs/fs.md
@@ -112,12 +112,15 @@ which quits the editor as acme's does (it refuses once, naming each pane with
unsaved text, `<name>: Modified (Exit again to discard)`, and a second
`Exit` with nothing edited since quits, throwing that text away; a scratch
under 100 bytes is not asked about; `Restore`, which replaces every pane,
-asks the same first -- `Dump` writes `pardes-<date>-<time>.zon` in
+asks the same first -- `Dump` writes `pardes-<date>-<time>.zon` (UTC) in
`DumpDir` (default `$XDG_DATA_HOME/pardes`, else `~/.local/share/pardes`)
and logs `dump <path>`, and `Restore` with no path takes the last one; a
Restore puts a new editor under every client, so the write of it is
answered and then every connection is hung up, their fids naming the old
-editor's panes: dial again, and the new log names the restored panes and
+editor's panes (through a 9ns mount the write usually fails with
+ECONNRESET all the same: 9ns fails a request whose reply is already in once
+the hang-up breaks its next send, so trust the log): dial again, and the new
+log names the restored panes and
`restore <path>`. The answer has 200 ms to leave before the cut, so a slow
client may see only the cut; the log's `restore <path>` is what says the
Restore happened. Keeping connections across it would mean carrying serials
@@ -132,7 +135,8 @@ start mark (C) to its end mark (D), where Kill sends its foreground job SIGTERM
"kill" note, which ends a process -- and never signals the shell itself;
in a shell running without job control (`set +m`) the job shares the
shell's group, so there is none to signal: Kill says `Kill: no job to
-signal`, and a write of it to `ctl` fails with that; and only the
+signal`, and a write of it to `ctl` fails with that; with nothing running
+it says `Kill: nothing running`; and only the
foreground job, so of `sleep 30; echo done` the `echo` still runs once the
`sleep` is stopped --
and reads every setting there is, one a line, in the words a write of it
@@ -238,7 +242,8 @@ same tree without leaving the process.
or anything else, a command line. Written at a terminal at its prompt it
is typed into that shell. From anywhere else -- a file, a scratch, a tag,
a terminal whose tty a program holds -- it runs as a command pane: a
- terminal whose child is `$SHELL -c` the line in the pane's directory,
+ terminal whose child is the root ctl's `Shell` (fish unless set) run
+ with `-c` and the line, in the pane's directory,
which shows its output and then `exit N` (its tag reads `<dir> (<line>)
running`, then `exit N`), and stays. The command is over when its process
exits, as in acme, not when its terminal closes: a job it left in the
@@ -256,11 +261,14 @@ same tree without leaving the process.
an interactive terminal in that pane's directory.
A terminal can be bound as a language's REPL: `Repl python` in its tag or
-on its `ctl` (the language names are the syntax table's; `Repl -` unbinds,
+on its `ctl` (the language names are the syntax table's, or a code fence's
+alias such as `py`, in any case; `Repl -` unbinds,
`Repl` bare says the binding, `Repl python` again changes nothing). Its tag
shows its id, `python-a`, `python-b` for the next, a freed letter reused,
and so does the end of its `ctl` line, after `current`/`notcurrent`.
-Then an exec made by a gesture on the body of a file in that language -- a
+A builtin's word still runs first, bound or not: `Del` clicked in the file
+closes its pane. Then any other exec made by a gesture on the body of a file
+in that language -- a
middle click, the execute key, on a selection or a single word, even `make`
in a comment -- or on the REPL's own body is typed into the REPL instead of
run: bracketed paste when its program asked for it (DECSET 2004), else line
@@ -278,8 +286,10 @@ the tag is how to run `make` from that file), `Exec <text>` run by name
(typed, a 2-1 chord onto `Exec`, a `ctl` line) and a command word @`cmd` in
the text, looked at or clicked (`# @`pytest -x`` in a script). A 9P `exec`
is no gesture and is never sent: a script writes to the REPL pane's
-`pty/data`. The REPL gets the text wherever it is -- at a `pdb` or `input()`
-prompt too. Bindings are not dumped, so a Restore leaves none.
+`pty/data`, multi-line code as a bracketed paste (`\e[200~<code>\e[201~`
+then `\r`), since line by line a blank line ends a Python block and Python
+3.14's REPL auto-indents each line typed into it. The REPL gets the text
+wherever it is -- at a `pdb` or `input()` prompt too. Bindings are not dumped, so a Restore leaves none.
The root's pair clicks at the active pane and `/pane/<n>/look` and
`/pane/<n>/exec` at that pane. Blank lines are skipped, and every other line
diff --git a/docs/open-questions.md b/docs/open-questions.md
index a2ce2086..d4b5699c 100644
--- a/docs/open-questions.md
+++ b/docs/open-questions.md
@@ -11,7 +11,8 @@ Raised 2026-09-27 in the review of pardes against acme (Plan 9 source at
**Decided 2026-09-28: a command pane.** Clicked or written at an interactive
terminal at its prompt, the line is typed into that shell, whose state the
clicker can see. From anywhere else it runs as its own terminal pane whose
-child is `$SHELL -c` the line in the pane's directory: full emulation
+child is the root ctl's `Shell` run with `-c` and the line, in the pane's
+directory: full emulation
(colours, `less`, `vim`, `sudo`'s prompt work), the exit status from waiting
on the child (`exit N`, `exit 127` for a misspelling, no prompt marks
needed), Kill signalling its process group, `run`/`exit` records in the log,
@@ -57,3 +58,19 @@ behaviour inside a chosen terminal: a line in, `exit N` and its output out.
The planned root `ctl` (session builtins) and pane `ctl` (pane builtins)
refuse unknown words, whatever is decided here; the question is only what
`exec` and the middle-click do with them.
+
+## Where does an exec from a code file go?
+
+**Decided 2026-09-28: to a REPL bound for its language, when one is.**
+`Repl python` binds a terminal; then an exec made by a gesture (a middle
+click, the execute key, a selection or a single word) on the body of a file
+in that language, or on the REPL's own body, is typed into the REPL
+instead of run. What stays a command whatever is bound: a builtin's word,
+a word in a tag, `Exec <text>` run by name, a command word @`cmd` in the
+text, and a 9P `exec` write (a script writes the REPL's `pty/data`). An
+event record written back is done as the click it was, REPL and all. With
+several bound the pane asks which, one key answering, and remembers
+nothing. A REPL takes text only while its program has the terminal, and a
+done command pane cannot be bound. Chosen over a per-file or per-directory
+binding, which would need a place to keep and show it; bindings are not
+dumped. `docs/fs.md` has the behaviour.
diff --git a/src/fs-help.txt b/src/fs-help.txt
index 8948ac78..57ef7b62 100644
--- a/src/fs-help.txt
+++ b/src/fs-help.txt
@@ -5,11 +5,11 @@ index one line per pane: serial, kind (text|term|pdf|image), dirty flag, n
status pid, version and pane count
look write a line: a right click on it at the active pane; read: the serials it touched
exec write a line: a middle click, an editor command word or a shell line; read the same
-log events: new/del/rename/save <serial> <name>, msg <serial|-> <text>, err <serial|-> <why>
+log events: new/del/rename/save <serial> <name>, run/exit/send <serial> ..., dump/restore <path>, msg, err
screen rendered screen as JSON, frozen from open to close
listeners the session's dial addresses
focus the serial of the pane with the keyboard; write a serial to give it the keyboard
-ctl settings, one a line; or Newcol, Dump, Exit (quits; asks once), Kill (stops the fg job)
+ctl settings, one a line; or Newcol, Dump, Exit (quits; asks once), Kill [word] (stops what pardes ran, or what starts with word)
commands every builtin: its word, arg if it takes one, and root or pane: which ctl takes it
pane/new open it to make a pane (named +New); the read answers that pane's serial
pane/<n>/ name body tag ctl addr dot limit data xdata sel dirty mark scroll errors (write-only:
@@ -39,7 +39,7 @@ Pitfalls, one each:
data: > replaces the addr range, : > deletes it, a 2nd > inserts (addr moved); body: > empties all.
tag reads the path, then its own text; writes append; truncating clears it, default words too.
A terminal's body is a history snapshot frozen per open; pty/data is the live stream.
- exec: a non-builtin line runs as a command pane ($SHELL -c; exit N shown, logged), a shell's typed in.
+ exec: a non-builtin line runs as a command pane (ctl's Shell -c; exit N shown, logged), a shell's typed in.
Through a mount a malformed write is EINVAL, a well-formed one that fails EIO: log's err says why.
lock/unlock need a held ctl fd (exec 3>ctl), a held lock fails: retry. A column's last pane -> +New.
- Repl python on a terminal's ctl: a .py body's clicks go to it; tag words, Exec x, @`x` stay commands.
+ Repl python on a terminal's ctl: a .py body's clicks go to it (Repl - unbinds, Repl says it); tags stay commands.