# yiwenlu66/PiloTY [Health: Active]

**Category:** 💻 Developer Tools  
**Repository:** https://github.com/yiwenlu66/PiloTY  
**GitHub Stars:** 44  
**Views:** 1  
**Installs:** 0  
**Upvotes:** 0  
**Directory Page:** https://allmcps.com/mcp/yiwenlu66-piloty

## Description
AI pilot for PTY operations enabling agents to control interactive terminals with stateful sessions, SSH connections, and background process management

## Claude Desktop Quick Installation
Install path detected from listing signals. Uses `uvx` (confidence: high):

```json
"mcpServers": {
  "piloty": {
    "command": "uvx",
    "args": ["--from"]
  }
}
```

## Documentation & README

<p align="center">
  <img src="https://raw.githubusercontent.com/yiwenlu66/PiloTY/HEAD/assets/logo.png" alt="PiloTY logo" width="220" />
</p>

# PiloTY

PiloTY (PTY for your AI Copilot) is an MCP server that gives an agent a persistent, interactive terminal.

If you have used Claude Code / Codex to run shell commands, you have probably hit the same wall: tool calls tend to be stateless. Each call starts "fresh", so environment variables disappear, interactive programs cannot be driven reliably, and long-running processes get cut off or orphaned while the agent is thinking.

PiloTY exists to make the agent's terminal behave more like a human's: start something in a real terminal, come back later, and keep going.

Warning: PiloTY exposes unrestricted terminal access. Treat it like giving the agent your keyboard.

## What it enables

- Long-running commands: builds, installs, migrations, test suites. Start once, check output later.
- Log monitoring: `tail -f`, `journalctl -f`, `kubectl logs -f`, CI logs, service restarts.
- "Vibe debugging": keep a REPL/debugger open while the agent reads code and tries ideas (`python`, `ipython`, `pdb`).
- Privileged operations: handle interactive password prompts (`sudo`, SSH passwords, key passphrases).
- SSH-based devops: keep a remote login session alive across tool calls; run remote commands in the same shell.
- Terminal UIs: `less`, `man`, `top`, `vim` can work, but cursor-heavy programs often require screen snapshots instead of plain text output.

## Quickstart

PiloTY is meant to be launched by an MCP client over stdio.

Add it to Codex CLI as an MCP server:

```bash
codex mcp add piloty -- uvx --from git+https://github.com/yiwenlu66/PiloTY.git piloty
```

If you prefer SSH-based Git fetch:

```bash
codex mcp add piloty -- uvx --from git+ssh://git@github.com/yiwenlu66/PiloTY.git piloty
```

If you already have a local clone:

```bash
codex mcp add piloty -- uv --directory /path/to/PiloTY run piloty
```

Run the server command directly (without adding it to an MCP client):

```bash
uvx --from git+https://github.com/yiwenlu66/PiloTY.git piloty
```

## Mental model

One session is one real interactive terminal that stays alive across tool calls.

- State persists: cwd, environment variables, foreground process, remote SSH connection, REPL/debugger state.
- PiloTY tracks both the raw output stream and a rendered screen/scrollback view.

PiloTY keeps two representations:

- `output`: incremental text stream (optionally ANSI-stripped)
- Rendered screen/scrollback: what a human would see in a terminal

Public MCP results separate call outcome from terminal interpretation:

- `outcome`: `success`, `deadline_exceeded`, `eof`, `error`, `invalid_session`, or `terminated`
- `terminal_state`: best-effort rendered-state classification after the call (`running`, `ready`, `password`, `confirm`, `repl`, `editor`, `pager`, `unknown`)

Sessions are addressed by a `session_id` string. Reusing the same id is what keeps state.

## Integration notes (for MCP integrators)

MCP does not expose a standard "client cwd" field, so the first step is always to create a session with an explicit working directory, then reuse the same `session_id` for subsequent calls.

Typical agent workflow:

- Create a session (explicit cwd) and reuse the same `session_id`.
- Use `send_line` to submit a newline-terminated command, `send_text` for raw bytes, and `send_control` / `send_signal` for interrupts.
- Use `wait_for_output` for temporal PTY output waiting, `wait_for_regex` for content-based waits, and `wait_for_shell_prompt` after `ssh` or similar login flows.
- Use `snapshot_screen` / `snapshot_scrollback` when layout matters. Snapshot tools are passive and do not ingest fresh PTY bytes.
- If prompt detection is wrong, configure a custom shell-prompt regex.
- Use `send_password` for secret entry; terminate the session when done.

For exact tool names, arguments, and return fields, use your MCP client's tool schema or read `piloty/mcp_server.py`.

## Limitations

- `deadline_s` is a wall-clock budget. On send/wait tools, it is not "process completion time".
- Drain-based tools (`send_line`, `send_text`, `send_control`, `send_password`, `send_signal`, `wait_for_output`) stop after the server quiescence policy (`PILOTY_QUIESCENCE_MS`, default `1000`) or when `deadline_s` expires.
- `wait_for_output` can return partial output with `outcome=deadline_exceeded` if output started but the PTY never went quiet before the deadline.
- `wait_for_regex` first checks already-rendered scrollback, then waits on new PTY bytes.
- `wait_for_shell_prompt` consumes PTY output while it waits and returns the consumed bytes in `output`.
- Terminal-state detection is best-effort and can be wrong (especially for custom prompts and cursor-heavy TUIs).
- Plain text output can be misleading for full-screen programs; use screen snapshots when layout matters.
- `send_password()` suppresses transcript logging and terminal echo for that send. It does not prevent other prompts/programs from echoing secrets later.
- Quiescence-based output collection can be confused by programs that print periodic noise. Tune with `PILOTY_QUIESCENCE_MS` (default `1000`).

## Logs

Each server instance writes session logs under `~/.piloty/`:

- `~/.piloty/servers/<server-instance-id>/sessions/<session-id>/transcript.log`: raw PTY bytes (combined stdout/stderr)
- `~/.piloty/servers/<server-instance-id>/sessions/<session-id>/commands.log`: inputs sent (best-effort)
- `~/.piloty/servers/<server-instance-id>/sessions/<session-id>/interaction.log`: inputs plus captured output (best-effort)
- `~/.piloty/servers/<server-instance-id>/sessions/<session-id>/session.json`: metadata snapshot
- `~/.piloty/active/<server-instance-id>/<session-id>`: symlink to the current session directory (when symlinks are supported)

Server logs default to `/tmp/piloty.log`.

`tools/session_viewer.py` can inspect sessions:

```bash
python tools/session_viewer.py list
python tools/session_viewer.py info <server-instance-id>/<session-id>
python tools/session_viewer.py tail -f <server-instance-id>/<session-id>
```

## Development

Repository layout:

```
piloty/
  core.py        # PTY + terminal renderer + session logs
  mcp_server.py  # MCP tools + state inference
tests/
tools/
  pty_playground.py
  session_viewer.py
```

Run tests:

```bash
python -m pytest -q
```

License: Apache License 2.0, see `LICENSE`.

