# CLI reference

> Top-level `ati` subcommands (`run`, `tool`, `provider`, `skill`, `assist`, `plan`, `key`, `token`, `auth`, `proxy`, `audit`, `edge`), global flags (`--output`, `--verbose`), and output formats.

- Repository: Parcha-ai/ati
- GitHub: https://github.com/Parcha-ai/ati
- Human docs: https://grok-wiki.com/public/docs/parcha-ai-ati-a9d4398f11fa
- Complete Markdown: https://grok-wiki.com/public/docs/parcha-ai-ati-a9d4398f11fa/llms-full.txt

## Source Files

- `src/main.rs`
- `src/cli/mod.rs`
- `src/cli/provider.rs`
- `src/output/mod.rs`
- `README.md`
- `src/cli/audit.rs`
- `src/cli/edge.rs`

---

---
title: "CLI reference"
description: "Top-level `ati` subcommands (`run`, `tool`, `provider`, `skill`, `assist`, `plan`, `key`, `token`, `auth`, `proxy`, `audit`, `edge`), global flags (`--output`, `--verbose`), and output formats."
---

The `ati` binary is a single Rust entrypoint (`src/main.rs`) built with **clap**. Every invocation runs `cli::common::ensure_ati_dir()` first, initializes structured logging (proxy vs CLI mode), dispatches to a handler under `src/cli/`, and on failure emits tracing errors plus optional structured JSON on stderr when `--output json` is active.

## Global flags

These flags apply to all subcommands.

| Flag | Env | Default | Effect |
|------|-----|---------|--------|
| `--output` / `--format` | `ATI_OUTPUT` | `json` | Selects `json`, `table`, or `text` formatting via `src/output/mod.rs` |
| `-J` / `--json` | — | off | Shorthand: forces JSON output (overrides `--output`) |
| `--verbose` | — | off | Enables debug tracing; with JSON errors, includes an error `chain` |

<ParamField body="--output" type="enum (json \| table \| text)" default="json">
Controls how successful command results are printed. Subcommands that emit fixed prose (for example `ati key list`) may ignore this for non-JSON paths.
</ParamField>

<ParamField body="-J, --json" type="boolean">
Global JSON shorthand. Also honored inside `ati run` when swallowed by `trailing_var_arg` (see `parse_tool_args` in `src/cli/call.rs`).
</ParamField>

<ParamField body="--verbose" type="boolean">
Sets tracing to debug and prints error cause chains on stderr for non-JSON failures.
</ParamField>

### Built-in help

Use `ati --help`, `ati -h`, or `ati <subcommand> -h` for clap-generated help. **`ati run` disables the global `--help` flag** so `ati run <tool> --help` can pass through to CLI-backed tools. For ATI’s own `run` help, use `ati run -h`.

## Output formats

Successful tool and discovery commands typically serialize a `serde_json::Value` and pass it through `output::format_output`:

| Format | Behavior |
|--------|----------|
| **json** | Pretty-printed JSON (`src/output/json.rs`) |
| **table** | `comfy-table` for arrays of objects or key–value objects; falls back to JSON for other shapes |
| **text** | Strings printed raw; objects as `key: value` lines; arrays one item per line |

<Note>
`ati audit tail` and `ati audit search` print JSON only when `--output json`; otherwise they emit one human-readable line per entry (`timestamp [OK|ERR] tool (Nms) agent=…`).
</Note>

### Error output and exit codes

On failure, `main` logs via `tracing::error!`. When output is JSON, stderr receives a structured object from `core::error::format_structured_error` with `code`, `message`, and `exit_code`. Exit codes are grouped by prefix: `input` → 2, `auth` → 3, `provider` → 4, `rate` → 5, default → 1.

## Command map

```text
ati [--output] [--verbose] [-J]
├── run <tool> [--arg value ...]
├── tool | tools
│   ├── list [--provider NAME]
│   ├── info <name>
│   └── search <query>
├── skill | skills
│   ├── list | show | search | info | install | remove | init | validate
│   ├── read | resolve | verify | diff | update
│   └── fetch <skillati-subcommand>
├── skillati
│   ├── catalog | read | resources | cat | refs | ref | build-index
├── assist [--plan] [--save FILE] [--local] <args...>
├── plan execute <file> [--confirm-each]
├── provider
│   ├── add-mcp | add-cli | import-openapi | inspect-openapi
│   ├── list | remove | info | load | install-skills | unload
├── auth status
├── token keygen | issue | inspect | validate
├── init [--proxy] [--es256]
├── key set | list | remove
├── audit tail | search
├── edge bootstrap-keyring | rotate-keyring
└── proxy [--port] [--bind] [--ati-dir] [--env-keys] [--migrate]
         [--enable-passthrough] [--sig-verify-mode] [--sig-drift-seconds]
         [--sig-exempt-paths]
```

<Info>
`ati init` is a top-level command (not nested). It creates `manifests/`, `specs/`, `skills/`, and `config.toml` under the ATI directory. Use `ati init --proxy` to seed JWT proxy configuration (HS256 by default, `--es256` for a key pair).
</Info>

## Runtime directory

Unless overridden by `ATI_DIR`, the ATI home defaults to `~/.ati` (`core/dirs.rs`). First use creates `manifests/`, `specs/`, `skills/`, and a stub `config.toml`.

| Path | Purpose |
|------|---------|
| `manifests/*.toml` | Provider and tool definitions |
| `specs/` | Downloaded OpenAPI specs |
| `skills/` | Installed skill directories |
| `credentials` | Dev-mode API keys (`ati key set`) |
| `keyring.enc` | AES-256-GCM encrypted secrets (local/proxy execution) |
| `audit.jsonl` | Tool-call audit log (override with `ATI_AUDIT_FILE`) |

## Execution mode auto-detection

Several commands branch on **`ATI_PROXY_URL`**:

| Command | Local (no proxy URL) | Proxy (`ATI_PROXY_URL` set) |
|---------|----------------------|-----------------------------|
| `ati run` | Keyring + direct HTTP/MCP/CLI dispatch | POST `/call` via `proxy/client.rs` |
| `ati assist` | Local LLM + registry context | POST `/help` |
| `ati tool *` | Local registry + scopes | Proxy tool endpoints |
| `ati skill *` / `skillati` | Local or GCS registry | Proxy `/skills` and `/skillati/*` |

`file_manager:*` tools always perform client-side file I/O first, then dispatch locally or to the proxy.

## `ati run`

Execute a named tool with `--key value` pairs captured as trailing arguments.

```bash
ati run finnhub:quote --symbol AAPL
ati run github:search_repositories --query "ati" -J
ati run web_search --query "rust async" --output table
```

<Steps>
<Step title="Parse arguments">
`parse_tool_args` converts `--key value` into a `HashMap<String, Value>`. Values are JSON-parsed when possible; bare `--flag` becomes `true`. Global flags `-J`, `--json`, `--verbose`, and `--output` are stripped if swallowed by `trailing_var_arg`.
</Step>
<Step title="Normalize keys">
`normalize_arg_keys` maps CLI keys to schema property names (case, hyphen, snake_case variants).
</Step>
<Step title="Dispatch">
Handler comes from the provider manifest: `mcp`, `cli`, or default HTTP/OpenAPI via `providers/generic`. Scope and rate limits apply when JWT validation is configured.
</Step>
<Step title="Format result">
Success prints formatted output to stdout. Audit entries append to `audit.jsonl` in local mode.
</Step>
</Steps>

<Warning>
`ati run` with a CLI provider passes **raw** `raw_args` to the subprocess executor so subcommand flags like `--help` reach the underlying binary unchanged.
</Warning>

## `ati tool`

Scope-filtered tool discovery (alias: `tools`).

| Subcommand | Arguments | Description |
|------------|-----------|-------------|
| `list` | `[--provider NAME]` | Tabular or JSON list of in-scope tools |
| `info` | `<name>` | Schema, provider, tags, and linked skills |
| `search` | `<query>` | Fuzzy match on name, description, tags, category |

## `ati provider`

Unified provider lifecycle: write manifests under `manifests/`, discover tools from OpenAPI or MCP, or register CLI binaries.

| Subcommand | Purpose |
|------------|---------|
| `add-mcp` | Generate MCP manifest (`--transport http\|stdio`, `--url` or `--command`, `--env KEY=VALUE`) |
| `add-cli` | Register a local CLI binary (`--command`, `--env`, `--timeout`) |
| `import-openapi` | Download spec to `specs/`, emit manifest (`--name`, `--auth-key`, `--include-tags`, `--dry-run`) |
| `inspect-openapi` | Preview operations and auth without saving |
| `list` / `info` / `remove` | Inspect or delete manifests |
| `load` | Ephemeral provider from OpenAPI URL or `--mcp` (`--save` to persist, `--ttl` cache) |
| `install-skills` | Install skills declared in a provider manifest |
| `unload` | Drop a cached ephemeral provider |

MCP and OpenAPI tools are namespaced as **`provider:tool`**.

## `ati skill` and `ati skillati`

**`ati skill`** (alias `skills`) manages methodology docs under `~/.ati/skills/`.

| Subcommand | Notes |
|------------|-------|
| `list` | Filters: `--category`, `--provider`, `--tool` |
| `show` / `info` | SKILL.md body vs `skill.toml` metadata (`--meta`, `--refs`) |
| `search` | Fuzzy over name, description, keywords, tools |
| `install` | Local path, git, or HTTPS (`--name`, `--all`, `--local` for offline manifest gen) |
| `remove` / `init` / `validate` | Lifecycle and validation (`--check-tools`) |
| `read` | Agent-oriented SKILL.md (`--tool`, `--with-refs`) |
| `resolve` | Skills auto-loaded for current scopes (`--scopes` path override) |
| `verify` / `diff` / `update` | Integrity and sync from source |
| `fetch` | Delegates to SkillATI subcommands (same as top-level `skillati`) |

**`ati skillati`** (also `ati skill fetch …`) reads the remote GCS skill registry without installing:

| Subcommand | Purpose |
|------------|---------|
| `catalog` | List remote skills (`--search`) |
| `read` | SKILL.md for one skill |
| `resources` | List bundled paths (`--prefix`) |
| `cat` | Read `scripts/`, `references/`, or cross-skill paths |
| `refs` / `ref` | Reference file listing and fetch |
| `build-index` | Build catalog manifest JSON for publishing (`--output-file`) |

## `ati assist`

LLM-powered discovery: natural-language query → recommended `ati run` commands.

```bash
ati assist "research Apple stock price and insiders"
ati assist finnhub "quote and sentiment for AAPL"
ati assist --plan --save plan.json "multi-step Finnhub research"
ati assist --local "offline ollama assist"
```

| Flag | Effect |
|------|--------|
| `--plan` | Structured JSON plan of tool steps (no prose) |
| `--save FILE` | Implies `--plan`; writes plan JSON |
| `--local` | Use local LLM (ollama) instead of hosted API |

If the first positional argument matches a tool or provider name, assist scopes to that surface.

## `ati plan`

| Subcommand | Description |
|------------|-------------|
| `execute FILE` | Run a saved plan JSON (`query`, `steps[]` with `tool`, `args`, `description`) |

`--confirm-each` prompts on a TTY before each step; failures can abort or continue interactively. Plans are produced by `ati assist --plan` / `--save`.

## `ati key`

Dev-oriented credential store at **`~/.ati/credentials`** (JSON map, mode `0600` on Unix). Distinct from **`keyring.enc`** used during tool execution.

| Subcommand | Syntax |
|------------|--------|
| `set` | `ati key set <name> <value>` |
| `list` | Masked values (`sk-1…cdef` style) |
| `remove` | `ati key remove <name>` |

## `ati token`

JWT lifecycle for proxy sandboxes (does not require `--output`).

| Subcommand | Key options |
|------------|-------------|
| `keygen` | `--algorithm ES256` (default) or `HS256` — prints PEM or hex secret |
| `issue` | `--sub`, `--scope`, `--ttl` (default 1800s), `--aud`, `--iss`, `--key` or `--secret`, repeatable `--rate` |
| `inspect` | Decode without verification |
| `validate` | Full verify (`--key` or `--secret`) |

## `ati auth`

| Subcommand | Description |
|------------|-------------|
| `status` | Decode `ATI_SESSION_TOKEN`: agent, scopes, expiry, verification status |

When no token is set and JWT is not configured locally, reports unrestricted dev mode.

## `ati audit`

Reads **`~/.ati/audit.jsonl`** (or `ATI_AUDIT_FILE`).

