MCPcopy Index your code
hub / github.com/cv/pi-ssh-remote

github.com/cv/pi-ssh-remote @v0.0.9

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.0.9 ↗ · + Follow
105 symbols 263 edges 31 files 9 documented · 9%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

pi-ssh-remote

A pi coding agent extension that redirects all file operations and commands to a remote host via SSH. This allows you to run pi locally while having it operate on a remote machine.

Installation

Option 1: Clone to extensions directory (recommended)

# Global installation (all projects)
git clone https://github.com/cv/pi-ssh-remote ~/.pi/agent/extensions/pi-ssh-remote

# Or project-local installation
git clone https://github.com/cv/pi-ssh-remote .pi/extensions/pi-ssh-remote

Option 2: Add to settings.json

Clone the repository anywhere, then add the path to your ~/.pi/agent/settings.json:

{
  "extensions": ["/path/to/pi-ssh-remote"]
}

Option 3: Load manually with CLI flag

pi -e /path/to/pi-ssh-remote

Usage

Important: Disable conflicting built-in tools

This extension registers tools named bash, read, write, edit, grep, find, and ls which conflict with pi's built-in tools of the same names. You must disable the built-in versions to avoid duplicate tool errors:

# Disable all built-in tools (extension provides SSH-wrapped versions)
pi --tools '' -e /path/to/pi-ssh-remote

Configure via command

Once pi starts with the extension loaded, use the /ssh command:

/ssh user@example.com              # Set remote host
/ssh user@example.com /path/to/dir # Set remote host + working directory
/ssh port 2222                     # Set custom port
/ssh command tsh ssh               # Set custom SSH command (e.g., Teleport)
/ssh cwd /path/to/dir              # Set remote working directory
/ssh timeout 60                    # Set timeout for SSH operations (seconds)
/ssh                               # Show current configuration
/ssh off                           # Disable remote mode

Configure via CLI flags

You can also configure the SSH remote directly from the command line:

pi --tools '' -e /path/to/pi-ssh-remote --ssh-host user@example.com
pi --tools '' -e /path/to/pi-ssh-remote --ssh-host user@example.com --ssh-cwd /path/to/project
pi --tools '' -e /path/to/pi-ssh-remote --ssh-host user@example.com --ssh-port 2222
pi --tools '' -e /path/to/pi-ssh-remote --ssh-host user@example.com --ssh-command "tsh ssh"
pi --tools '' -e /path/to/pi-ssh-remote --ssh-host user@example.com --ssh-timeout 60

Example session

# Start pi with the extension and SSH preconfigured
pi --tools '' -e /path/to/pi-ssh-remote --ssh-host myuser@myserver.com --ssh-cwd /home/myuser/project

# With custom port:
pi --tools '' -e /path/to/pi-ssh-remote --ssh-host myuser@myserver.com --ssh-port 2222

# With Teleport:
pi --tools '' -e /path/to/pi-ssh-remote --ssh-host myuser@myserver.com --ssh-command "tsh ssh"

# Or start without SSH and configure later with /ssh command:
pi --tools '' -e /path/to/pi-ssh-remote
# Then in pi:
/ssh myuser@myserver.com /home/myuser/project
/ssh port 2222
/ssh timeout 30                    # Set 30-second timeout for SSH operations

Using with GitHub Codespaces

GitHub Codespaces can be accessed via SSH by generating an SSH config:

# Generate SSH config for your codespaces (one-time setup)
gh cs ssh --config >> ~/.ssh/config

This creates SSH host aliases like cs.my-codespace-name.main that you can use directly:

# Use the generated host alias with pi-ssh-remote
pi --tools '' -e /path/to/pi-ssh-remote --ssh-host cs.my-codespace-name.main --ssh-cwd /workspaces/my-project

The generated config includes ControlMaster auto for SSH connection multiplexing, making repeated commands fast.

Features

  • Provides SSH-wrapped tools:
  • bash - Executes commands on the remote host
  • read - Reads files from the remote host
  • write - Writes files to the remote host
  • edit - Edits files on the remote host
  • grep - Searches file contents on the remote host
  • find - Finds files by name pattern on the remote host
  • ls - Lists directory contents on the remote host

  • Session persistence - Configuration persists across session reloads and branching

  • UI integration:

  • Shows status in footer: 🔗 SSH: user@host:port (cwd) [command] ⏱timeout
  • Tool calls show [user@host] prefix
  • Tool results show [remote] prefix

  • Flexible connection options:

  • Custom port via --ssh-port or /ssh port
  • Custom SSH command via --ssh-command or /ssh command (for Teleport, bastion hosts, etc.)
  • Configurable timeouts via --ssh-timeout or /ssh timeout to prevent hanging operations

  • Large file support - Uses chunked base64 encoding for files that exceed shell argument limits

  • Proper shell escaping - Handles special characters in paths and content

  • Smart tool detection - Auto-detects rg (ripgrep) and fd on the remote host and uses them when available, falling back to standard grep and find otherwise

