Metadata-Version: 2.4
Name: auto-any
Version: 0.1.1
Summary: Deterministic browser and task automation with replayable receipts
Requires-Python: >=3.11
Requires-Dist: anyio>=4.0
Requires-Dist: fastapi>=0.115
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic-settings>=2.4
Requires-Dist: pydantic>=2.8
Requires-Dist: pyjwt>=2.8
Requires-Dist: python-json-logger>=2.0
Requires-Dist: rich>=13.7
Requires-Dist: sse-starlette>=2.1
Requires-Dist: typer>=0.12
Requires-Dist: uvicorn[standard]>=0.30
Provides-Extra: anthropic
Requires-Dist: anthropic>=0.116; extra == 'anthropic'
Provides-Extra: appium
Requires-Dist: appium-python-client>=4.0; extra == 'appium'
Provides-Extra: bedrock
Requires-Dist: boto3>=1.35; extra == 'bedrock'
Provides-Extra: browser
Requires-Dist: playwright>=1.45; extra == 'browser'
Provides-Extra: dev
Requires-Dist: asgi-lifespan; extra == 'dev'
Requires-Dist: httpx; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Requires-Dist: respx>=0.21; extra == 'dev'
Requires-Dist: ruff>=0.6; extra == 'dev'
Provides-Extra: efa
Requires-Dist: rubricon>=0.2.2; extra == 'efa'
Provides-Extra: mcp
Requires-Dist: mcp>=1.0; extra == 'mcp'
Provides-Extra: openai
Requires-Dist: openai>=1.40; extra == 'openai'
Provides-Extra: selenium
Requires-Dist: selenium>=4.20; extra == 'selenium'
Description-Content-Type: text/markdown

# auto-any

```
goal + URL -> signature -> exact receipt? -> deterministic replay
                         \-> local/remote engine -> browser -> distiller -> receipt
```

Run with `uvicorn auto_any.main:app`. For local development install RTR first with
`uv pip install -e <path-to-replayable-test-runner>`.
Configuration uses the `AANY_` prefix; see `.env.example`.

## Install / share

One command gets a teammate from zero to "auto-any MCP Connected":

```powershell
pwsh install/install.ps1
```

macOS, Linux, or Git Bash:

```bash
bash install/install.sh
```

See [`install/README.md`](install/README.md) for options (custom venv path, local wheel) and the two `.env` knobs you must set.

## Reuse my Chrome logins

To run against a cloned copy of an already-authenticated Chrome profile:

```powershell
$env:AANY_PROFILE_MODE = "clone"
$env:AANY_CHROME_SOURCE_PROFILE = "Profile 2"  # or Default
uvicorn auto_any.main:app
```

The clone is created under `AANY_PROFILES_DIR`, and the source User Data tree is
never written. Chrome may be left open; a cookie written very recently may not
have been flushed yet. `AANY_PROFILE_KEEP=false` removes the clone after the run.
Cloning copies live authentication cookies, so treat the profiles directory as
sensitive and do not commit or share it. Set `AANY_BLOCK_PRIVATE_NETWORKS=true`
for hosted deployments; the default is false so operator-owned localhost and
LAN targets remain usable. For a persistent named profile, use
`AANY_PROFILE_MODE=named` and select it with `profile: {"name":"work"}` (or use
a pack that declares `profile_name`). Named profiles
are managed with `GET /profiles` and `DELETE /profiles/{name}`.

## Capabilities

| Capability | Action kinds | Runner |
|---|---|---|
| browser | `playwright` | RTR Playwright meta-runner |
| shell | `shell` | RTR shell runner (allow/deny policy) |
| http | `http_request` | RTR HTTP runner |
| extract | `extract` | typed Pydantic model |
| verify | `verify` | explicit RTR assertion |

Add a capability by implementing the `Capability` contract, registering its
name in `CAPABILITIES`, and registering an RTR `StepRunner` for each action
kind. `CapabilityGate` then dispatches it without changing the engine loop.