| Subcommand | Options |
|------------|---------|
| `tail` | `-n` / `--` count (default 20) |
| `search` | `--tool` (wildcard suffix), `--since` (`1h`, `30m`, `7d`) |

JSON output serializes full `AuditEntry` objects (`ts`, `tool`, `args`, `status`, `duration_ms`, `agent_sub`, optional `job_id`, `sandbox_id`, `error`).

## `ati edge`

Operator commands for edge VMs with 1Password-backed keyrings.

### `bootstrap-keyring`

Pulls labeled fields from `op item get`, writes `<ati_dir>/keyring.enc` and `<ati_dir>/.keyring-key` (persistent session key, idempotent).

| Flag | Description |
|------|-------------|
| `--vault` | 1Password vault name |
| `--item` | Item name or UUID |
| `--ati-dir` | ATI root (default `~/.ati`) |
| `--op-path` | `op` binary path |
| `--op-token-file` | Service-account token file → `OP_SERVICE_ACCOUNT_TOKEN` |

### `rotate-keyring`

Atomically replaces `keyring.enc`, then **SIGHUP** the systemd service (default `ati`) so the proxy reloads secrets without restart.

| Flag | Description |
|------|-------------|
| `--service` | Unit to signal (default `ati`) |
| `--no-signal` | Skip SIGHUP (pre-start rotation) |

Requires prior `bootstrap-keyring`. Field labels in 1Password become keyring entry names (for example `sandbox_signing_shared_secret`).

## `ati proxy`

Run ATI as an HTTP server holding secrets for sandboxed agents.

```bash
ati proxy --port 8090 --bind 127.0.0.1
ati proxy --env-keys --migrate
ati proxy --enable-passthrough --sig-verify-mode enforce
```

| Flag | Default | Description |
|------|---------|-------------|
| `--port` | `8090` | Listen port |
| `--bind` | `127.0.0.1` | Bind address (`0.0.0.0` for all interfaces) |
| `--ati-dir` | `~/.ati` | Manifests, keyring, scopes |
| `--env-keys` | off | Load API keys from environment instead of `keyring.enc` |
| `--migrate` | off | Apply embedded DB migrations when `ATI_DB_URL` is set |
| `--enable-passthrough` | off | Expose raw HTTP routes from `handler = "passthrough"` manifests |
| `--sig-verify-mode` | `log` | HMAC sandbox signature: `log`, `warn`, or `enforce` |
| `--sig-drift-seconds` | `60` | Max clock skew for signed requests |
| `--sig-exempt-paths` | built-in set | Comma-separated path globs exempt from verification |

<Note>
Signing secret is read from keyring entry `sandbox_signing_shared_secret`. In `enforce` mode, a missing secret fails closed at startup.
</Note>

Proxy routes (`/call`, `/mcp`, `/help`, `/skills`, `/skillati/*`, `/health`, JWKS, optional admin) are documented on the proxy API page.

## Local scopes and JWT

`cli::common::load_local_scopes_from_env` enforces:

- If JWT validation env is configured → **`ATI_SESSION_TOKEN`** (or file variants) required and validated.
- Otherwise → unrestricted dev mode for local commands.

This affects `ati tool list`, `ati run` (local path), and skill visibility gates.

## Related pages

<CardGroup>
<Card title="Quickstart" href="/quickstart">
Initialize `~/.ati/`, import a provider, store keys, and run your first tool.
</Card>
<Card title="Execution modes" href="/execution-modes">
Local keyring vs `ATI_PROXY_URL` proxy mode and credential placement.
</Card>
<Card title="Environment variables" href="/environment-variables">
`ATI_OUTPUT`, `ATI_DIR`, `ATI_PROXY_URL`, `ATI_SESSION_TOKEN`, JWT keys, and audit paths.
</Card>
<Card title="Assist and plan reference" href="/assist-and-plan-reference">
`--plan`, `--save`, internal `_llm` provider, and plan JSON schema.
</Card>
<Card title="Configure JWT and keys" href="/configure-jwt-and-keys">
`ati token`, `ati init --proxy`, and session token issuance patterns.
</Card>
<Card title="Deploy proxy server" href="/deploy-proxy-server">
Production `ati proxy` binding, passthrough, sig-verify rollout, and systemd.
</Card>
</CardGroup>