Requirements

  • SSH access to the remote host (key-based authentication recommended for seamless operation)
  • Remote host must have standard utilities: cat, sed, mkdir, base64, printf, ls, head, grep (or rg), find (or fd)

How it works

When SSH remote is configured, the extension wraps tool operations with SSH:

Tool Remote execution
bash with ls -la ssh user@host 'cd /remote/cwd && ls -la'
read of file.txt ssh user@host 'cd /remote/cwd && cat file.txt'
write to file.txt ssh user@host 'cd /remote/cwd && printf ... \| base64 -d > file.txt'
edit of file.txt Read via SSH, modify locally, write back via SSH

For write operations, content is base64-encoded to safely pass through the shell and handle binary data.

Limitations

  • No image support for remote read - Images cannot be displayed inline when reading from remote. The file will be read as text.
  • No streaming for large outputs - Output is collected and returned after command completes.
  • SSH connection per command - Each tool call establishes a new SSH connection. Consider using SSH connection multiplexing (ControlMaster) for better performance.
  • Tool name conflicts - Must disable all built-in tools using --tools '' flag.

Recommended SSH config for performance

Add to your ~/.ssh/config:

Host your-server
    HostName example.com
    User youruser
    ControlMaster auto
    ControlPath ~/.ssh/sockets/%r@%h-%p
    ControlPersist 600

Then create the sockets directory:

mkdir -p ~/.ssh/sockets

This keeps SSH connections open for 10 minutes, making subsequent commands much faster.

Troubleshooting

"Tool names must be unique" error

This occurs when both the extension's tools and pi's built-in tools are loaded. Solution:

pi --tools '' -e /path/to/pi-ssh-remote

Model says it's in "READ-ONLY mode"

The model may incorrectly assume it's read-only if the conversation context suggests limited tools. Simply instruct the model that it has write and edit capabilities, or start a fresh session.

SSH connection failures

Ensure: 1. You can SSH to the host manually: ssh user@host 2. Key-based authentication is set up (password prompts won't work in non-interactive mode) 3. The host alias (if using SSH config) is correctly configured

Contributing

See CONTRIBUTING.md for development setup and testing instructions.

License

MIT

Extension points exported contracts — how you extend this code

TruncationResult (Interface)
(no doc)
__mocks__/@mariozechner/pi-coding-agent.ts
SSHConfig (Interface)
(no doc)
src/types.ts
SSHConfig (Interface)
(no doc)
e2e/ssh-tools.e2e.test.ts
ExtensionAPI (Interface)
(no doc)
__mocks__/@mariozechner/pi-coding-agent.ts
RemoteToolsCache (Interface)
(no doc)
src/types.ts
ExtensionContext (Interface)
(no doc)
__mocks__/@mariozechner/pi-coding-agent.ts
ToolResultWithError (Interface)
(no doc)
src/types.ts
Renderable (Interface)
(no doc)
__mocks__/@mariozechner/pi-tui.ts

Core symbols most depended-on inside this repo

createMockExtensionAPI
called by 130
tests/test-utils.ts
createMockContext
called by 90
tests/test-utils.ts
getHost
called by 24
src/types.ts
escapeForShell
called by 16
src/types.ts
getErrorMessage
called by 14
src/types.ts
buildRemoteCommand
called by 9
src/types.ts
sshExec
called by 9
src/types.ts
resetAllMocks
called by 9
tests/test-utils.ts

Shape

Function 62
Method 28
Interface 11
Class 4

Languages

TypeScript100%

Modules by API surface

src/types.ts28 symbols
src/state.ts13 symbols
__mocks__/@mariozechner/pi-tui.ts11 symbols
e2e/ssh-tools.e2e.test.ts10 symbols
__mocks__/@mariozechner/pi-coding-agent.ts6 symbols
tests/test-utils.ts5 symbols
src/tools/write.ts4 symbols
src/tools/read.ts4 symbols
src/tools/ls.ts4 symbols
src/tools/grep.ts4 symbols
src/tools/find.ts4 symbols
src/tools/edit.ts4 symbols

For agents

$ claude mcp add pi-ssh-remote \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact