# talonbox

[![PyPI](https://img.shields.io/pypi/v/talonbox.svg)](https://pypi.org/project/talonbox/)
[![Changelog](https://img.shields.io/github/v/release/wolfmanstout/talonbox?include_prereleases&label=changelog)](https://github.com/wolfmanstout/talonbox/releases)
[![Tests](https://github.com/wolfmanstout/talonbox/actions/workflows/test.yml/badge.svg)](https://github.com/wolfmanstout/talonbox/actions/workflows/test.yml)
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/wolfmanstout/talonbox/blob/main/LICENSE)

A local sandbox for testing Talon scripts. Inspired by playwright-cli.

`talonbox` is an independent, community-driven sandbox for [Talon Voice](https://talonvoice.com/) development. It gives humans and coding agents a safer place to stage Talon changes inside a local Lume VM before touching the host machine.

## Installation

Install with `uv`:

```bash
uv tool install talonbox
```

You can also install it with `pip` or `pipx`:

```bash
pip install talonbox
pipx install talonbox
```

## Usage

`talonbox` provides a small set of primitives for testing Talon scripts in a VM-backed sandbox.

For top-level help, run:

```bash
talonbox --help
```

Typical workflow:

```bash
talonbox start
talonbox rsync -av ~/.talon/user/ guest:/Users/lume/.talon/user/
talonbox mimic "focus chrome"
talonbox screenshot /tmp/talon.png
talonbox stop
```

For a first-pass diagnostic when the setup seems broken, run:

```bash
talonbox smoke-test
```

`smoke-test` is a mutating end-to-end sanity check. It may stop a running VM, pushes a temporary Talon command bundle, runs `mimic`, captures a screenshot, keeps debugging artifacts under `/tmp`, and leaves the VM stopped when it finishes.

General guest access:

```bash
talonbox exec -- whoami
talonbox scp guest:/tmp/out.png /tmp/out.png
printf 'print(1 + 1)\n' | talonbox repl
```

Host-side outputs from `rsync`, `scp`, and `screenshot` are intentionally restricted to `/tmp`.
This is a caller-facing safety guarantee: invoking `talonbox` must not let humans or coding agents cause arbitrary host writes outside `/tmp`.
On macOS, `/tmp` may resolve to `/private/tmp`; that canonical temp root is still allowed, but symlink escapes rooted under it are rejected.
For `rsync` and `scp`, talonbox keeps the explicit `guest:/...` transfer rules and runs the underlying transfer process inside the macOS sandbox, so extra host-side writes outside that boundary fail with an obvious permission error instead of relying on a large flag denylist.

You can also run:

```bash
python -m talonbox --help
```

## Security Principles

These principles are meant to keep Talon experimentation contained and predictable, especially when `talonbox` is driven by coding agents:

- No caller-triggered writes to host files outside `/tmp`. A `talonbox` command should not let its caller cause arbitrary host writes beyond that boundary.
- No symlink escapes through `/tmp`; a symlink placed under `/tmp` should not be able to redirect writes outside the allowed boundary.
- On macOS, treat `/private/tmp` as the canonical form of the same allowed temp root, not as a separate exception.
- Prefer explicit guest/host boundaries. Remote paths must be written as `guest:/...` so transfers stay easy to audit.
- Favor VM-local execution first. Talon code should run in the guest and only copy explicit outputs back to the host.

## Development

To contribute to this tool, use uv. The following command will establish the
venv and run tests:

```bash
uv run pytest
```

To run talonbox locally, use:

```bash
uv run talonbox
```
