# pi-ssh extension specification ## Goal Pi and its default tools remain local. Explicit collision-free tools perform selected operations on one configured remote server: - `ssh_read` - `ssh_write` - `ssh_edit` - `ssh_find` - `ssh_grep` - `ssh_bash` The extension is for operating servers from local projects, not for replacing Pi's local workspace. It never auto-loads remote project instructions. ## Connection model Runtime communication uses Node `ssh2` only. OpenSSH is not spawned during Pi sessions. A user must explicitly import a concrete OpenSSH alias before connecting: ```text ssh_config.sh import → ssh -G → user chooses private-key or password auth → ssh2 obtains host key, user confirms fingerprint → ssh2 verifies authentication → encrypted vault is updated ``` The resulting host ID is the only runtime selector: ```text /ssh [:/absolute/path] pi --ssh [:/absolute/path] ``` Arbitrary `user@host`, port overrides, ProxyJump, and ProxyCommand are not supported in the first pure-ssh2 version. Unsupported imported configuration is rejected rather than ignored. ## Vault Default paths: ```text ${XDG_CONFIG_HOME:-$HOME/.config}/my-pi/pi-ssh/hosts.enc ${XDG_CONFIG_HOME:-$HOME/.config}/my-pi/pi-ssh/vault.key ``` The directory is mode `700` and files are mode `600` on POSIX. A random adjacent 256-bit key encrypts and authenticates the complete validated configuration with AES-256-GCM. Each write uses a fresh IV and atomic replacement; plaintext is never written to a temporary file. The adjacent-key design prevents casual disclosure of `hosts.enc` alone but does not protect against code able to read both files as the same local user. The encrypted payload includes endpoint, authentication data, host groups, default cwd, and a pinned SHA256 host-key fingerprint. Private keys remain in their original paths; only their path and optional passphrase are stored. ## Authentication Supported methods: - password; - single-password keyboard-interactive; - OpenSSH private key; - encrypted private key with passphrase. Passwords, passphrases, private-key contents, vault key, and decrypted configuration must never enter command arguments, logs, permission evidence, system prompts, or Pi session entries. ## Host-key verification Import displays the observed host-key algorithm and SHA256 fingerprint for explicit confirmation. Runtime `hostVerifier` must compare the server key with the pinned fingerprint and fail closed on any mismatch. Key changes require explicit host update. ## Transport One persistent `ssh2.Client` belongs to the active host. Connection loss fails closed and no operation is automatically replayed. ### Shell `ssh_bash` and explicit user `!` commands open exec channels. Commands run through `bash -lc` after changing to the selected remote cwd. Output streams through the normal Pi Bash operations callback. Abort or timeout closes the channel without reconnecting or replaying. ### Files SFTP implements file operations: - read and access checks; - recursive directory creation; - remote write through a temporary file; - atomic OpenSSH rename extension when available; - safe direct-write fallback when SFTP v3 cannot replace an existing target. Remote paths map from Pi's local factory cwd into the selected remote cwd, but permission-system access extractors prevent those paths from entering local path normalization. ### Search Search tools execute one capability-adaptive, bounded shell pipeline inside the already approved tool call. They never install or upload binaries. - `ssh_find`: `fd` → `fdfind` → `git ls-files` → `find`; fixed filename/path substring semantics. - `ssh_grep`: `rg` → `git grep` → `find -exec grep`; literal case-insensitive semantics by default. - each backend emits at most `limit + 1` lines so truncation is explicit; public `limit` is 1–200; each returned line is capped. - relative paths resolve against remote cwd and `~/` against remote home. - user strings are single-quoted as shell arguments and NUL/newline input is rejected. - capability detection occurs only within the reviewed search call. - search output is normalized by `pi-ssh` and excluded from RTK compaction. Direct search commands remain denied through `ssh_bash`; structured search tools are the authoritative remote search surface. ## Permission boundary There is one permission gate: `pi-permission-system`. - `ssh_read`, `ssh_write`, `ssh_edit`, `ssh_find`, and `ssh_grep` default to `ask`. - `ssh_bash` is a Bash-semantic `shellTools` alias with `decisionFloor: "ask"`. - Bash hard denies remain denies. - All asks enter the configured authorizer chain. - Permission service absence or bridge registration failure must not install a permissive fallback. Evidence includes configured host ID, endpoint, port, remote cwd, and a bounded operation summary, never credentials. ## Session and UI The session stores only host ID, remote cwd, and remote home. Resume reloads current vault data and establishes a new ssh2 connection; failures fall back to local mode. `/ssh off` disposes the client and clears the status line. The system prompt states that default tools are local and `ssh_*` tools are remote. It does not include remote file content.