# Filesystem Every native session serves 9P2000 on a Unix socket. Pane shells receive `PARDES_9P` (socket path) and `PARDES_PANE` (pane serial). The socket is `$XDG_RUNTIME_DIR/pardes-9p-.sock`, or lives under `~/.local/state/pardes` when XDG_RUNTIME_DIR is unset. Detached sessions use their session name; `--9p=` overrides it. A `pardes ` launched from a pane forwards Look to that pane over 9P. `--nested` opens a separate editor and disables forwarding from its pane shells; its 9P service stays available. Look resolves the OS filesystem first, then the editor's virtual filesystem. Explicit paths bypass that search: | Editor path | Meaning | 9P server path | |---|---|---| | `/n/os/proc/self` | OS filesystem | `/os/proc/self` | | `/n/self/pane/2/body` | pane 2's text | `/pane/2/body` | | `/virtual/pane/2/body` | the same, in the editor's own spelling | `/pane/2/body` | | `/virtual/src/pardes.zig` | source embedded in this build | `/src/pardes.zig` | | `/n/peer/pane/2/body` | another session's text | peer's `/pane/2/body` | The mount name `self` is reserved and maps to the server root, so `/n/self/X` and `/virtual/X` both name the served `/X`. `--mount=peer=work` mounts the named session `work`; the dial can also be an absolute socket path, `unix!/path`, `tcp!IP!port`, or `quic!IP!port`. At runtime, use `Mount peer dial` and `Unmount peer`. There are eight named mounts; `os` and `self` are reserved. Unmount refuses mounts still used by a pane, its working directory, or a pending Save. Mounts are saved in dumps. Save uses the file's original mount. `pardes --9p-tcp='tcp!127.0.0.1!5640'` adds a TCP listener alongside the Unix socket. Build with `-Dquic=true` and system OpenSSL 3.6+ to enable QUIC; `--9p-quic='quic!127.0.0.1!5641'` adds its listener. Both accept numeric IPv4/IPv6 addresses, not DNS names. Listener port zero chooses a free port; `/listeners` reports all active dial addresses. All connections have session access, including `os`. TCP is unencrypted. QUIC uses an ephemeral TLS identity without peer verification or login. It carries 9P2000 on one bidirectional stream with ALPN `pardes-9p`. Unix and TCP connections share four slots served by cloud9's `std.Io` runner; QUIC has four of its own on the editor's poll loop. OpenSSL's internal buffers are separate, dynamically allocated memory. [Plan9port's client](https://9fans.github.io/plan9port/man/man1/9p.html) can drive Unix or TCP without a kernel mount, and `9ns` mounts the tree in a private namespace: ```sh 9p -n -a "unix!$PARDES_9P" read index 9p -n -a 'tcp!127.0.0.1!5640' ls pane/1 9ns --unix "$PARDES_9P" -- sh -c 'cat "$NINE_MOUNT/index"' ``` For [Linux v9fs](https://www.kernel.org/doc/html/latest/filesystems/9p.html), use `version=9p2000,cache=none,access=any` and `trans=unix`, or `trans=tcp` with `port=5640`. Set `uname`, `dfltuid`, and `dfltgid` for the local user. Leave `aname` empty. The opt-in [Linux v9fs experiment](v9fs.md) tests a kernel mount in a separate subprocess namespace (`zig build v9fs-test`, requiring explicit mount authorization). Neither 9P2000.u nor 9P2000.L is implemented. Existing Plan9port/v9fs clients need a userspace bridge for QUIC. ## The served tree ``` /README this guide, also src/fs-help.txt /index one line per pane: serial, kind (text|term|pdf|image), dirty flag, name /ctl write: one command per line; read: the serials the last command made or touched /new reading it creates one empty pane and answers "\n" (the /net/tcp/clone idiom) /log one line per editor event: new|del|rename|save ; reads park /screen rendered screen JSON; frozen per open handle /listeners the session's dial addresses /pane// name body tag ctl addr data xdata sel errors event, plus pty/{ctl,status,data} /os/ the host filesystem /src/ the editor's embedded sources, only when built with -Dembed-sources=true ``` Nothing in the tree is created by list, stat, walk or read, except that reading `/new` makes a pane; that is its whole purpose, so a recursive read of the tree makes one pane per open of it. `/ctl` and `/pane//ctl` take the editor's own command language, two verbs: - `look TEXT` is a right click on `TEXT`: a path opens a file, `file:12` jumps to a line, a directory opens a shell there, a URL opens in the browser. From `/ctl` the look happens at the active pane; from a pane's `ctl` at that pane. - `exec TEXT` is a middle click: a command word from `src/builtins.zig` (`Save`, `Del`, `New`, `Newcol`, `Mount NAME DIAL`, `Unmount NAME`, `Dump`, `Restore`, `Msg TEXT`, `Find`, `Grep`, `Tty`, ...), or anything else, which runs in the pane's terminal. Both verbs are lowercase; the words after `exec` are the editor's capitalized commands. A pane's `ctl` also keeps acme's addr verbs (`addr=dot`, `dot=addr`, `limit=addr`, `clean`, `dirty`, `cleartag`, `get`, `mark`, `nomark`, `noscroll`, `scroll`, `show`). Every line of a write is checked before any line runs; a malformed line fails the write with EINVAL. A command that fails inside the editor is reported on the message row, not as a write error. After a write to either `ctl`, reading `/ctl` answers the serials of the panes the command created, or, when it created none, the pane a look focused or the pane an exec acted on (even one it closed), one per line. Before any command it answers `pid`, `version` and `panes` lines. `/pane//name` reads the pane's file name (a terminal's directory) and writing it renames the buffer; a relative name resolves against the pane's directory. `sel` reads the editor selection and writing it replaces the selection. `body` appends on write and replaces on truncating open. `addr` selects a range and `data` or `xdata` read or replace it. `errors` appends to the directory's `+Errors` pane. Holding `event` open redirects the pane's Look and Exec clicks to that client; writing a record back performs the action. Stats report real lengths for `index`, `ctl`, `name`, `body`, `tag` and `sel`, modes 0644/0666 (0444 for read-only files, 0222 for write-only), the pane's last edit time or the process start as mtime, and stable qids. Directory entries carry no sizes; stat the entry. `/log` records `new`, `del`, `rename` and `save` while at least one client holds it open; a read parks until a record arrives. `/screen` returns JSON with `cols`, `rows`, `cursor`, a `styles` table, and row-major `cells` of `[grapheme, style_index]`. Each open freezes one frame until close. A terminal `body` freezes its history on the first read of each open handle; `pty/data` streams live output. Screen and terminal-body snapshots share 32 handle slots, released on close or disconnect. `-Dembed-sources=true` embeds the editor's sources and serves them under `/src` (and `/shaders` on GUI builds). `EffectCode ` lists the current backend's implementation files under `/virtual`, which Look opens; without the option the command reports the sources as unavailable. The esp32p4 build enables the option by default, so the device can serve its own source. This is a control filesystem, not a complete POSIX export. Native filenames may contain up to 255 bytes. Existing regular OS files support read, write, and truncation to zero; protocol create, remove, rename, and other metadata changes are refused. Ownership and permissions under `/os` are synthetic. Zero-length truncation accepts the accompanying `mtime` hint sent by Linux v9fs; the hint is not stored. Standalone timestamp changes remain refused. The tree lives in `src/ninep/`: `tree.zig` (nodes, lookup, readdir, dispatch, and the editor's reply payload over cloud9's backend contract), `pane.zig` (pane files), `ctl.zig`, `addr.zig`, `pty.zig`, `events.zig` (event and log streams), `screen.zig` and `sources.zig`. The protocol engine is cloud9's `fs.Server`, configured in `src/9p.zig` (the editor's and the board's capacities); the transports are `src/9p_io.zig` (cloud9's `serve.Runner` for Unix and TCP, a poll loop for QUIC, and the 9P client for mounts); `src/fs.zig` keeps host access, mounts, resolution, find and grep. `zig build fs-test` drives real sessions using the independent Python client in `test/ninep.py`; `zig build fs-discovery-test` checks that browsing creates nothing and that `new`, `ctl`, `name`, `sel` and `log` behave. `zig build 9p-test` checks the two engine configurations' budgets (the engine's own tests are cloud9's `zig build test`); `zig build fs-bench` measures filesystem transactions in the core. `zig build fs-test quic-test -Dquic=true` also exercises QUIC mounts and I/O.