npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@judaharagao/opencode-ssh

v1.4.1

Published

SSH access plugin for OpenCode - secure remote command execution with command blocking

Readme

opencode-ssh

SSH access plugin for OpenCode — secure remote command execution with command blocking and audit.

Features

  • 🔐 SSH Session Management — Connect to multiple remote servers simultaneously
  • Real-time Command Execution — Execute commands with live output streaming
  • 🛡️ Security-First Design — Destructive commands blocked 100%, risky commands require approval every time
  • 📋 Full Audit Trail — Every command is logged with timestamps, results, and details
  • 🔒 Three Security Modes — Full, Restricted, or Read-Only
  • 📤 File Transfer — Upload and download files via SCP/SFTP
  • 🎯 Command Safety Checker — Preview command safety before execution
  • ⚙️ Configurable Policies — Add custom blocklist/allowlist patterns
  • 🛤️ Proxy SupportProxyJump and ProxyCommand from your ssh config
  • 🛡️ Host Key Verification — optional strict_host_key MITM protection via known_hosts
  • Rate Limiting — per-host command rate limit and cooldown
  • 🔁 Auto-Reconnect — dropped sessions reconnect automatically on the next command
  • 🔐 Credential Hygiene — passwords are cleared from memory after a successful handshake

Installation

Add to your opencode.json:

{
  "plugin": ["@judaharagao/opencode-ssh"]
}

Or with configuration:

{
  "plugin": [
    ["@judaharagao/opencode-ssh", {
      "mode": "full",
      "max_sessions": 5,
      "default_timeout": 30,
      "audit_enabled": true
    }]
  ]
}

Configuration Options

| Option | Type | Default | Description | |--------|------|---------|-------------| | mode | "full" | "restricted" | "read_only" | "full" | Security mode for command execution | | max_sessions | number | 5 | Maximum concurrent SSH sessions | | default_timeout | number | 30 | Default command timeout in seconds | | audit_enabled | boolean | true | Enable audit logging | | blocklist_extra | string[] | [] | Additional regex patterns to block | | allowlist | string[] | [] | Additional allowed patterns (restricted/read_only mode) — merged with the per-project allowlist from ssh.security_policy | | ssh_config_path | string | ~/.ssh/config | Path to the SSH config file used to resolve host aliases, defaults, proxies, and auto-connect targets | | auto_connect | boolean | false | Connect automatically at startup to every Host entry in the ssh config that has a HostName (with retry/backoff) | | auto_reconnect | boolean | true | Reconnect a dropped session automatically before the next ssh.exec/ssh.upload/ssh.download (key-authenticated sessions) | | strict_host_key | boolean | false | Reject connections whose host key is not an exact match in ~/.ssh/known_hosts (MITM protection) | | rate_limit_per_minute | number | 120 | Max commands allowed per host per minute | | cooldown_seconds | number | 0 | Minimum delay (seconds) between commands on the same host |

SSH Config Integration

The plugin can reuse your existing ~/.ssh/config (or a custom path via ssh_config_path):

  • Host resolutionssh.connect(host="myalias") resolves the alias to its HostName, and automatically applies the User, Port and IdentityFile from the config. username, port and auth_method/key_path become optional when configured.
  • ProxyJump / ProxyCommandProxyJump and ProxyCommand directives in the ssh config are honored, so connections route through bastion/jump hosts transparently.
  • Auto-connect — with "auto_connect": true, the plugin connects at startup to every Host entry that has a HostName, using the configured key (or ~/.ssh/id_rsa). Unreachable hosts are retried with backoff and skipped without blocking startup.
  • Missing file alert — if ssh_config_path points to a file that does not exist, the plugin warns on connect instead of silently ignoring the setting.

Example ssh config:

Host prod-web
    HostName 10.0.0.10
    User deploy
    Port 2222
    IdentityFile ~/.ssh/prod_key

Host prod-db
    HostName 10.0.0.50
    ProxyJump jumpuser@bastion:2200

With ssh.connect(host="prod-web") the plugin connects to [email protected]:2222 using ~/.ssh/prod_key. prod-db is reached tunneled through bastion.

Security Modes

Full Mode

All commands are allowed except those in the blocklist. Destructive commands are always blocked. Risky commands require approval.

Restricted Mode

Only commands in the allowlist + read-only commands are allowed. Risky and destructive commands are blocked.

Read-Only Mode

Only read-only commands (ls, cat, grep, docker ps, etc.) are allowed. No write operations.

Custom Allowlist

