Skip to main content

Porterminal - Vibe Code From Anywhere

PyPI Python Downloads License CI

Hand a computer to an agent, full control, and watch it.
One command, one URL. (Also a slick terminal for your own phone.)

1. uvx ptn
2. Hand the URL to an AI agent, or scan the QR yourself
3. Watch it work in any browser, and take over anytime

Porterminal demo

Why

I need something dangerously easy to remote access a computer.

ngrok requires registration and the free tier sucks. Cloudflare Tunnel is excellent plumbing, but by itself it only gives you a tunnel, not a phone-friendly terminal. Tailscale is great when you own both ends, but it still means joining devices to a private network. Termius requires complicated setup: port forwarding, firewall rules, key management...

So I built something simpler: run a command, scan a QR, start typing.

Then it clicked: the same trick (one command, one URL) is the easiest way to give an AI agent a real terminal on any computer. No MCP server to write, no SSH keys, no Docker, no config. Run uvx ptn, hand over the URL, and the agent runs commands, reads the screen, and answers prompts on that machine. And because it's a web terminal, you can open the same session in any browser to watch it work live, or grab the keyboard and take over.

Features

  • Hand a computer to an agent, full control, and watch it - Give an AI agent the URL and it gets a real terminal on the machine via MCP or plain REST. Open the same session in any browser to watch it work live, and grab the keyboard whenever you want. No keys, no Docker. The agent learns how from <url>/llms.txt and <url>/.well-known/mcp.json. See Agent access.
  • One command, instant access - uvx ptn and you (or an agent) get a real terminal on this machine. No SSH, no port forwarding, no config files. Cloudflare tunnel + QR code.
  • Actually usable on mobile - Touch-optimized with momentum scrolling, pinch-to-zoom, swipe gestures, and modifier keys (Ctrl, Alt).
  • Full terminal apps - vim, htop, less, tmux all work correctly with proper alt-screen buffer handling.
  • Persistent multi-tab sessions - Sessions survive disconnects. Close the browser, switch networks, reconnect from another device, and your shell and running processes are still there. You and an agent can share one session: watch it work, or take over.
  • Cross-platform - Windows (PowerShell, CMD, WSL), Linux/macOS (Bash, Zsh, Fish, Nushell, and any shell via $SHELL). Auto-detects your shells.
  • Hard to guess by default - Every launch adds an independent 128-bit random access path. The bare tunnel hostname and every wrong path return 404. The URL is hidden on screen, but the QR contains the complete credential, so keep both private. Press c to copy agent instructions and URL, or u to copy the URL only.

Install

Method Install Update
uvx (no install) uvx ptn uvx ptn@latest
uv tool uv tool install ptn uv tool upgrade ptn
pipx pipx install ptn pipx upgrade ptn
pip pip install ptn pip install -U ptn

One-line install (uv + ptn):

OS Command
Windows powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/lyehe/porterminal/master/install.ps1 | iex"
macOS/Linux curl -LsSf https://raw.githubusercontent.com/lyehe/porterminal/master/install.sh | sh

Requires Python 3.12+ and cloudflared (auto-installed if missing).

Usage

ptn                    # Start in current directory
ptn ~/projects/myapp   # Start in specific folder
Flag Description
-n, --no-tunnel Local network only (no Cloudflare tunnel)
--mcp-only MCP shell control without a QR code, browser terminal, or REST API
-p, --password Prompt for password to protect this session
-sp, --save-password Save or clear password in config
-tp, --toggle-password Set password requirement (on/off/toggle)
-v, --verbose Show detailed startup logs
-i, --init Create .ptn/ptn.yaml with auto-discovered project scripts as buttons
-if, --init-from URL/PATH Create .ptn/ptn.yaml from a URL or local file
-c, --compose Enable compose mode by default
-k, --keep-qr Keep the QR code visible after the first connection
-u, --check-update Check if a newer version is available
-V, --version Show version

While running: with a tunnel active, the connection URL is hidden on screen for privacy. Press c to copy agent instructions and URL, including /mcp, /api/agent/run, and /llms.txt; press u to copy the URL only; or scan the QR to connect. Ctrl+C stops the server.

