Remote operations for Pi over SSH.
pi-extension-ssh turns SSH from an occasional shell escape into a repeatable Pi capability with:
- remote session mode
- remote tool routing
- local audit logging
- target profiles
- allowlist support
- environment guardrails
- confirmation for prod and other protected targets
Created by Fabio Rizzo Matos · contact: fabiorizzo@vindula.com.br
You can already do this with plain shell commands:
ssh user@host "cd /srv/app && docker ps"But that is not the same as giving Pi a real remote operating mode.
With this package installed, Pi can treat the remote host as the working environment itself.
That matters when you want:
- repeatable remote sessions instead of one-off SSH hops
ssh-read,ssh-write,ssh-edit,ssh-bash,ssh-grep,ssh-find,ssh-lsoperating remotely by default- an audit trail in
.pi/ssh/ssh.log - stable target names like
prod-app,staging-app,bastion-eu - environment-aware controls for sensitive systems
In short:
- plain SSH = good for ad-hoc commands
- pi-extension-ssh = good for remote operations workflows
Run a whole Pi session against a remote host:
pi -e ./ssh.ts --ssh user@host
pi -e ./ssh.ts --ssh user@host:/remote/path
pi -e ./ssh.ts --ssh prod-appWhen --ssh is active:
- Pi resolves a remote working directory
ssh-read,ssh-write,ssh-edit,ssh-bash,ssh-grep,ssh-find,ssh-lsoperate on the remote machine by default- user
!commandsalso execute remotely - the status bar shows the active remote target
- connect runs an automatic preflight check and surfaces missing remote tools early
- the system prompt reflects the remote cwd and environment
If you explicitly want the SSH extension to override the built-in tool names (read, write, edit, bash, grep, find, ls), set this in .pi/ssh/config.json or ~/.pi/agent/ssh/config.json:
{
"toolRoutingMode": "builtin-overrides"
}Default:
toolRoutingMode: "namespaced"to avoid conflicts with tool wrappers such aspi-tool-display
Run a one-off remote command without switching the whole session:
/ssh-run user@host:/srv/app ls -la
/ssh-run prod-app docker ps
On /ssh-connect and --ssh, the extension runs a lightweight preflight check automatically.
That verifies:
- connectivity
- resolved remote
pwd - expected remote tools such as
bash,cat,mkdir,base64,file,rg, andfd
You can also run the same verification on demand with:
/ssh-health
/ssh-health prod-app
SSH activity is logged locally to:
.pi/ssh/ssh.log
Each line is structured JSON and can include metadata such as:
- remote target
- profile
- environment
- mode
- decision (
executed,blocked,confirmed,denied) - reason
The package supports project-local and global SSH config files:
- project:
<project>/.pi/ssh/config.json - global:
~/.pi/agent/ssh/config.json
This lets you:
- define friendly target names
- restrict where Pi is allowed to connect
- require confirmation for protected targets
- block dangerous commands in certain environments
- keep shared global targets read-only while still importing them into a project when local overrides are needed
The extension now includes a TUI-first target manager:
- create local config with
/ssh-configure - manage local targets with
/ssh-manage - view both project-local and global targets in one place
- import global targets into project-local config for safe per-project overrides
You can store runbooks in:
- project:
<project>/.pi/ssh/runbooks/*.{md,markdown,json} - global:
~/.pi/agent/ssh/runbooks/*.{md,markdown,json}
Markdown runbooks use frontmatter plus fenced command blocks, which makes them easier to read and review.
Runbooks let you:
- define repeatable operational checklists
- bind a default target to a named workflow
- preview steps before execution
- require per-runbook or per-step confirmation
- pass parameters such as
service,container, andpath - pass extra generic parameters with
--param key=valueor inline flags like--release=2026.03.23 - keep execution tied to the same SSH guardrails and logs
pi install git:github.com/vindulaintranet/pi-extension-sshpi install git:github.com/vindulaintranet/pi-extension-ssh@v0.1.6pi install /absolute/path/to/pi-extension-sshAfter installing, restart Pi or run:
/reload
/ssh-run user@host:/srv/app docker ps
pi -e ./ssh.ts --ssh user@host:/srv/app/ssh-connect
If no targets exist yet, the extension can now open a TUI wizard and create .pi/ssh/config.json for you.
After that, use /ssh-manage to add, edit, remove, review, filter/search, import, or connect targets without manually opening the JSON first.
/ssh-context
/ssh-health
/ssh-summary
/ssh-runbooks
/ssh-runbook
/ssh-disconnect
Add a config file:
{
"allowlist": ["staging-app", "prod-app"],
"targets": {
"staging-app": {
"remote": "ops@staging-host",
"cwd": "/srv/app",
"environment": "staging"
},
"prod-app": {
"remote": "ops@prod-host",
"cwd": "/srv/app",
"environment": "prod",
"requiresConfirmation": true,
"aliases": ["production"]
}
},
"environmentPolicies": {
"prod": {
"requiresConfirmation": true,
"confirmWriteOperations": true,
"confirmMutatingCommands": true,
"blockedCommands": [
"rm -rf",
"git reset --hard",
"terraform destroy"
]
}
}
}Then run:
pi -e ./ssh.ts --ssh prod-appList configured targets with:
/ssh-targets
Create a project-local SSH config through the TUI:
/ssh-configure
Manage project-local SSH targets through the TUI:
/ssh-manage
The manager shows both:
- project-local targets you can edit here
- global targets that are read-only here, but importable into the project
- a filter/search flow so large target sets are easier to navigate
/ssh-configure— create.pi/ssh/config.jsonthrough a TUI wizard/ssh-manage— add, edit, remove, review, filter/search, connect, and import global targets into project-local config from the TUI/ssh-connect— choose a configured target interactively or pass one explicitly; offers config creation when none exist/ssh-disconnect— leave the active SSH session target/ssh-context— inspect the active target, policies, preflight status, and log path/ssh-health [target]— verify connectivity and required remote tools on demand/ssh-summary [--format text|markdown|json|raw] [--output <path>] [--last] [--include-entries] [--raw]— review or export the current/recent SSH session summary, including runbook reports when present/ssh-runbook-report [name] [--format text|markdown|json] [--output <path>] [--last]— export just the runbook execution report(s) from the current or most recent session/ssh-runbooks [query|--filter <query>]— list or filter available project-local and global SSH runbooks/ssh-runbook <name> [--target <target>] [--service <name>] [--container <name>] [--path <path>] [--param key=value] [--filter <query>]— preview and execute a named SSH runbook with parameter overrides/ssh-targets— list project-local and global profiles with source markers/ssh-run <target> <command>— run one explicit remote command without switching the whole session
Example summary exports:
/ssh-summary
/ssh-summary --format markdown --include-entries --output .pi/ssh/reports/latest.md
/ssh-summary --format json --output .pi/ssh/reports/latest.json --last
/ssh-summary --raw --output .pi/ssh/reports/latest.jsonl --last
Example runbook usage:
/ssh-runbooks
/ssh-runbooks prod
/ssh-runbook prod-health-check --container app --param release=2026.03.23
/ssh-runbook staging-deploy-smoke --target staging-app --service web --path /srv/app
/ssh-runbook-report --format markdown --output .pi/ssh/reports/runbooks.md
Use profile-based access such as prod-app with confirmation and blocked commands for safer incident work.
Point Pi at staging-app and let it inspect logs, config, and code remotely with normal tools.
Keep SSH targets named and documented instead of relying on remembered shell snippets.
Use target profiles per customer/tenant/region and maintain a local audit trail of remote activity.
This inline example is a compact illustration.
If you want copy-paste-ready templates for common setups, use the files in examples/:
examples/dev-staging-prod.config.jsonexamples/bastion-jumpbox.config.jsonexamples/customer-environments.config.jsonexamples/global-shared-platform.config.jsonexamples/project-local-overrides.config.jsonexamples/runbooks/prod-health-check.mdexamples/runbooks/staging-deploy-smoke.mdexamples/runbooks/prod-health-check.jsonexamples/runbooks/staging-deploy-smoke.json
{
"allowlist": ["prod-app", "staging-app", "bastion-eu"],
"targets": {
"prod-app": {
"remote": "ops@prod-host",
"cwd": "/srv/app",
"environment": "prod",
"requiresConfirmation": true,
"aliases": ["production"]
},
"staging-app": {
"remote": "ops@staging-host",
"cwd": "/srv/app",
"environment": "staging"
},
"bastion-eu": {
"remote": "admin@bastion-eu",
"cwd": "/home/admin",
"environment": "default"
}
},
"environmentPolicies": {
"prod": {
"requiresConfirmation": true,
"confirmWriteOperations": true,
"confirmMutatingCommands": true,
"blockedCommands": [
"rm -rf",
"git reset --hard",
"terraform destroy",
"shutdown",
"reboot"
]
}
}
}A practical enterprise setup is:
- keep shared targets such as bastions, platform hosts, and approved base profiles in the global config
- keep project-specific names, cwd values, aliases, and overrides in the local project config
- keep shared operational runbooks in the global runbook directory and project-specific runbooks in the project runbook directory
- prefer Markdown+frontmatter runbooks for human review, and keep JSON as an escape hatch for more structured cases
- use
/ssh-manageto view both layers and import a global target into the project when you need a local override
That gives you:
- shared platform defaults
- safer per-project customization
- clearer ownership of what is centrally managed vs locally editable
This package already includes the agreed enterprise track features:
- allowlist
- host profiles
- remote
grep/find/ls - guardrails by environment
- structured logs
- confirmation for prod
- SSH key-based authentication
bashon the remote host- remote utilities used by the extension:
cattestmkdirbase64filergfor remotegrepfdfor remotefind
- remote
findcurrently expectsfdon the remote host - remote
grepcurrently expectsrgon the remote host - target handling is config-driven; this version includes TUI setup and target management, but still keeps JSON as the source of truth
- the TUI manager edits only project-local config; global targets are visible and importable, but remain read-only there
- runbooks support Markdown+frontmatter and JSON, but this version does not yet provide advanced templating, branching, or variable typing
- logs are structured JSONL locally, but no external export sink is included yet
- historical summaries are session-scoped; this version does not provide arbitrary cross-session analytics
npm install
npm run validateThis runs:
- unit tests for SSH parsing, config loading, allowlist/policy behavior, logging, command building, and truncation
- bundle validation for the Pi extension entrypoint
- package validation with
npm pack --dry-run
See:
MIT