opencode-pty
v0.1.0
Published
OpenCode plugin for interactive PTY management - run background processes, send input, read output with regex filtering
Maintainers
Readme
opencode-pty
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.
Why?
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.
Features
- 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
Setup
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.
Updating
[!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
opencodeTools Provided
| 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 |
Usage Examples
Start a dev server
pty_spawn: command="npm", args=["run", "dev"], title="Dev Server"
→ Returns: pty_a1b2c3d4Check server output
pty_read: id="pty_a1b2c3d4", limit=50
→ Shows last 50 lines of outputFilter for errors
pty_read: id="pty_a1b2c3d4", pattern="error|ERROR", ignoreCase=true
→ Shows only lines matching the patternSend Ctrl+C to stop
pty_write: id="pty_a1b2c3d4", data="\x03"
→ Sends interrupt signalKill and cleanup
pty_kill: id="pty_a1b2c3d4", cleanup=true
→ Terminates process and frees bufferConfiguration
Environment Variables
| Variable | Default | Description |
|----------|---------|-------------|
| PTY_MAX_BUFFER_LINES | 50000 | Maximum lines to keep in output buffer per session |
Permissions
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.
Example: Allow specific commands for PTY
{
"$schema": "https://opencode.ai/config.json",
"permission": {
"bash": {
"npm run dev": "allow",
"npm run build": "allow",
"npm test *": "allow",
"cargo *": "allow",
"python *": "allow"
}
}
}How It Works
- 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
Session Lifecycle
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.
Local Development
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"]
}License
MIT
Contributing
Contributions are welcome! Please open an issue or submit a PR.
