# Linux terminals with a kernel 9P mount Execute `Tty9p`, or press `SPC n 9` in editor mode, to open a terminal below this pane with the current Pardes session mounted through Linux v9fs. The new pane asks for your sudo password when needed. After mounting, it starts your configured shell as your normal user, with your account's supplementary groups. The shell receives `PARDES_MOUNT`, the absolute mountpoint: ```sh ls "$PARDES_MOUNT/pane" cat "$PARDES_MOUNT/index" cat "$PARDES_MOUNT/README" cat "$PARDES_MOUNT/pane/$PARDES_PANE/body" echo 'Msg hello' > "$PARDES_MOUNT/exec" n=$(cat "$PARDES_MOUNT/pane/new") ``` **Opening** `pane/new` makes a pane, and reading that open file answers its serial; address the pane as `pane/` from then on. Each open makes another one, so read it once and keep the number. A *stat* makes nothing, which is why `new` can be listed at all: `ls`, `ls -l` and `find` over the whole mount create nothing, because none of them open it. The mount belongs to that pane's subprocess tree. Other panes and the editor core keep their original mount namespace. It works in native Linux TTY and SDL sessions, including detached sessions. A frontend attaching from elsewhere does not perform the mount; the session host starts the new terminal. ## Build and setup The normal Linux build installs the ordinary `pardes-v9fs` executable beside `pardes` and `pardes-gui`: ```sh zig build ``` Start an updated editor to get the builtin. An already running core retains its old code. The host resolves the helper beside its own executable; `PARDES_V9FS_HELPER=/absolute/path/to/pardes-v9fs` overrides this for development builds whose editor and helper live in different build-cache directories. Linux must support `9p` and its Unix transport (`9pnet_fd`). v9fs mounting needs `CAP_SYS_ADMIN` in the initial user namespace, which sudo supplies. The launcher uses `sudo -E` to retain the shell environment; local sudo policy must allow that. It restores the caller's PATH after dropping privileges because sudo's `secure_path` can replace it even with `-E`. No setuid installation, passwordless sudo policy, system group, or FUSE is installed. The helper currently accepts explicit mount paths and a command; it is not a restricted privilege broker. Do not grant it blanket passwordless access. A group-authorized helper would require a separate restricted design. ## Runtime organization `src/linux/v9fs.zig` builds `pardes-v9fs` and provides helper discovery to the native host. `Tty9p` marks the new pane for a mounted shell; `host_io.forkShell` starts the normal interactive shell and queues a quoted helper command. For bash and fish, the command waits for the shell's prompt-ready mark. The helper runs as a foreground shell job, so sudo uses the terminal like a manually run command. Authentication failure or cancellation returns to the original shell; exiting the mounted shell also returns there. The unprivileged launcher creates a private temporary mountpoint and invokes sudo inside the new PTY. The elevated helper creates a private mount namespace, makes propagation recursively private, and mounts the session's Unix socket with `version=9p2000,cache=none,access=any,nosuid,nodev,noexec`. It restores the calling user's account groups, drops all real/effective/saved root IDs and mount capabilities, and executes the shell. Ordinary commands such as sudo remain available for subsequent explicit authentication. The launcher waits for sudo, forwards termination signals, and removes its empty temporary directory on exit. Namespace destruction releases the mount when its last process exits. The core stays outside the mount namespace, which is the helper's private one: a path under `$PARDES_MOUNT` names nothing in the editor's own namespace, so a Look on one from that shell opens nothing. Each `Tty9p` currently creates its own mount and consumes a server connection; the session has four application connection slots across all transports. This is the explicit per-pane version. A shared launcher for all pane shells remains future work. Detached sessions retain the running mounted pane when frontends leave; Dump/Restore does not reconstruct mounted-shell namespaces. Descendants that deliberately outlive the terminal may retain their namespace until exit. ## Tests ```sh zig build v9fs-terminal-test -Dplatform=tty zig build v9fs-driver-test -Dplatform=tty zig build 9p-test -Dplatform=tty sudo -v zig build v9fs-test -Dplatform=tty ``` `v9fs-terminal-test` exercises the builtin, real launcher, PTY input, session environment, quoted helper paths, hidden password input, and core responsiveness using an unprivileged sudo stand-in. It checks that authentication failure and interruption clean up the temporary mountpoint and leave the original shell usable. It does not claim kernel-mount coverage. `v9fs-test` mounts through the same runtime helper. Its driver keeps the editor unprivileged and uses `sudo -n`, retaining the calling terminal's authorization. Missing authorization or kernel support fails the test instead of skipping it. It checks mount isolation, privilege dropping, inherited access, directory refresh, body reads and truncation, independent wire updates, addressed edits, shell redirection to name, Exec dispatch, rendered screen JSON, and OS-file reads. Linux follows `O_TRUNC` with a `Twstat` carrying zero length and an `mtime` hint. Pardes accepts this truncation without storing caller-selected timestamps; standalone timestamp, permission, and ownership changes remain unsupported. The initial kernel probe passed on this host on 2026-09-14. The broader `fs-test` has an existing syntax-bold assertion failure (now `test/fs.py:615`), also reproduced on the cached editor binary preceding the truncation fix.