Skip to content

Repository files navigation

opencode-ops

All-in-one OpenCode operations plugin — SSH sessions, local terminals, GitHub Actions, and a web dashboard in a single plugin.

Overview

opencode-ops is an OpenCode operations plugin combining SSH session management, local terminal emulation, GitHub Actions/secrets management, and a web dashboard. Inspired by opencode-ssh-session.

Features

SSH Sessions

  • Multiple concurrent sessions — connect to several hosts simultaneously
  • .ssh/config integration — list and use hosts from your SSH config; session IDs prefer config aliases over raw IPs
  • Auto-reconnect — dead sessions for the same host are auto-flushed before connecting, preventing _1, _2, _3 ID proliferation
  • Session flush & reconnect — manually flush dead sessions or reconnect a dead session while keeping its ID
  • Heartbeat monitoring — automatic health checks with reconnection logic
  • File transfer — upload/download files via base64 over existing connections
  • Remote file editing — read, write, append, and edit files on remote hosts (chunked reads for large files)
  • Interactive input — send passwords and confirmations to SSH prompts
  • Password authentication — hosts without a key are prompted via an interactive ASKPASS flow in the web dashboard
  • Smart session resolution — auto-selects session when only one exists

Local Terminals

  • Local command execution — spawn bash sessions on the host machine
  • Pattern watching — auto-detect errors, ready states, warnings
  • Ring buffer — capped output buffer (50k lines default) to prevent memory growth
  • Background sessions — long-running processes with notifications on exit
  • Interactive stdin — send input directly to running processes

GitHub Integration

  • Repository info — visibility, default branch, language, topics
  • File browsing — read files with pagination, search, and line-level context; list directories
  • Environments — list repository environments (production, staging, etc.)
  • Variables — CRUD for repo and environment-level Actions variables
  • Secrets — list, set, delete repo/environment secrets (libsodium sealed box encryption)
  • Org-level — list organization variables and secrets
  • Workflows — list workflows, runs, jobs, steps with status icons
  • Logs — download and read workflow run/job logs (auto-unzipped, plain-text fallback)
  • Control — dispatch, cancel, and rerun workflows
  • Artifacts — list and get download URLs for build artifacts
  • Per-tool tokens — pass a GitHub PAT to any github_* tool; supports $ENV_VAR references

Dashboard & Integration

  • Web dashboard/ops-dashboard slash command opens browser UI
  • Multi-instance dashboard — view SSH & terminal sessions from multiple opencode instances in one dashboard
  • Session compacting — active sessions preserved in context across conversations
  • System prompt injection — agent always knows which sessions are active
  • Bash guard — reminds the AI to use SSH/terminal tools instead of raw commands
  • Slash commands/ops-dashboard

Installation

Add the plugin to your OpenCode configuration (opencode.json):

{
"plugin": ["opencode-ops"]
}

Requires bun >= 1.1.0 and OpenCode with plugin support (@opencode-ai/plugin >= 1.4.0).

For GitHub tools, set the GITHUB_TOKEN environment variable with a valid GitHub personal access token.

SSH Tools

ToolDescription
ssh_connectOpen a new persistent SSH session (auto-flushes dead sessions for same host)
ssh_execExecute a command on an SSH session (output truncated at 500 lines / 40KB)
ssh_disconnectClose an SSH session
ssh_flushRemove all dead/disconnected sessions (optionally for a specific host)
ssh_reconnectReconnect a dead session, reusing its session ID
ssh_listList all active SSH sessions with status
ssh_infoGet detailed info for a specific session
ssh_hostsList hosts from ~/.ssh/config
ssh_uploadUpload a local file to a remote host
ssh_downloadDownload a file from a remote host
ssh_inputSend raw input to an SSH session
ssh_write_fileCreate or overwrite a file on a remote host
ssh_appendAppend content to a file on a remote host
ssh_readRead a file from a remote host (with line numbers)
ssh_editEdit a file on a remote host (find & replace, chunked reads for large files)
ssh_dashboardOpen the web dashboard

ssh_connect

ParameterTypeRequiredDescription
hoststringyesSSH host — prefer an alias from ~/.ssh/config (e.g. prod-web). Use ssh_hosts to discover aliases. Only use user@IP if no alias exists.
optionsstringnoExtra SSH flags (-p 2222, -i ~/.ssh/mykey)
passwordstringnoSSH password for hosts without a key. Warning: goes through the chat context — prefer the dashboard's interactive prompt for sensitive passwords.

Dead sessions for the same host are automatically flushed before connecting, so the base session ID is reused instead of creating _2, _3, etc. Session IDs are derived from SSH config aliases when available (e.g. prod-web instead of 10-0-0-5).

Password Authentication