Restricted and read-only modes respect allowlist patterns from both sources (merged, deduped):

  1. Plugin config — in your opencode.json:

    ["@judaharagao/opencode-ssh", {
      "mode": "restricted",
      "allowlist": ["docker stop .*", "docker rm .*"]
    }]
  2. Per-project policy — at runtime via ssh.security_policy:

    ssh.security_policy(action="add_allowlist", pattern="docker stop .*")

    Patterns persist in <project>/.opencode-ssh/policy.json and are merged with the config patterns on every execution. Either source alone is enough to permit a matching command in restricted/read_only mode. The destructive blocklist always wins over any allowlist entry.

Commands (Tools)

ssh.connect

Establish an SSH connection to a remote server.

ssh.connect(host="192.168.1.100", username="admin", auth_method="key")

ssh.disconnect

Close an SSH session.

ssh.disconnect(session_id="ssh-abc123")

ssh.list_sessions

List all active SSH sessions.

ssh.list_sessions()

ssh.exec

Execute a command on a remote server.

ssh.exec(session_id="prod-server", command="docker ps -a")

ssh.exec_batch

Execute multiple commands in sequence.

ssh.exec_batch(session_id="prod-server", commands="cd /app\nls -la\ndocker ps")

ssh.upload

Upload a file via SCP.

ssh.upload(session_id="prod-server", local_path="./config.yml", remote_path="/app/config.yml")

ssh.download

Download a file via SCP.

ssh.download(session_id="prod-server", remote_path="/var/log/app.log", local_path="./app.log")

ssh.check_command

Check if a command is safe (dry-run).

ssh.check_command(command="rm -rf /tmp/cache")

ssh.security_policy

View or modify the security policy.

ssh.security_policy(action="view")
ssh.security_policy(action="add_blocklist", pattern="custom-dangerous-.*")
ssh.security_policy(action="add_allowlist", pattern="docker stop .*")
ssh.security_policy(action="remove_allowlist", pattern="docker stop .*")

User confirmation required: Viewing the policy is read-only and does not prompt. Every mutation (add_allowlist, remove_allowlist, add_blocklist, remove_blocklist) triggers opencode's permission prompt and is re-confirmed by the user every single time — the LLM can never self-grant an allowlist entry without explicit user approval.

ssh.audit_log

View the command audit trail.

ssh.audit_log(limit=20)
ssh.audit_log(session_id="prod-server", command_filter="docker")

Security

Host Key Verification

With "strict_host_key": true the plugin verifies the remote server's host key against ~/.ssh/known_hosts before completing the handshake:

  • a matching key → connection allowed;
  • a changed key (possible MITM) → connection refused;
  • an unknown host → connection refused (add the host key to known_hosts first, e.g. via ssh-keyscan host >> ~/.ssh/known_hosts).

Destructive Commands (100% Blocked)

These commands are permanently blocked with no exceptions:

  • rm -rf /, rm -rf ~, rm -rf .*
  • mkfs, dd if=/dev/zero
  • Fork bombs (:(){:|:&};:)
  • chmod -R 777 /, chmod -R 000 /
  • shutdown, reboot, init 0/6
  • kill -9 1, killall
  • iptables -F, ufw disable
  • wget/curl | sh|bash

Risky Commands (Approval Required Every Time)

These commands require your explicit approval each time:

  • DROP TABLE, DELETE FROM, TRUNCATE
  • sudo su, sudo -i
  • systemctl stop/disable
  • kill -9, kill -15
  • npm uninstall -g, apt remove/purge
  • userdel, groupdel
  • iptables -A/-D

Credential Safety

  • Passwords and SSH keys are never stored in logs or output
  • Session info only contains host, username, and port
  • Passwords are cleared from memory right after a successful handshake
  • For this reason password-authenticated sessions do not auto-reconnect (re-issue ssh.connect); key-authenticated sessions reconnect automatically from the on-disk key
  • All sessions are destroyed when the plugin is disposed

Audit Log

All commands are logged in .opencode-ssh/audit.jsonl with:

  • Timestamp
  • Session ID (host@user)
  • Command executed
  • Result (success/blocked/approved/error)
  • Exit code
  • Duration
  • Matched security rule (if any)

View the audit log with ssh.audit_log.

Development

Versioning

package.json is the single source of truth for the plugin version. It is propagated automatically by scripts/sync-version.cjs to:

  • src/version.tsPLUGIN_VERSION (between GENERATED markers)
  • marketplace.jsonversion

Bump the version in package.json, then run bun run version:sync (or just bun run build, which runs the sync first).

License

MIT