Metadata-Version: 2.4
Name: virtuai-cli
Version: 0.7.3
Summary: Run VirtuAI deep agents on your local machine
Author-email: uCloudStore <lmoreno@ucloudstore.com>
License: Proprietary
Project-URL: Homepage, https://imvituai.com
Keywords: virtuai,ai,agents,cli
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: websockets>=12.0
Requires-Dist: httpx[http2]>=0.27
Requires-Dist: httpx-sse>=0.4
Requires-Dist: certifi>=2024.0
Requires-Dist: keyring>=25.0
Requires-Dist: typer>=0.12
Requires-Dist: rich>=13.0
Requires-Dist: textual>=0.86

# VirtuAI CLI

Run VirtuAI agents from your terminal — chat interactively in a Claude-Code-style TUI, or pipe them into shell scripts. The agent's bash/file tools run on **your** machine, so files appear in your filesystem and commands hit your real shell.

## Installation

```bash
pip install virtuai-cli
```

Or with [pipx](https://pipx.pypa.io/) (recommended for CLI tools — handles PATH automatically):

```bash
pipx install virtuai-cli
```

Requires Python 3.11+.

## Quick start

### 1. Pair this machine with a workspace

Open the VirtuAI portal → **Settings → CLI** → generate a pairing code, then:

```bash
virtuai pair <CODE>
```

The pairing is one-time; the resulting token is stored in your system keychain.

### 2. Chat with an agent

```bash
virtuai chat
```

Opens an interactive TUI. Pick an agent (skipped if your workspace has only one), type a message, watch the response stream in. The agent's tool calls — `bash`, file reads, file writes — execute on this machine, in the current directory.

### 3. Use it from a shell script

```bash
virtuai ask "summarize the changes in this branch"

git diff | virtuai ask "what does this change?"

virtuai ask --json "find any bugs" > events.jsonl
```

`ask` is non-interactive: it prints the response to stdout, then exits.

## Commands

| Command | Description |
|---|---|
| `virtuai chat`          | Open the interactive chat TUI |
| `virtuai ask "..."`      | One-shot prompt for scripts (reads stdin if piped) |
| `virtuai pair <code>`    | Pair this machine with a workspace |
| `virtuai unpair`         | Revoke the current pairing |
| `virtuai run`            | Headless WebSocket runner — let the web app/channels invoke local tools without opening the TUI |
| `virtuai status`         | Show pairing and connection status |
| `virtuai logs`           | Show recent commands the agent executed locally |
| `virtuai login`          | Authenticate with your VirtuAI account (browser flow) |
| `virtuai config get/set` | Read or set local CLI options (e.g. `server_url`) |

## Inside `virtuai chat`

The TUI streams tokens, renders tool calls as live cards (running → complete), tracks the agent's todo list, and shows a randomized "✻ Pondering…" indicator while the agent is composing.

Slash commands (type `/` to see the filtered list, Tab to autocomplete):

| Slash command       | What it does |
|---|---|
| `/help`             | Show this list |
| `/clear`, `/new`    | Drop the current session and start fresh |
| `/history`          | List your recent conversations with this agent |
| `/load <id>`        | Reopen a past conversation by session_id |
| `/models`           | List models available for this agent |
| `/model <id>`       | Switch the model for subsequent messages |
| `/exit`, `/quit`    | Close the TUI |

Key bindings:

- **Esc** — cancel the in-flight response
- **Ctrl+L** — start a new conversation
- **Ctrl+C** — quit
- **Tab** — autocomplete the current `/command`

## `virtuai ask` for scripting

```bash
# Direct prompt
virtuai ask "what's in this folder?"

# Pipe stdin in (concatenated with the argument if both given)
git log --oneline -20 | virtuai ask "summarize these commits"

# Continue a previous session (use --print-session to surface the id)
virtuai ask --session sess-aaa "and apply that fix" --print-session

# Machine-readable: every event as one JSON line
virtuai ask --json "find any bugs" > events.jsonl

# Just the final answer, no streaming (good for capturing into variables)
ANSWER=$(virtuai ask -q "give me the current time")

# Pick a different agent or model
virtuai ask --agent code-review --model claude-opus "review main.py"

# Skip the local runner for a faster startup when no tools are needed
virtuai ask --no-tools "tell me a joke"
```

Output streams:

- `stream` (default) — tokens go to **stdout**, tool indicators to **stderr** (so `> out.txt` captures only the answer)
- `--quiet` / `-q` — accumulate, print only the final assistant text at the end
- `--json` — every SSE event as one JSONL line on stdout (parseable)

Exit codes: `0` success · `1` stream error · `2` bad args / agent not found.

## Common options

```
--server <url>       Override the saved server URL
--workdir <path>     Working directory for tool execution (default: current dir)
--agent <id|name>    Pick a specific agent
--model <id>         Override the agent's default model
```

## Security model

- The CLI token is stored in your OS keychain (Keychain on macOS, libsecret on Linux, Credential Manager on Windows).
- All traffic is over TLS WebSockets and HTTPS; the CLI uses the [`certifi`](https://github.com/certifi/python-certifi) CA bundle, so macOS Python installs without `Install Certificates.command` still verify correctly.
- Local commands run under your user account with your file permissions.
- The agent **cannot `cd` above the working directory** — `cd ..` past the workdir is rejected by the executor.
- A denylist blocks obvious foot-guns: `sudo`, `rm -rf /`, fork bombs, `mkfs`, `dd of=/dev/…`, etc.
- Every executed command is recorded with timestamp + exit code to `~/.virtuai/audit.log`.
- The agent only has access while `virtuai chat`, `virtuai ask`, or `virtuai run` is in the foreground — no background daemon.

## Programmatic use

The async building blocks the TUI is built on are importable directly:

```python
import asyncio
from virtuai_cli import config as cfg
from virtuai_cli.chat.sse import stream_chat

async def main():
    token  = cfg.load_token(cfg._KEYRING_CLI_TOKEN_KEY)
    server = cfg.get_server_url()
    async for event in stream_chat(server, token, "your-agent-id", "Hello"):
        if event.get("type") == "token":
            print(event["content"], end="", flush=True)

asyncio.run(main())
```

A formal SDK (typed client class, sync wrappers) is on the roadmap.

## Links

- **Homepage**: <https://imvirtuai.com>
- **PyPI**: <https://pypi.org/project/virtuai-cli/>
- **Issues / docs**: contact your workspace admin