Agent access (MCP + REST)

For shell control entirely behind the scenes, run ptn --mcp-only. The local terminal UI stays open: press c to copy the agent prompt and MCP address, or u to copy just the MCP address. These keys also work with --no-tunnel. Connect your MCP client to the generated <url>/mcp endpoint. This mode shows no QR code and disables the web terminal, browser WebSockets, and REST API, so commands cannot be watched or entered through the browser. MCP discovery and /llms.txt remain available. The complete MCP URL still grants shell control of the computer.

The same URL also works for AI agents. MCP-capable clients can use <url>/mcp (Streamable HTTP) for native typed tools. Agents that cannot register an MCP server can use the REST fallback at <url>/api/agent/run with ordinary HTTP requests. Either path creates a persistent agent shell, shown as a 🤖 tab you can watch and take over from your phone.

Hand the agent the complete generated URL, including its access code. MCP clients can auto-discover the server from <url>/.well-known/mcp.json (the MCP server.json descriptor), and there's a human/agent-readable <url>/llms.txt with usage. The base page also includes accessibility-visible hints for browser-driving agents, while the human UI stays compact. Example client config:

{
  "mcpServers": {
    "porterminal": { "url": "https://<your-tunnel>.trycloudflare.com/<access-code>/mcp" }
  }
}

MCP tools: run_command (clean output + exit code), read_screen, send_keys, send_signal (Ctrl-C / EOF).

REST fallback:

curl -s -X POST https://<your-tunnel>.trycloudflare.com/<access-code>/api/agent/run \
  -H "content-type: application/json" \
  -d '{"command":"echo hello","timeout":30}'

The response includes a session_id; reuse it with <url>/api/agent/screen, <url>/api/agent/keys, <url>/api/agent/signal, and DELETE <url>/api/agent/session.

When you open Porterminal on your phone, the top-right copy button copies the same agent-ready share text. Browser-only agents also get a fallback on the base page: a DOM-readable Terminal screen mirror and a clearly labeled Terminal input.

Security: <url> means the complete generated URL, including its random access code. The bare tunnel hostname exposes nothing, but anyone (or any agent) with the complete URL gets full, non-elevated shell access. See docs/agent-access.md.

Mobile Gestures

Gesture Action
Tap Focus terminal, clear selection
Long-press Start text selection
Double-tap Select word
Swipe left/right Arrow keys (← →)
Scroll Momentum scrolling with physics
Pinch Zoom text (10-24px)

Modifier keys (Ctrl, Alt, Shift): Tap once for sticky (one keystroke), double-tap for lock.

Compose mode (▤ button): Toggle a text input field where you can type or dictate, edit your text with full mobile editing features (autocorrect, suggestions, cursor positioning), then send to terminal. Useful for longer commands or voice input.

Configuration

Run ptn --init to create a starter config. It auto-discovers project scripts from package.json, pyproject.toml, or Makefile and adds them as buttons:

ptn -i
# Created: .ptn/ptn.yaml
# Discovered 3 project script(s): build, dev, test

Or create ptn.yaml manually:

# Terminal settings
terminal:
  default_shell: nu              # Default shell ID
  shells:                        # Custom shell definitions
    - id: nu
      name: Nushell
      command: nu
      args: []

# Custom buttons (appear in toolbar)
# row: 1 = default row, 2+ = additional rows
buttons:
  - label: "claude"
    send:
      - "claude"
      - 100        # delay in ms
      - "\r"
  - label: "build"
    send: "npm run build\r"
    row: 2         # second button row

# Update checker settings
update:
  notify_on_startup: true   # Show update notification
  check_interval: 86400     # Seconds between checks (default: 24h)

# Security settings
security:
  require_password: true    # Always require password at startup
  password_hash: ""         # Saved password hash (use ptn -sp to set)
  max_auth_attempts: 5      # Max failed attempts before disconnect

Config is searched in order: $PORTERMINAL_CONFIG_PATH, ./ptn.yaml, ./.ptn/ptn.yaml, ~/.ptn/ptn.yaml.

