A plugin for OpenCode that provides interactive PTY (pseudo-terminal) management, enabling the AI agent to run background processes, send interactive input, and read output on demand.
OpenCode's built-in bash tool runs commands synchronously—the agent waits for completion. This works for quick commands, but not for:
- Dev servers (
npm run dev,cargo watch) - Watch modes (
npm test -- --watch) - Long-running processes (database servers, tunnels)
- Interactive programs (REPLs, prompts)
This plugin gives the agent full control over multiple terminal sessions, like tabs in a terminal app.
- Background Execution: Spawn processes that run independently
- Multiple Sessions: Manage multiple PTYs simultaneously
- Interactive Input: Send keystrokes, Ctrl+C, arrow keys, etc.
- Output Buffer: Read output anytime with pagination (offset/limit)
- Pattern Filtering: Search output using regex (like
grep) - Permission Support: Respects OpenCode's bash permission settings
- Session Lifecycle: Sessions persist until explicitly killed
- Auto-cleanup: PTYs are cleaned up when OpenCode sessions end
Add the plugin to your OpenCode config:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["opencode-pty"]
}That's it. OpenCode will automatically install the plugin on next run.
Warning
OpenCode does NOT auto-update plugins.
To get the latest version, clear the cached plugin and let OpenCode reinstall it:
rm -rf ~/.cache/opencode/node_modules/opencode-pty
opencode| Tool | Description |
|---|---|
pty_spawn |
Create a new PTY session (command, args, workdir, env, title) |
pty_write |
Send input to a PTY (text, escape sequences like \x03 for Ctrl+C) |
pty_read |
Read output buffer with pagination and optional regex filtering |
pty_list |
List all PTY sessions with status, PID, line count |
pty_kill |
Terminate a PTY, optionally cleanup the buffer |
pty_spawn: command="npm", args=["run", "dev"], title="Dev Server"
→ Returns: pty_a1b2c3d4
pty_read: id="pty_a1b2c3d4", limit=50
→ Shows last 50 lines of output
pty_read: id="pty_a1b2c3d4", pattern="error|ERROR", ignoreCase=true
→ Shows only lines matching the pattern
pty_write: id="pty_a1b2c3d4", data="\x03"
→ Sends interrupt signal
pty_kill: id="pty_a1b2c3d4", cleanup=true
→ Terminates process and frees buffer
| Variable | Default | Description |
|---|---|---|
PTY_MAX_BUFFER_LINES |
50000 |
Maximum lines to keep in output buffer per session |
This plugin respects OpenCode's permission settings for the bash tool. Commands spawned via pty_spawn are checked against your permission.bash configuration.
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"bash": {
"npm *": "allow",
"git push": "deny",
"terraform *": "deny"
}
}
}Important
Limitations compared to built-in bash tool:
-
"ask" permissions are treated as "deny": Since plugins cannot trigger OpenCode's permission prompt UI, commands matching an "ask" pattern will be denied. A toast notification will inform you when this happens. Configure explicit "allow" or "deny" for commands you want to use with PTY.
-
"external_directory" with "ask" is treated as "allow": When the working directory is outside the project and
permission.external_directoryis set to "ask", this plugin allows it (with a log message). Set to "deny" explicitly if you want to block external directories.
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"bash": {
"npm run dev": "allow",
"npm run build": "allow",
"npm test *": "allow",
"cargo *": "allow",
"python *": "allow"
}
}
}- Spawn: Creates a PTY using bun-pty, runs command in background
- Buffer: Output is captured into a rolling line buffer (ring buffer)
- Read: Agent can read buffer anytime with offset/limit pagination
- Filter: Optional regex pattern filters lines before pagination
- Write: Agent can send any input including escape sequences
- Lifecycle: Sessions track status (running/exited/killed), persist until cleanup
spawn → running → [exited | killed]
↓
(stays in list until cleanup=true)
Sessions remain in the list after exit so the agent can:
- Read final output
- Check exit code
- Compare logs between runs
Use pty_kill with cleanup=true to remove completely.
git clone https://github.com/shekohex/opencode-pty.git
cd opencode-pty
bun install
bun run tsc --noEmit # Type checkTo load a local checkout in OpenCode:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["file:///absolute/path/to/opencode-pty"]
}MIT
Contributions are welcome! Please open an issue or submit a PR.