Skip to main content

A headless terminal layer: a persistent PTY + OSC 133 structure source, exposed to AI agents over MCP.

Project description

cleat

CI

A headless terminal layer for AI agents. cleat runs a persistent shell session behind a PTY, parses its byte stream for OSC 133 shell-integration marks, and exposes it to an agent over MCP as structured resultsstdout, real exit_code, files touched — instead of raw escape-code soup.

It is not a terminal emulator and not a modification to your terminal. It's a separate process that runs inside whatever terminal you already use, and it stays terminal-agnostic.

Why

When an agent drives a terminal, it normally sees a continuous byte river: prompt redraws, echoed keystrokes, color codes, and output, with no marker for where one command's output ends or whether it succeeded. Worse, when you scrape a PTY, the exit code isn't in the stream at all — the shell knows $? but never prints it.

cleat injects OSC 133 marks into the shells it spawns and parses them back out, so the agent gets:

{ "stdout": "...", "exit_code": 0, "completed": true }

…and the session is persistent: cd, export, activated venvs, and ssh sessions all carry across calls — something a fresh subprocess per command cannot do.

Install

Requires Python ≥3.10 on a POSIX system (Linux/macOS). With uv installed, register it with Claude Code:

claude mcp add cleat -- uvx --from git+https://github.com/sidyellur/cleat cleat

Or add it to a project's .mcp.json:

{
  "mcpServers": {
    "cleat": {
      "command": "uvx",
      "args": ["--from", "git+https://github.com/sidyellur/cleat", "cleat"]
    }
  }
}

For local development:

git clone https://github.com/sidyellur/cleat && cd cleat
python -m venv .venv && . .venv/bin/activate
pip install -e .
cleat            # runs the MCP server over stdio

Tools

Tool Returns Use for
run_command(command, timeout) {stdout, exit_code, completed} (+ files_changed if watching) normal commands — full, exact stdout
read_output(timeout) {output, exit_code, completed} watching a long-running / streaming command
read_screen() {screen, cursor} inspecting a full-screen TUI (vim, top, less)
send_keys(keys, enter) {screen, cursor, exit_code, completed} driving a REPL / TUI / prompt (control chars pass through: =Ctrl-C)
resize(cols, rows) {cols, rows} laying out a TUI for a given size
watch_files(path) {watch_root} enable per-command files_changed under path

completed: false means the program is still running or waiting for input (e.g. a REPL) — drive it with send_keys and poll with read_output.

How it works

agent ─(MCP)─ server.py ─ engine.py (persistent PTY, ptyprocess)
                            ├─ structure.py  → OSC 133 marks → {stdout, exit_code}
                            └─ pyte screen    → rendered view for REPLs/TUIs

The engine injects OSC 133 per shell without touching your real config: zsh via a temp $ZDOTDIR, bash via --rcfile + vendored bash-preexec, and fish ≥4 via its native shell integration (older fish is unsupported).

Caveats

  • POSIX only. Uses pty/termios; no Windows.
  • It gives the agent a real shell. Commands run with your user's privileges in a persistent session. Run it only where you'd let an agent run shell commands.
  • files_changed detects writes, not reads (create/modify/delete under the watched root). Read-tracking needs privileged syscall tracing.
  • bash: a command whose first token is a subshell (...) or brace group { ...; } emits no start mark; its exit code is recovered but stdout for that one command is not captured.
  • Full-screen TUIs: use read_screen (the rendered grid), not run_command.
  • Shells: zsh and bash are fully supported. fish requires ≥4 (native OSC 133) and is supported for command execution; interactive REPL/TUI driving is verified on zsh/bash.

License

MIT (see LICENSE). Vendors bash-preexec, also MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

cleat-0.1.0.tar.gz (31.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

cleat-0.1.0-py3-none-any.whl (31.2 kB view details)

Uploaded Python 3

File details

Details for the file cleat-0.1.0.tar.gz.

File metadata

  • Download URL: cleat-0.1.0.tar.gz
  • Upload date:
  • Size: 31.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cleat-0.1.0.tar.gz
Algorithm Hash digest
SHA256 4dfce3e2e4690f25846324b2b2bb062ccd52861099d18ecedee16b204f5191e5
MD5 8027f36ac82245389a0401b389247940
BLAKE2b-256 883b6613ed8c759f84da4925e2fa73d9a782f533c03366309895a6ef8568bf6f

See more details on using hashes here.

Provenance

The following attestation bundles were made for cleat-0.1.0.tar.gz:

Publisher: release.yml on sidyellur/cleat

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file cleat-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: cleat-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 31.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for cleat-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 8804a6074a413c7f053530ce92f15c41c6d4cc5633f37c8b1d409b63c7c27c3b
MD5 b9fc4c95aa13c8fcdd77e554d29859bc
BLAKE2b-256 0e0a8d582945c9f0836eb352f743d54fa067f3e43d74e76dde1032a983be04f6

See more details on using hashes here.

Provenance

The following attestation bundles were made for cleat-0.1.0-py3-none-any.whl:

Publisher: release.yml on sidyellur/cleat

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page