Security

Every launch creates a new 128-bit random path such as https://<tunnel>.trycloudflare.com/<access-code>/. All browser, WebSocket, MCP, REST, health, and static routes require that exact prefix; the bare host and wrong paths return 404. This makes brute-forcing a discovered tunnel hostname impractical.

The complete generated URL is still a bearer credential: anyone who gets it has shell access. Restart Porterminal to rotate the code if it leaks. The optional password adds authentication to browser WebSockets, but MCP and REST continue to trust the complete URL so agents can use the one-link workflow.

A browser remembers a successful password in plaintext storage scoped to that complete launch URL. Saving a password for a newer launch on the same origin retires older Porterminal password entries; clearing or rejecting a remembered password removes them all without touching other browser storage. Consequently, concurrent launches on the same origin may prompt again, while an already authenticated connection remains connected.

From the UI: Open Settings (gear icon) and use the Security section to set/change password and toggle password requirement. Changes require server restart.

From CLI:

# One-time password (prompt each session)
ptn -p

# Save password to config (no prompt needed)
ptn -sp
# Password: ****
# Confirm password: ****

# Clear saved password (enter empty password)
ptn -sp
# Password: [press Enter]

# Set or toggle password requirement
ptn -tp          # Toggle on/off

See docs/security.md for details.

Troubleshooting

Connection fails? Use the complete generated URL, including its access code. Cloudflare tunnel issues can also be resolved by restarting the server (Ctrl+C, then ptn) for a fresh tunnel and access path.

uvx ptn still runs an older version? An existing uv tool installation can take precedence. Run uv tool upgrade ptn, or bypass installed tools with uvx --isolated ptn@latest.

Shell not detected? Set your $SHELL environment variable or configure shells in ptn.yaml.

Contributing

This project does not accept external contributions (pull requests or code changes) for security reasons (see CONTRIBUTING.md). You're welcome to fork and run your own copy under AGPL-3.0.

Run from source:

git clone https://github.com/lyehe/porterminal
cd porterminal
uv sync --frozen
uv run --frozen ptn

License

AGPL-3.0

Metadata

Release files for ptn 1.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ptn 1.2.0
File Size Uploaded
ptn-1.2.0.tar.gz 242.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for ptn 1.2.0
File Interpreter ABI Platform
ptn-1.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 521.3 kB

Release files / ptn-1.2.0.tar.gz

Download URL ptn-1.2.0.tar.gz
Size 242.4 kB
Tags Source
SHA-256 checksum
How to use checksums
f2b1646389169250a7574c1822c0cc78ecaa778d7f3a7edcf22753145005e2ec
BLAKE2b-256 checksum
How to use checksums
a753ff417c094c8ea1d24e42829ea2f172cbd68ef3d952f6e3a83065607dd998
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

Release files / ptn-1.2.0-py3-none-any.whl

Download URL ptn-1.2.0-py3-none-any.whl
Size 278.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b34afba2af46a7f13cbc8ef4d56b519d9b1fc3bc6665f79bd9a7eb7b7bd34f5d
BLAKE2b-256 checksum
How to use checksums
c2aa05fb2a014e8815657187b28e6ed062ddb51c5e3ffd39e8a61a94570f10aa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 13, 2026.

Transparency log

Release history Release notifications | RSS feed

1.2.2

2 release files

1.2.1

2 release files

This release

1.2.0 This release

2 release files

1.1.1

2 release files

1.1.0

2 release files

1.0.7

2 release files

1.0.6

2 release files

1.0.5

2 release files

1.0.4

2 release files

1.0.3

2 release files

1.0.2

2 release files

1.0.1

2 release files

1.0.0

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.6

2 release files

0.5.5

2 release files

0.5.4

2 release files

0.5.3

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.4.7

2 release files

0.4.6

2 release files

0.4.5

2 release files

0.4.4

2 release files

0.4.3

2 release files

0.4.2

2 release files

0.4.1

2 release files

0.4.0

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.7

2 release files

0.2.6

2 release files

0.2.5

2 release files

0.2.4

2 release files

0.2.3

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page