# Assist and plan reference

> `ati assist` flags (`--plan`, `--save`, `--local`), internal `_llm` provider, structured plan output, and `ati plan` execution of saved tool-call plans.

- 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/cli/help.rs`
- `src/cli/plan.rs`
- `docs/assist-examples.md`
- `manifests/_llm.toml`
- `tests/plan_test.rs`
- `src/core/skill.rs`

---

---
title: "Assist and plan reference"
description: "`ati assist` flags (`--plan`, `--save`, `--local`), internal `_llm` provider, structured plan output, and `ati plan` execution of saved tool-call plans."
---

`ati assist` is ATI’s LLM-backed discovery command: it assembles scope-filtered tool and skill context, calls the internal `_llm` provider (or Anthropic / local OpenAI-compatible fallbacks), and returns either conversational `ati run` guidance or a machine-readable plan. `ati plan execute` replays saved plan JSON by dispatching each step through the same `ati run` stack used for single calls.

## Command surface

| Command | Purpose |
|---------|---------|
| `ati assist [scope] <query…>` | Natural-language tool discovery and usage guidance |
| `ati assist --plan [scope] <query…>` | Same context, but LLM must return structured JSON steps |
| `ati assist --save <path> [scope] <query…>` | Implies `--plan`; writes pretty-printed plan JSON to `<path>` |
| `ati plan execute <file>` | Validate tools, then run each plan step via `ati run` |
| `ati plan execute <file> --confirm-each` | Prompt before each step on an interactive TTY |

Positional arguments use `trailing_var_arg`: when the first token matches a registered tool or provider name, assist runs in **scoped** mode; otherwise the full argument list is the query.

<ParamField body="--plan" type="flag">
Return a structured plan of tool calls instead of prose. Always uses the local assist pipeline (does not forward to the proxy).
</ParamField>

<ParamField body="--save" type="string">
Output path for plan JSON. Setting this flag enables plan mode even without `--plan`.
</ParamField>

<ParamField body="--local" type="flag">
Force the OpenAI-compatible local LLM path (`OLLAMA_HOST`, default `http://localhost:11434`). Also honored when `ATI_ASSIST_PROVIDER=local`.
</ParamField>

## Runtime routing

```mermaid
flowchart TB
  subgraph assist_cli["ati assist"]
    A[Parse args + scope]
    B{--plan or --save?}
    C[execute_plan_mode\nlocal LLM only]
    D{ATI_PROXY_URL set?}
    E[POST proxy /help]
    F[execute_local\nbuild context + call_llm]
  end
  subgraph llm_backends["LLM backends"]
    G[Cerebras via _llm.toml]
    H[Anthropic Messages API]
    I[Local OpenAI-compatible]
  end
  subgraph replay["ati plan execute"]
    J[Load plan JSON]
    K[Validate tools in registry]
    L[ati run per step]
  end
  A --> B
  B -->|yes| C --> G
  B -->|no| D
  D -->|yes| E
  D -->|no| F
  F --> G
  F --> H
  F --> I
  C --> G
  J --> K --> L
```

<Note>
Plan mode (`--plan` / `--save`) never uses `ATI_PROXY_URL`. Even in proxy deployments, plan generation runs locally with manifests, keyring, and MCP discovery from `~/.ati/`.
</Note>

Prose assist without plan flags:

- **`ATI_PROXY_URL` set** — forwards to `POST /help` on the proxy, JWT via `ATI_SESSION_TOKEN`.
- **Otherwise** — loads `~/.ati/manifests`, discovers MCP tools, filters by JWT scopes when validation is configured, and calls `call_llm` directly.

## Internal `_llm` provider

The bundled manifest `manifests/_llm.toml` defines an **internal** provider (hidden from `ati tool list`) used only for assist:

| Field | Value |
|-------|-------|
| Provider | `_llm` |
| Tool | `_chat_completion` |
| Endpoint | `POST /chat/completions` on `https://api.cerebras.ai/v1` |
| Model | `zai-glm-4.7` |
| Auth key | `cerebras_api_key` in keyring (or `CEREBRAS_API_KEY` env, checked first) |
| Generation | `max_completion_tokens: 1536`, `temperature: 0.3` |

Proxy `POST /help` uses the same manifest and keyring entry. If `_llm.toml` or the key is missing, the proxy returns **503** with an explicit error. Internal tools never appear in the assist system prompt’s tool list (`list_public_tools` excludes `internal = true` providers).