Authentication is routed per host:

  • Explicit key — the host has IdentityFile in ~/.ssh/config (or -i in options): key-only auth with BatchMode=yes, never prompts.
  • No explicit key — password-capable mode via an SSH_ASKPASS helper (OpenSSH ≥ 8.4 required on the client). Default keys (~/.ssh/id_rsa, etc.) and ssh-agent are still tried silently first; if they fail, ssh falls back to a password:
    • if a password was passed to ssh_connect (or entered in the dashboard's Connect dialog), it is used directly;
    • otherwise the web dashboard opens automatically with an interactive password prompt — type the password there and the pending ssh_connect call completes;
    • if no password arrives within ~2 minutes, the connection fails with a hint.

The password is kept in memory only (never written to logs, API responses, or the system prompt) so ssh_reconnect works without re-typing; it is cleared on disconnect and after a failed login. During the handshake it travels through a transient 0600 file inside a private 0700 directory (~/.cache/opencode-ops/) that is deleted immediately after connecting.

Limitation: password auth is not supported through ProxyJump — jump hosts still require keys/agent.

ssh_exec

ParameterTypeRequiredDescription
commandstringyesShell command to execute
session_idstringnoSession ID (auto-resolved if only one exists)
timeoutnumbernoTimeout in ms (default: 120000)

Output is truncated at 500 lines / 40KB. For reading files, prefer ssh_read (supports pagination). For file transfers, use ssh_download/ssh_upload.

ssh_flush

ParameterTypeRequiredDescription
hoststringnoOnly flush dead sessions for this host. Omit to flush all dead sessions.

ssh_reconnect

ParameterTypeRequiredDescription
session_idstringnoSession ID to reconnect. Omit if only one dead session exists.

Shell state is lost — this creates a fresh connection, but reuses the same session ID.

ssh_upload / ssh_download

ParameterTypeRequiredDescription
localPathstringyesLocal file path
remotePathstringyesRemote destination path
session_idstringnoSession ID

ssh_input

Sends raw input directly to the SSH stdin — use \n for Enter key:

ParameterTypeRequiredDescription
inputstringyesInput string (add \n for Enter)
session_idstringnoSession ID

ssh_write_file

Create or overwrite a file on the remote host. Content is base64-encoded before transfer. Creates parent directories automatically.

ParameterTypeRequiredDescription
filePathstringyesAbsolute path on the remote host
contentstringyesFile content to write
session_idstringnoSession ID

ssh_append

Append content to a file on the remote host. Creates the file if it doesn't exist.

ParameterTypeRequiredDescription
filePathstringyesAbsolute path to the file on the remote host
contentstringyesContent to append
session_idstringnoSession ID

ssh_read

Read a file from the remote host with line numbers. Supports offset/limit for large files. Detects binary files and directories.

ParameterTypeRequiredDescription
filePathstringyesAbsolute path to the file on the remote host
offsetnumbernoLine number to start from (1-indexed, default: 1)
limitnumbernoMax lines to read (default: 2000)
session_idstringnoSession ID

ssh_edit

Edit a file on the remote host by replacing an exact string match. The oldString must be unique unless replaceAll is true.

ParameterTypeRequiredDescription
filePathstringyesAbsolute path to the file on the remote host
oldStringstringyesThe exact text to find and replace
newStringstringyesThe text to replace it with
replaceAllbooleannoReplace all occurrences (default: false)
session_idstringnoSession ID

Terminal Tools

ToolDescription
terminal_execSpawn a local bash session
terminal_writeSend input to a terminal session
terminal_readRead output from a terminal
terminal_listList all terminal sessions
terminal_killKill a terminal session
terminal_watchAdd/configure pattern watchers

terminal_exec

ParameterTypeRequiredDescription
commandstringyesBash command to run
backgroundbooleannoRun in background (default: false)
cwdstringnoWorking directory
envobjectnoEnvironment variables
descriptionstringnoHuman-readable label
watchersarraynoPattern watcher configs

Pattern Watchers

For background terminal sessions, you can configure watchers to detect specific patterns:

FieldTypeDescription
patternstringRegex pattern to match
labelstringWatcher label (e.g. error, ready)
prioritystringlow, medium, high
cooldownnumberMinimum ms between triggers

Default watchers for background sessions: error, ready, warning, test.

GitHub Tools

All GitHub tools require the GITHUB_TOKEN environment variable to be set.

Repository & Files

ToolDescription
github_repo_infoGet repository metadata (visibility, branch, language, etc.)
github_file_readRead a file or list a directory from a GitHub repo

Environments

ToolDescription
github_environment_listList repository environments (production, staging, etc.)

Variables & Secrets (Repo/Environment level)

ToolDescription
github_var_listList repo or environment variables
github_var_getGet a specific variable by name
github_var_setCreate or update a variable
github_var_deleteDelete a variable
github_secret_listList secrets (names only — values are never exposed)
github_secret_setCreate or update a secret (encrypted with libsodium sealed box)
github_secret_deleteDelete a secret

Variables & Secrets (Organization level)

ToolDescription
github_org_var_listList organization-level variables
github_org_secret_listList organization-level secrets (names only)

GitHub Actions / Workflows

ToolDescription
github_workflow_listList workflows in a repository
github_workflow_runsList workflow runs with filters (branch, status, conclusion, event)
github_workflow_run_getGet detailed info for a specific run
github_workflow_jobsList jobs and steps for a workflow run
github_workflow_run_logsDownload and read logs for a workflow run
github_workflow_job_logsDownload and read logs for a specific job
github_workflow_dispatchTrigger a workflow_dispatch event
github_workflow_cancelCancel a running workflow run
github_workflow_rerunRe-run a workflow (all jobs or failed only)
github_artifact_listList artifacts for a workflow run
github_artifact_downloadGet a temporary download URL for an artifact

Common Parameters

Most GitHub tools share these parameters:

ParameterTypeRequiredDescription
ownerstringyesRepository owner (user or organization)
repostringyesRepository name
environmentstringnoEnvironment name (for env-scoped variables/secrets)

Workflow-specific tools also accept:

ParameterTypeRequiredDescription
run_idnumberyes*Workflow run ID
job_idnumberyes*Job ID (from github_workflow_jobs)
workflow_idstring/numberyes*Workflow ID or filename (e.g. deploy.yml)
artifact_idnumberyes*Artifact ID (from github_artifact_list)

* Required for the respective tool only.

github_workflow_runs Filters

ParameterTypeDescription
workflow_idnumberFilter by workflow ID
branchstringFilter by branch name
statusstringqueued, in_progress, completed
conclusionstringsuccess, failure, cancelled, skipped, timed_out
eventstringpush, pull_request, workflow_dispatch, schedule
per_pagenumberResults per page (1-100, default 20)
pagenumberPage number

github_workflow_dispatch

ParameterTypeRequiredDescription
ownerstringyesRepository owner
repostringyesRepository name
workflow_idstringyesWorkflow ID or filename
refstringyesGit ref (branch, tag, or SHA)
inputsobjectnoWorkflow inputs as key-value pairs

github_workflow_rerun

ParameterTypeRequiredDescription
ownerstringyesRepository owner
repostringyesRepository name
run_idnumberyesWorkflow run ID to rerun
failed_onlybooleannoRerun only failed jobs (default: false)

Slash Commands

CommandDescription
/ops-dashboardOpen web dashboard in browser

How It Works

Architecture

The plugin uses three core components plus a GitHub client:

  • SessionManager — manages multiple SSH child processes. Each session spawns ssh -T with stdin/stdout piped, uses unique markers to delimit command output, has its own mutex for sequential execution, and runs periodic heartbeat checks (echo + marker).
  • TerminalManager — manages local bash processes with a ring buffer for output. Streams stdout/stderr, supports SIGINT/Ctrl+C, and auto-detects patterns via watchers.
  • GitHubClient — wraps the GitHub REST API (v2022-11-28) with pagination support, log unzip, and libsodium sealed box encryption for secrets.
  • Dashboard — HTTP server serving a web UI showing real-time status of all SSH and terminal sessions. Supports multi-instance aggregation — multiple opencode processes register with the primary dashboard and their sessions appear in a unified view.

Session Output Delimiting

SSH commands use unique markers (<<__OC_SSH_DONE__<id>>) to delimit output, allowing the reader to isolate command results from any background output (e.g. SSH Motd, cron jobs).

Auto-Flush & Session ID Resolution

When ssh_connect is called, dead sessions for the same host are automatically flushed so the base session ID is reused (no more servername_2, servername_3). Session IDs are derived from ~/.ssh/config aliases when possible — connecting to root@10.0.0.5 will produce session ID prod-web if that alias exists in your SSH config.

Heartbeat Monitoring

Every 30 seconds, each SSH session receives an echo probe. After 3 consecutive failures, the session is marked as errored. This detects disconnected sessions without relying on process exit. Dead sessions can be flushed with ssh_flush or reconnected with ssh_reconnect.

Secret Encryption

GitHub secrets are encrypted client-side using libsodium's sealed box via tweetnacl (NaCl crypto_box) and @noble/hashes (Blake2b for nonce derivation). The secret value is never sent in plaintext to the API.

System Prompt Injection

The plugin appends active session info to the system prompt, so the AI always knows which sessions exist and how to interact with them. Session context is also preserved during conversation compaction.

Bash Guard

A tool.execute.before hook detects when the AI tries to use the built-in bash tool for SSH-like operations (ssh, scp, sftp, rsync) and prepends a reminder to use the plugin's SSH tools instead.

Development

bun install
bun run build # Build to dist/
bun run typecheck # Type-check without emitting

License

MIT

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages