parkerhancock/dev-terminal

Persistent terminal (PTY) session management via HTTP API for AI assistants

0 stars0 forksUpdated Jan 7, 2026
npx skills add parkerhancock/dev-terminal

README

dev-terminal - Terminal automation for AI assistants

Terminal automation for AI assistants. Inspired by dev-browser.

Key features:

  • Persistent sessions - Create once, interact across multiple scripts
  • SSH support - Connect to remote servers with the same API
  • Headed mode - Browser UI to watch AI actions in real-time
  • Full PTY support - Run interactive TUI apps (htop, vim, ncurses, etc.)
  • LLM-friendly snapshots - Text, ANSI, or SVG output for AI analysis

Installation

Claude Code Plugin

/install parkerhancock/dev-terminal

Restart Claude Code after installation.

Manual / Standalone

Requires Node.js v18+.

git clone https://github.com/parkerhancock/dev-terminal
cd dev-terminal && npm install

Quick Start

Start the server:

./server.sh              # Headless
./server.sh --headed     # With browser UI

Create and interact with terminals:

import { connect, sleep } from "./src/client.js";

const client = await connect();
const term = await client.terminal("my-app");

await term.writeLine("ls -la");
await term.waitForText("total");

const snap = await term.snapshot();
console.log(snap.text);

await term.key("ctrl+c");
client.disconnect();

Client API

Connection

import { connect } from "./src/client.js";

const client = await connect(); // Default: http://localhost:9333
const client = await connect("http://..."); // Custom server URL

Client Methods

// Create or reconnect to a named terminal
const term = await client.terminal("name");
const term = await client.terminal("name", options);

// List all terminal names
const names = await client.list();

// Close/kill a terminal
await client.close("name");

// Get server info
const info = await client.info();

// Disconnect (terminals keep running)
client.disconnect();

Terminal Options

const term = await client.terminal("name", {
  // Local terminal options
  command: "bash", // Shell or command to run
  args: ["-l"], // Arguments (default: login shell)
  cols: 120, // Width in columns (default: 120)
  rows: 40, // Height in rows (default: 40)
  cwd: "/path/to/dir", // Working directory
  env: { MY_VAR: "value" }, // Additional environment variables

  // SSH options (for remote terminals)
  ssh: {
    host: "example.com", // Required
    username: "deploy", // Required
    port: 22, // Default: 22
    password: "...", // Password auth
    privateKey: "...", // Key content (not path)
    passphrase: "...", // For encrypted keys
    agent: process.env.SSH_AUTH_SOCK, // SSH agent
  },
});

Terminal Methods

// Write raw data
await term.write("hello");

// Send a line (adds Enter)
await term.writeLine("ls -la");

// Send special keys
await term.key("enter");
await term.key("ctrl+c");
await term.key("up");

// Get screen snapshot
const snap = await term.snapshot();
console.log(snap.text); // Plain text (ANSI stripped)
console.log(snap.raw); // Raw output with ANSI codes
console.log(snap.lines); // Array of lines
console.log(snap.alive); // Process still running?
console.log(snap.exitCode); // Exit code if exited

// Get SVG rendering
const snap = await term.snapshot({ format: "svg" });
console.log(snap.svg);

// Resize terminal
await term.resize(80, 24);

// Clear output buffer
await term.clear();

// Wait for text to appear
const found = await term.waitForText("Ready", { timeout: 5000 });

// Wait for process to exit
const code = await term.waitForExit({ timeout: 10000 });

Special Keys

CategoryKeys
Arrowsup, down, left, right
Controlenter, tab, escape, backspace, delete
Ctrl+Xctrl+c, ctrl+d, ctrl+z, ctrl+l, ctrl+a, ctrl+e, ctrl+k, ctrl+u, ctrl+w, ctrl+r
Functionf1 - f12
Navigationhome, end, pageup, pagedown, insert

SSH Remote Terminals

Connect to remote servers via SSH. The API is identical to local terminals.

import * as fs from "fs";
import * as os from "os";
import * as path from "path";

// Private key authentication
const term = await client.terminal("server1", {
  ssh: {
    host: "192.168.1.100",
    username: "deploy",
    privateKey: fs.readFileSync(path.join(os.homedir(), ".ssh/id_rsa"), "utf8"),
  },
});

// Password authentication
con

...
Read full README

Publisher

parkerhancockparkerhancock

Statistics

Stars0
Forks0
Open Issues0
LicenseMIT License
CreatedJan 6, 2026