## LLM selection order

`call_llm` resolves backends in this order (unless `--local` / `ATI_ASSIST_PROVIDER=local` forces local first):

<Steps>
<Step title="Local override">
`--local` or `ATI_ASSIST_PROVIDER=local` → `call_local_llm` against `{OLLAMA_HOST}/v1/chat/completions` (120s timeout).
</Step>
<Step title="Cerebras">
`CEREBRAS_API_KEY` env, else keyring `cerebras_api_key` via `_chat_completion` manifest.
</Step>
<Step title="Anthropic">
`ANTHROPIC_API_KEY` → `https://api.anthropic.com/v1/messages`; model from `ATI_ASSIST_MODEL` (default `claude-haiku-4-5-20251001`).
</Step>
<Step title="Local fallback">
If no cloud keys are set, auto-attempt local LLM; failure surfaces install hints for Ollama and `OLLAMA_HOST`.
</Step>
</Steps>

| Variable | Default | Role |
|----------|---------|------|
| `CEREBRAS_API_KEY` | — | Preferred cloud key (checked before keyring) |
| `ANTHROPIC_API_KEY` | — | Anthropic fallback |
| `ATI_ASSIST_MODEL` | `claude-haiku-4-5-20251001` | Anthropic model id |
| `ATI_ASSIST_PROVIDER` | auto | Set to `local` to force local LLM |
| `OLLAMA_HOST` | `http://localhost:11434` | Local server base URL |
| `ATI_OLLAMA_MODEL` | `smollm3:3b` | Local model name |

<Warning>
Local models on CPU are slow and may ignore large tool contexts. Production assist should use Cerebras or Anthropic; `--local` is intended for air-gapped or sandboxed environments.
</Warning>

## Context assembly

### Tool catalog

- Unscoped queries pre-filter up to **50** tools with the same fuzzy scorer as `ati tool search` (`prefilter_tools_by_query`).
- Scoped queries load one tool’s schema, or all tools for a provider name.
- CLI providers optionally embed live `--help` output (5s timeout, max 3000 chars per capture; skipped when more than five CLI tools unless scoped).
- JWT scopes from `load_local_scopes_from_env` filter tools before prompting; without JWT config, local mode is unrestricted for development.

### Skills

Matched skills inject SKILL.md content (up to **16 000** chars total, **4 000** per skill) via `build_skills_for_tools`:

1. Skills bound to matched tool names  
2. Skills bound to those tools’ providers  
3. Keyword search on tool-name tokens  

Proxy `/help` additionally merges remote SkillATI catalog sections. See [Skills and SkillATI](/skills-and-skillati).

### Prose output extras

Text mode appends a **Quick Reference** block when the model mentions tool names from context: auto-generated `ati run` usage cards and parameter summaries from each tool’s JSON Schema. JSON mode (`--output json` / `-J`) returns:

```json
{
  "content": "<llm text>",
  "tools_referenced": ["tool_a", "tool_b"]
}
```

Proxy JSON assist sets `tools_referenced` to an empty array (the proxy does not post-process mentions).

## Plan mode

Plan mode reuses the same context builder as prose assist, then appends a plan-mode system prompt suffix instructing the model to reply with **only** JSON:

```json
{
  "steps": [
    {
      "tool": "<tool_name>",
      "args": { "<key>": "<value>" },
      "description": "<what this step does>"
    }
  ]
}
```

`parse_plan_response` accepts raw JSON or JSON inside markdown fences (`` ```json `` / `` ``` ``). It builds a `Plan` object:

<ResponseField name="query" type="string">
Original user query (from resolved assist args).
</ResponseField>

<ResponseField name="steps" type="array">
Ordered `PlanStep` entries; missing `args` defaults to `{}`.
</ResponseField>

<ResponseField name="created_at" type="string">
UTC timestamp in RFC3339 from `chrono::Utc::now()`.
</ResponseField>

Each `PlanStep` contains `tool`, `args` (`HashMap<String, Value>`), and `description`.

<RequestExample>

```bash
ati assist --plan "get top HN stories then search the web for the top headline"
```

</RequestExample>

<RequestExample>

```bash
ati assist --save ./workflow.json finnhub "quote and insider activity for AAPL"
```

</RequestExample>

