gpty-cli
CLI for controlling the gpty terminal workspace over JSON-RPC IPC. Connects to a running gpty GUI instance; only new-pane and layout load may start one on demand, and --no-daemon refuses even those (a query must not open a workspace). Pane types are validated client-side with “did you mean?” suggestions before any IPC round-trip.
Getting it
Release bundles ship this CLI beside the GUI - gpty-gui on Linux and Windows, gPTY.app on macOS - and the CLI starts that GUI on demand, so a downloaded bundle needs no toolchain. From a source checkout, cargo build -p gpty (or cargo build --workspace) puts the binary in target/debug/gpty.
Role in the Workspace
| Crate | Role | Depends On |
|---|---|---|
gpty-core |
Engine library (PTY, ANSI, grid, concepts) | - |
gpty-ipc |
IPC transport + protocol | gpty-core |
gpty-gdext |
Godot 4 GDExtension bridge + IPC server | gpty-core, gpty-ipc |
gpty-cli |
CLI for workspace control | gpty-ipc |
Usage
# Open a new terminal pane
gpty new-pane --type terminal
# Open a new pane with a custom command and focus
gpty new-pane -t terminal -c "htop" -f
# List all active panes
gpty list-panes
# Close a pane
gpty kill-pane T1
# Focus a pane
gpty focus-pane T2
# Send text to a terminal pane
gpty inject T1 --text "ls -la"
# Read a pane's output (screen + scrollback)
gpty pane-read T1 --lines 200
# Pane status; no pane = every pane's status
gpty pane-status T1
gpty pane-status
# Run a command in a new pane
gpty pane-run --command "cargo test"
# Wait for output matching a regex (Rust syntax, up to 60 s)
gpty pane-wait T1 --pattern "tests passed" --timeout-ms 30000
# Declare this pane's agent state (run inside the pane; display only)
gpty state working
# Inject into every pane carrying a tag
gpty new-pane --tags ci
gpty broadcast --tags ci --text "make test"
# Search a Markdown vault and read one of its notes (agent access)
gpty vault search ~/notes "ownership"
gpty vault read ~/notes notes/idea.md
# Curate a link's display weight (the wiki pane's graph; needs a running GUI)
gpty vault weight ~/notes notes/idea.md notes/spec.md --weight 40
gpty vault weight ~/notes notes/idea.md notes/spec.md --clear
# Manage concept triggers
gpty concept list
gpty concept toggle cat_command
# Print the bundled agent skill (for coding agents inside a pane)
gpty --skill
# Output JSON Schema for AI tool integration
gpty schema
gpty schema --format mcp
# Run as MCP server over stdio
gpty mcp
# Manage the GUI daemon
gpty daemon start
gpty daemon status
gpty daemon stop
# Save, load, and list workspace layouts
gpty layout save mysetup
gpty layout load mysetup
gpty layout list
# Install, manage, and run plugins
gpty plugin install godot-pty/gpty-omp
gpty plugin list
gpty plugin run godot-pty/gpty-omp run-tests
# Check a manifest locally (the plugin-authoring loop and a plugin repo's CI)
gpty plugin validate ./gpty-plugin.toml
gpty plugin validate ./gpty-plugin.toml --json
# Machine-readable JSON output
gpty list-panes --json
# Print version info
gpty versionSubcommands
| Command | Description |
|---|---|
new-pane |
Open a new pane (-t, --pane-type terminal/code_viewer/file_tree/inspector/reasoning/cli_view/wiki/media, -c, --command command, --arg program argument for cli_view (repeatable), -s, --split split, -f, --focus focus, --tags broadcast tags). observer is a deprecated alias for inspector. |
list-panes |
List all active panes with stable ids, labels, types, and positions |
kill-pane |
Close a pane by id or "active" |
focus-pane |
Focus a pane by id |
inject |
Send text to a terminal pane by id |
pane-read |
Read a pane’s plain-text output (screen + scrollback, --lines 1–2000) |
pane-status |
Status primitives for a pane (pid, running, exit_code, exit_reason, idle_ms); no argument answers {panes: [{pane_id, label, type, status}]} for every pane, with status: null for panes that have no status primitives (non-terminals) |
pane-run |
Run a command in a new terminal pane (--command) |
pane-wait |
Wait for a pane’s output to match a regex (--pattern, --timeout-ms 100–60000) |
state |
Declare the state of the pane the command runs in (idle, working, needs-attention, completed, failed). Needs the credentials a pane injects (GPTY_EVENT_*), submits over the event socket, and is not an MCP tool |
broadcast |
Inject text into every pane carrying one of the given --tags |
vault |
Read-only knowledge-base access: search <vault_path> <pattern> (absolute vault directory; re-indexes changed notes first, --limit 1–500) answers {results, total, truncated}, read <vault_path> <path> answers the note document. Neither writes to the vault |
concept |
List or toggle concept triggers (list, toggle <name>) |
schema |
Output JSON Schema describing all commands (--format mcp for MCP manifest) |
mcp |
Run as MCP server over stdio (for AI tool integration) |
daemon |
Manage the GUI: start, stop, status |
layout |
Layout management: save <name>, load <name>, list |
plugin |
Install, manage, and run plugins: install <owner>/<repo>[@ref] (git clone, manifest validation, GUI review dialog - a plugin’s actions run as you, so a human must accept), list, enable/disable <id> and uninstall <id> (each notifies a running GUI so its profile list drops or picks up the plugin’s layouts without a restart; with no GUI the notice is dropped and the next launch reads the store), logs <id>, run <id> <action> (spawns the action’s CLI command through GPTY_BIN_PATH), validate <path> (check a gpty-plugin.toml file or plugin directory with the install validator - the local authoring loop, no GUI and no network; --json prints {"ok":…} and exits 1 on rejection). Not an MCP tool: install waits on the review dialog, the admin actions touch local state |
version |
Print version info |
Global Flags
| Flag | Description |
|---|---|
--skill |
Print the bundled agent skill (SKILL.md) and exit |
--json |
Machine-readable JSON output. A failed command still exits 1, with the JSON-RPC error envelope on stdout (error.data.code is the stable discriminator) |
--socket <path> |
Override IPC socket path |
--timeout <ms> |
Connection timeout in milliseconds (default 5000) |
--no-daemon |
Don’t auto-spawn the GUI if not running |
-v, --verbose |
Verbose output to stderr |
Key Dependencies
| Crate | Version | Role |
|---|---|---|
gpty-ipc |
path | IPC transport + client |
gpty-core |
path | Concept engine (manifest validation round-trips) |
clap |
4 | CLI argument parsing |
anyhow |
1 | Error handling |
serde / serde_json |
1 | JSON store + output |
toml |
0.8 | gpty-plugin.toml parsing |
dirs |
6 | Platform directories (GUI binary discovery) |
tokio |
1 | Async runtime |
MCP registry
The repository’s server.json declares this crate as the
io.github.godot-pty/gpty server in the
official MCP registry. Before it
publishes, the registry verifies that the crate belongs to that entry by
looking for this exact line in the crate README - crates.io strips HTML
comments, so the token is plain text rather than a comment:
MCP Registry name: mcp-name: io.github.godot-pty/gpty