### Rubricon / EFA scoring

Install the optional evaluator integration with `pip install 'auto-any[efa]'`
and select it with `score="efa"` in an automation request. The adapter uses
Rubricon's dynamic criteria generation and per-criterion evaluator to attach
RAS, APR, and criterion scores to the run result. It evaluates the completed
response only; replay remains deterministic and does not invoke an LLM.

Paused OTP/CAPTCHA/confirmation turns emit `needs_input`; resume with
`POST /automations/{run_id}/resume`. Secret values are stored in receipts only
as `{"$var":"field"}`. Trace artifacts are per-run and video is opt-in.

## Storage layout

The storage root is `AANY_HOME`, defaulting to `Path.home() / ".auto_any"`.
Relative `AANY_RECEIPTS_DIR` and `AANY_ARTIFACTS_DIR` values resolve under this
root; absolute values are honored as supplied.

```
~/.auto_any/
├── receipts/                 # replayable receipts
├── artifacts/<run_id>/       # per-run screenshots + trace.zip
│   ├── 001_open.png
│   ├── 002_click.png
│   └── trace.zip
├── ledger.jsonl              # append-only run history
└── site_profiles.json        # site → browser-profile mapping
```

Browser screenshots are captured automatically after browser actions, with
zero-padded ordered names such as `001_open.png` and `002_click.png`. Capture
is non-fatal and is enabled by the `auto_screenshot=True` driver constructor
option. A run without an explicit ID uses a timestamped artifact directory.
The run ledger is enabled by default as an append-only JSONL file; pass
`AANY_LEDGER=null` to opt out, or `AANY_LEDGER=<path>.db` for SQLite.

> **Economics:** replayed runs cost **0 LLM tokens**; planned runs cost **N LLM tokens**.

## MCP server

auto_any can run as a STDIO Model Context Protocol (MCP) server so Claude and
other MCP clients can invoke it in-process.

```powershell
# install the MCP extra
uv pip install -e ".[mcp,browser]"

# register with Claude Desktop (do not edit ~/.claude manually)
claude mcp add-json auto-any '{"command": "auto-any-mcp"}'
```

The server boots one shared headless runtime (`AANY_PROFILE_MODE=fresh`) and
exposes five tools:

| Tool | Purpose |
|---|---|
| `auto_any_list_packs` | List installed packs + parameter schemas |
| `auto_any_run_pack` | Run a pack by name with validated params |
| `auto_any_run` | Run a free-text goal + URL |
| `auto_any_list_receipts` | List saved receipts (signature key + title) |
| `auto_any_replay` | Replay a receipt with zero LLM tokens |

Start it manually with `auto-any-mcp`.

## Three Lanes

auto_any exposes the same automation engine through three interfaces. All three delegate to the shared `automation_events` generator in `api/automations.py`.

| Lane | Command | Description |
|------|---------|-------------|
| **CLI** | `auto-any run --goal "..." --url "..."` | Direct command-line execution |
| **HTTP** | `auto-any serve` (starts uvicorn) | REST API at `POST /automations` |
| **MCP** | `python -m auto_any.mcp_server` | STDIO tools for Claude Desktop |

All lanes accept the same request shape: `goal`, `url`, `mode` (auto/always_plan/replay_only), and return streaming events containing `run_started`, `progress`, `run_finished`, and optionally `receipt_saved`.

Additional CLI commands:
- `auto-any receipts` — list stored receipts (signature key + title)
- `auto-any replay <signature_key>` — replay a receipt with zero LLM tokens
- `auto-any version` — print the running build's identity

## Receipt Contract

A **receipt** is a deterministic, replayable record of an automation run. It contains:

- **signature_key**: SHA256 hash of `goal + url + context` — the identity for exact-match replay
- **title**: Human-readable description
- **steps**: Ordered list of actions (goto, click, type, extract, verify...)
- **url**: Target URL at time of execution