On parse failure, the CLI exits with `Failed to parse plan from LLM response` and prints the raw model output for debugging.

## `ati plan execute`

<Steps>
<Step title="Load and parse">
Read the plan file as JSON into `Plan`.
</Step>
<Step title="Validate">
Ensure every `step.tool` exists in `ManifestRegistry` before any execution (`unknown tool` error names the step index).
</Step>
<Step title="Run steps">
For each step, convert `args` to `--key value` pairs (non-strings use `Value::to_string()`), then call `call::execute` (respects `ATI_PROXY_URL` like a normal `ati run`).
</Step>
</Steps>

| Behavior | Detail |
|----------|--------|
| Success | Prints `[OK]` on stderr |
| Failure | Prints `[ERROR] <message>`; with `--confirm-each` on a TTY, offers to continue |
| Skip | `--confirm-each` + `n` skips the step |
| Abort | `--confirm-each` + error + `n` stops with `Plan execution aborted at step N` |

Example plan file:

```json
{
  "query": "find info",
  "steps": [
    {
      "tool": "hackernews:top_stories",
      "args": { "limit": 5 },
      "description": "Get top stories"
    },
    {
      "tool": "web_search",
      "args": { "query": "rust async" },
      "description": "Search web"
    }
  ],
  "created_at": "2025-01-01T00:00:00Z"
}
```

```bash
ati plan execute ./workflow.json
ati plan execute ./workflow.json --confirm-each
```

## Proxy `POST /help`

:::endpoint POST /help
LLM-powered assist for sandboxed agents. Requires JWT when proxy JWT validation is enabled. Body: `{ "query": string, "tool"?: string }`. Response: `{ "content": string, "error"?: string }`.
:::

The handler mirrors local assist scoping, uses scope-filtered `list_public_tools`, resolves skills (local + remote SkillATI), and calls Cerebras through `_chat_completion`. Documented security policy: include the `help` scope (or `*`) in session tokens so agents may use discovery endpoints; tool visibility still follows `tool:` / `skill:` scopes ([JWT and scopes reference](/jwt-scopes-reference)).

## Scopes and JWT

When `ATI_JWT_*` validation is configured locally, `ati assist` and plan mode require a valid `ATI_SESSION_TOKEN` and only expose tools allowed by the token’s `scope` claim. `ati auth show` reports `help_enabled` when the token includes `help` or `*`. Scoped assist to a tool outside the token returns: `'name' is not visible in your current scopes.`

## Failure modes

| Symptom | Likely cause |
|---------|----------------|
| `No _llm.toml manifest found` | Missing `manifests/_llm.toml` in `ATI_DIR` |
| `LLM API key not found in keyring` | `ati key set cerebras_api_key …` not run (proxy) |
| `Failed to parse plan from LLM response` | Model returned prose or malformed JSON; retry or tighten query |
| `Step N: unknown tool` | Plan references a tool not in manifests (typo or unloaded provider) |
| `Cannot read plan file` / `Invalid plan JSON` | Bad path or corrupt plan file |
| `Scope 'X' is not visible` | JWT or scope filter excludes that tool/provider |
| Empty / useless local answers | Model too small or CPU-bound; use cloud keys |

## Related pages

<CardGroup>
<Card title="Scopes and tool discovery" href="/scopes-and-tool-discovery">
JWT scope filtering and the three discovery tiers: `ati tool search`, `ati tool info`, and `ati assist`.
</Card>
<Card title="CLI reference" href="/cli-reference">
Top-level `assist` and `plan` subcommands, global `--output` / `--verbose` flags.
</Card>
<Card title="Proxy API reference" href="/proxy-api-reference">
`POST /help` request shape, auth, and error codes.
</Card>
<Card title="Configure JWT and keys" href="/configure-jwt-and-keys">
Issuing tokens with `help` and tool scopes for assist in sandboxes.
</Card>
<Card title="Environment variables" href="/environment-variables">
`ATI_PROXY_URL`, `ATI_SESSION_TOKEN`, `OLLAMA_HOST`, and assist-related overrides.
</Card>
<Card title="Execution modes" href="/execution-modes">
Local keyring vs proxy routing for `ati run` (including plan replay).
</Card>
<Card title="OpenAPI stock research workflow" href="/openapi-stock-research">
End-to-end Finnhub recipe using `ati assist` plus chained `ati run` calls.
</Card>
</CardGroup>
