Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.declaw.ai/llms.txt

Use this file to discover all available pages before exploring further.

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

pip install declaw anthropic
export ANTHROPIC_API_KEY="your-anthropic-key"
This example requires a real TTY (sys.stdin.isatty()). It will not work inside a Jupyter notebook or piped stdin.

Tools

ToolDescription
shell(cmd)Non-interactive command. Returns stdout/stderr/exit_code.
pty_interactive(cmd, reason)Interactive command. Prompts user y/n, then forwards local TTY to sandbox.
read_file(path)Read a file from the sandbox.
write_file(path, content)Write a file to the sandbox.
ls(path)List a sandbox directory.

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.
handle = sbx.pty.create(size=size, on_data=tee, timeout=1800)
signal.signal(signal.SIGWINCH,
              lambda *_: handle.resize(_local_term_size()))
tty.setraw(fd)
while True:
    data = os.read(fd, 1024)
    if data == b"\x04":
        handle.send_stdin(b"exit\n")
        break
    handle.send_stdin(data)

Running it

export DECLAW_API_KEY="your-api-key"
export DECLAW_DOMAIN="api.declaw.ai"
export ANTHROPIC_API_KEY="your-anthropic-key"
python cookbook/examples/agent-with-pty/main.py
You are prompted for a goal. Try something like:
> install the gh CLI and log me in to my GitHub account
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.