**What replay guarantees:**
- Same goal + same URL → same actions in same order
- Zero LLM tokens consumed (deterministic playback)
- Pass/fail per step — if a page element changed, replay reports failure

**What replay does NOT guarantee:**
- External state (logged-in sessions, database data, third-party API responses)
- Timing/performance — replay is deterministic but not real-time
- Cross-browser parity — receipts are driver-specific (Playwright vs Selenium)
- Future site changes — replay fails if UI changed; this is the intended behavior

The signature key is the lookup key for both `auto-any receipts` and the MCP `auto_any_replay` tool.

## How to Tell Which Build is Running

On 2026-07-26, the MCP server ran for hours importing stale code from a different git worktree while reporting healthy. Nothing revealed which build was actually executing.

Two ways to verify the running build:

```bash
# CLI — prints version, git SHA, dirty flag, and import path
$ auto-any version
auto-any 0.1.0 git:bf3545d

$ auto-any version --json
{"version": "0.1.0", "git_sha": "bf3545d", "dirty": false, "import_path": "C:\\Users\\...\\src\\auto_any"}
```

```bash
# MCP — check the startup log line
$ python -m auto_any.mcp_server
selected browser driver=playwright tier=config_explicit task_hint=
MCP server starting: auto-any 0.1.0 git:bf3545d; import_path=C:\Users\...\src\auto_any
```

The `import_path` field shows the exact directory from which `auto_any` was loaded. If this differs from the expected worktree, the running code is stale.

## Quickstart — adopt it for any UI automation

```bash
uv venv && uv pip install -e ".[dev,browser]"
uv run playwright install chromium          # real browser lane

# list built-in automation packs (smoke_test, form_fill, example_form)
uv run auto-any packs

# run the API
uv run auto-any serve --port 8080
#   POST /automations            free-text goal (the raw engine)
#   GET  /packs                  installed packs + their param schemas
#   POST /packs/{name}/run       typed params -> same pipeline -> receipt

# reuse your real Chrome logins (no interactive auth):
#   AANY_PROFILE_MODE=clone AANY_CHROME_SOURCE_PROFILE="Profile 2"
# real LLM to drive arbitrary UIs:
#   AANY_LLM_PROVIDER=anthropic AANY_LLM_API_KEY=...
```

### Packs quickstart

The built-in packs are `smoke_test`, `form_fill`, and `example_form`. For a
local unauthenticated development server, set `AANY_AUTH_DISABLED=true`, then
inspect schemas and run `smoke_test` as an SSE stream:

```bash
export AANY_AUTH_DISABLED=true
uv run auto-any serve --port 8080

curl http://127.0.0.1:8080/packs
curl -N -X POST http://127.0.0.1:8080/packs/smoke_test/run \
  -H 'Content-Type: application/json' \
  -d '{"base_url":"http://127.0.0.1:8080","checks":[{"path":"/health","expect_text":"ok"}]}'
```

With authentication enabled, add `-H "Authorization: Bearer <token>"` to both
requests.

Add a new use-case as a **pack** (no core edits) - see `ARCHITECTURE.md`.

## Multi-vendor execution

`AANY_BROWSER_DRIVER=playwright|selenium|appium|auto` selects the per-action driver.
Install optional integrations with `uv pip install -e ".[selenium]"` or `.[appium]`;
absent SDKs and servers produce an actionable unavailable event. A request can
override this with `{"driver":"selenium"}`. Export receipts with
`POST /receipts/{key}/export` and `{"format":"cypress"}` (`playwright` and
`robot` are also supported). `$var` values become vendor environment lookups and
are never written as secrets. Set `score` to `passmark` for a tolerant score report.

### Tests

```bash
uv run pytest -q            # hermetic unit suite (fakes only, no browser)
AANY_E2E=1 uv run pytest tests/test_e2e_real_browser.py   # real headless Chromium
```
