Skip to main content
A Cursor-style coding agent backed by Claude and a persistent declaw sandbox. The agent has five tools for everyday work (shell, read_file, write_file, ls) plus one special tool: pty_interactive, which hands your local TTY to the sandbox when the agent decides it needs human input.

Use case

Sometimes an agent hits a wall that requires a human: an OAuth login, a sudo password, a TUI license agreement, or a vim session. Instead of failing or asking you to switch to another terminal, the agent calls pty_interactive with a reason, you approve with y/n, and your terminal drops into a live shell inside the sandbox. When the interactive command finishes, control returns to the agent loop.

What you’ll learn

  • Defining tool schemas for the Anthropic Messages API
  • Running a multi-turn agent loop with tool-use stop reason
  • PTY handoff pattern: raw-mode local TTY forwarding with SIGWINCH
  • Capturing PTY output in a thread-safe bytearray and feeding it back to the agent
  • Trimming captured output to keep the agent’s context bounded

Prerequisites

This example requires a real TTY (sys.stdin.isatty()). It will not work inside a Jupyter notebook or piped stdin.

Tools

How PTY handoff works

When the agent calls pty_interactive:
  1. The script prints the agent’s reason and the command in a box and asks Proceed? [y/N].
  2. On y, sbx.pty.create() opens a PTY session. The local TTY switches to raw mode (tty.setraw), and a SIGWINCH handler propagates window resizes.
  3. Every local keystroke is forwarded via handle.send_stdin(). Every byte from the sandbox streams to stdout via on_data and is also captured in a bytearray.
  4. Ctrl-D sends exit\n to close the remote shell cleanly.
  5. The captured output (trimmed to ~4 KB) is returned as the tool result so the agent knows what happened during the session.

Running it

You are prompted for a goal. Try something like:
The agent will use shell to install gh, then call pty_interactive(cmd="gh auth login", reason="GitHub OAuth flow requires browser interaction"). You approve, complete the login in the live terminal, press Ctrl-D, and the agent continues.

Full source

See cookbook/examples/agent-with-pty/main.py in the repo.