Documentation
Everything you need to use ai effectively. From your first prompt to advanced policy configuration.
Overview
ai is a single-binary Rust CLI agent. ai run "PROMPT" performs a one-shot request (or read the prompt from stdin); bare ai starts an interactive session. The response streams to stdout, while thinking and tool calls go to stderr, so results pipe cleanly into other commands.
The model starts with only what you give it — no filesystem, no network, no shell. Every capability beyond a plain answer is opt-in via CLI flags or a declarative policy file. Two exceptions are on by default: local semantic memory (disable with --no-memory) and session persistence (disable with --no-session).
api_base + flavor, and the full models.dev catalog.
Quickstart
Run ai setup once to pick a provider and model. After that, ai (no arguments) drops you into an interactive session that remembers the conversation and can resume it later.
Commands & Flags
Value flags accept either --flag value or --flag=value.
Commands
| Command | Description |
|---|---|
ai | Start an interactive session (the default with no subcommand). |
ai run PROMPT | One-shot request. If PROMPT is absent, read it from stdin (cat f | ai run). |
ai session list | List saved sessions (the current one is marked *). |
ai session delete NAME | Delete a session by name. |
ai memory list | List stored memory facts. |
ai memory search QUERY | Semantic search across memory and past transcripts, with match scores. |
ai skills list | List discovered skills with their origin (user/AI) and path. |
ai skills delete NAME | Delete a skill's folder (SKILL.md plus bundled files). |
ai dream [--jobs N] | Run memory maintenance (see Memory Maintenance). |
ai setup [FILE] | Interactive provider/model wizard plus AI config editing (see Setup). |
ai completions SHELL | Print a shell completion script (bash, zsh, fish, …) and exit. |
Global flags
| Flag | Description |
|---|---|
-c, --config FILE | Load configuration from FILE (default ~/.config/ai/config.yaml). |
--provider PROVIDER, --model MODEL | Override the provider or model for this run. |
--system PROMPT | Override the system prompt for this invocation. |
-s, --session-name NAME | Name the session, or continue the most recent session with that name (an undated NAME matches across dates). |
--no-session | Do not read or write a session; run stateless. |
--no-memory | Disable persistent memory for this run. |
-r, --read PATH | Allow read-only access to PATH. Repeatable; supports globs. |
-w, --write PATH | Allow read/write access to PATH. Repeatable; also grants read. |
-x, --execute PATTERN | Allow execution of PATTERN (comma-separated names). Repeatable. |
--web | Allow all web access (fetch and search). |
--web-fetch PATTERN, --web-search PATTERN | Narrow web access to matching URLs / queries. Repeatable. |
--proxy URL | Route web requests through a proxy (http://… or socks5h://…). |
-p, --policy FILE | Load access policy from FILE. CLI rules take precedence. |
-i, --ask | When a tool needs a resource not covered by any allow rule, ask you to approve or deny. |
-t, --tool URL | Connect to an MCP tool server. Repeatable. |
-X, --container [IMAGE] | Run external commands in a container (default debian:stable-slim). |
--container-runtime RUNTIME, --no-container | Choose auto/docker/podman, or ignore a configured container. |
-y, --yolo | Grant all permissions. Dangerous. |
--max-tokens N, --max-turns N | Cap output tokens, or agent turns (tool rounds; default 100). |
--thinking [TOKENS] | Enable extended reasoning (default 16,000 tokens). |
-v/--verbose, -q/--quiet, --no-color | Debug logging, quieter output, and disabled ANSI colors. |
Examples
Configuration
Config is YAML at ~/.config/ai/config.yaml (override with -c). Every field is optional; CLI flags and env vars override config values. Unknown keys warn; ai setup rejects them.
Environment Variables
| Variable | Provider |
|---|---|
OPENAI_API_KEY | OpenAI |
ANTHROPIC_API_KEY | Anthropic |
OLLAMA_API_KEY | Ollama |
GROQ_API_KEY | Groq |
GEMINI_API_KEY | Google Gemini |
DEEPSEEK_API_KEY | DeepSeek |
MISTRAL_API_KEY | Mistral |
OPENROUTER_API_KEY | OpenRouter |
XAI_API_KEY | xAI |
BRAVE_API_KEY, TAVILY_API_KEY, EXA_API_KEY, SERPER_API_KEY | Web search providers |
HTTP_PROXY, HTTPS_PROXY, ALL_PROXY, NO_PROXY | Web request proxy |
An API key may be a literal or env:VAR_NAME; env: is preferred so secrets stay out of the file.
Field Reference
| Field | Default | Description |
|---|---|---|
provider | openai | Provider id (built-in or any models.dev id) |
flavor | derived | Request shape: openai or anthropic |
api_key | — | Key or env:VAR reference |
api_base | provider default | Base URL (required for custom endpoints) |
model | gpt-4o | Model name |
system_prompt | built-in | Default system prompt |
max_tokens, thinking | — | Output cap; extended-thinking budget |
context_window | provider | Context size for the usage indicator |
session_dir | <data-dir>/ai/sessions | Session storage |
policy | — | Policy file with allow/deny rules |
memory | <data-dir>/ai/memory.db | Persistent memory database (SQLite) |
embedding_model | multilingual-e5-small | Local embedding model for semantic search |
memory_max_distance | 0.175 | Cosine distance cutoff for injected hits |
skills.dir | <data-dir>/ai/skills | Where SKILL.md files are discovered |
skills.auto_create, skills.min_tuples | false, 10 | Let ai dream author skills; review threshold |
dream.auto, dream.jobs | false, 4 | Run maintenance at session end; parallel requests |
proxy | env | Proxy URL for web requests |
search.providers | DuckDuckGo→Google→Bing | Ordered web-search backends |
container.default_image, container.runtime, container.network | —, auto, policy | Container isolation settings |
mcp.servers | — | External MCP servers { url, name? } |
Providers
ai speaks the OpenAI and Anthropic APIs natively. Any other provider works by setting api_base to its compatible endpoint and choosing the matching flavor (openai or anthropic). Built-ins cover OpenAI, Anthropic, Ollama, Groq, DeepSeek, Google Gemini, Mistral, OpenRouter, xAI, and llamafile; ai setup can also browse the full models.dev catalog.
Example configs
Access Policy
The policy engine controls what files, commands, and web resources the model can access. Rules are evaluated first-match: the first matching Allow or Deny rule wins. CLI flags (-r, -w, -x, --web) are prepended to policy-file rules and take precedence.
Actions
| Action | Covers |
|---|---|
read | read_file, list_dir, search_content, find_files, file_info, file_view |
write | write_file, replace_in_file, delete_file, create_directory, move_file, copy_file |
execute | execute (external commands only) |
web-fetch | web_fetch, download_file, browser tools |
web-search | web_search |
Policy File Syntax
One rule per line. # starts a comment.
Path Matching
Path patterns support glob wildcards and are segment-aware: /tmp matches /tmp/foo.txt but not /tmpfile. Paths are resolved (symlinks included) before the policy is consulted, so a deny inside an allowed tree is honored. ~ is expanded.
Execute Patterns
The execute tool always runs. 150+ built-in commands (echo, cat, grep, sed, git, curl, …) run inside a virtual bash interpreter (bashkit) and are governed by filesystem read/write policy, not execute permissions. External commands (e.g. cargo, npm, python) are checked against the execute allowlist. See Filesystem & Containers for how containers change this.
Interactive Ask Mode
With -i/--ask, an unmatched action prompts you and remembers the choice for the session: allow once, remember the exact target, remember its directory, or deny.
Allow read for /home/user/project/src/auth.rs? [y=once, a=always, r=this dir, N=deny]
Filesystem & Containers
Every user-supplied path is resolved and authorized in one checked layer before the operation, so deny rules inside an allowed tree hold and symlink escapes are blocked.
External commands run through bashkit. In-process builtins run without a grant; external commands require -x unless a container is active. When a container is configured (-X/--container[=IMAGE], default debian:stable-slim, or container.default_image), a single session container starts at agent startup and every execute command runs inside it:
- Policy read roots are bind-mounted read-only, write roots read-write; the host filesystem is otherwise invisible.
- The container gets no network unless web access is granted (
container.network: policy). --no-containerforces host execution;--container-runtimepicks docker/podman.--yolodoes not disable the container — it relaxes tool policy only. Whole-filesystem (**) grants are not mountable and are warned about.
Sessions
Sessions persist the full message log (tool calls and results included) to JSON. Each session records its provider and model; resuming under a different pair forks a fresh session instead of replaying an incompatible history.
ai run and bare ai automatically continue the newest session when it is less than 60 minutes old and its provider/model match; otherwise a new session starts. One-off sessions are saved only after a successful run. Pass --no-session to run stateless.
In-Session Commands
| Command | Action |
|---|---|
/exit, /quit | Exit the session |
/clear | Clear all messages in the session |
/compact | Summarize the conversation and replace history with the summary |
/session | Print the current session name |
/help | Show slash commands — and for anything else about ai, just ask |
[NN%], colored by tier.
Memory
Memory is enabled by default and stored in a SQLite database (memory.db). Facts and past exchanges are embedded locally (ONNX via fastembed) and searched with sqlite-vec, so nothing leaves your machine. Relevant hits and transcript excerpts are injected per message, each shown with a cosine match score.
Four tools back this: memory_add (text, optional tags, origin), memory_search, memory_get (fetch one entry by key), and memory_delete. Tuning keys: embedding_model (default multilingual-e5-small) and memory_max_distance (lower is stricter). Disable with --no-memory.
Memory Maintenance
ai dream keeps memory healthy. It runs over a work pool (--jobs N, config dream.jobs, default 4):
- extract — distill durable facts from unprocessed transcript tuples.
- skills — when
skills.auto_createis true, review sessions with at leastskills.min_tuplesunreviewed exchanges and author or update skills. - prune — delete processed transcripts older than 7 days (skill-pending sessions are held back).
- judge — review entries unused and unjudged for 30 days and delete obsolete ones.
An interactive session offers to run maintenance at exit when the backlog is large, and dream.auto: true runs it automatically at the end of every saved session.
Skills
A skill is a SKILL.md file (YAML front matter with name and description) under the skills directory (skills.dir, default <data-dir>/ai/skills). Skills are listed in the system prompt, and the model loads one on demand with the load_skill tool, which returns the full body plus the absolute paths of any bundled files (scripts, references). The skills folder is granted read access automatically.
With skills.auto_create: true, ai dream can author skills from past sessions. AI-created skills are tagged origin: ai and are the only ones the agent may modify or delete; they appear as (AI-created) in the prompt. Inspect and remove them with ai skills list and ai skills delete NAME.
Web & Search
Web access is off unless granted: --web for everything, or --web-fetch URL / --web-search QUERY for narrower grants. web_fetch retrieves a page and converts it to readable text; web_search uses an ordered ladder of providers configured in search.providers:
- Keyed APIs —
brave,tavily,exa,serper. An omittedapi_keyfalls back toBRAVE_API_KEY/TAVILY_API_KEY/EXA_API_KEY/SERPER_API_KEY. - SearXNG — a normal entry that needs a
url(queried via its JSON API). - Keyless scrapers —
duckduckgo,google,bing.
The first provider that succeeds wins; a listed provider missing credentials is skipped with a warning. --probe-web QUERY tests the configured providers.
BRAVE_API_KEY (or api_key: env:BRAVE_API_KEY), and add - name: brave to search.providers.
MCP Tool Servers
Connect Model Context Protocol servers to extend ai with external tools — IDE integrations, database agents, API gateways. Use --tool URL for one run, or declare servers in config:
Config servers and --tool URLs are merged and deduplicated. A config server that fails to connect is skipped with a warning; a --tool failure aborts startup.
Built-in Tools
30+ built-in tools are conditionally registered based on active policy rules.
Filesystem
read_file
Read file contents. Supports offset and limit for pagination.
write_file
Create or overwrite a file. Creates parent directories automatically.
list_dir
List directory contents with type prefixes (d directory, l symlink, f file).
replace_in_file
Surgical string replacement. Old string must match exactly once.
delete_file
Delete a file or directory. Directories require recursive: true.
create_directory
Create a directory and all parent directories (like mkdir -p).
file_info
File or directory metadata: size, permissions, modification time, and type.
move_file
Move or rename a file or directory. Checks write permission on source and destination.
copy_file
Copy a file. Checks read on source, write on destination.
file_view
Extract readable text from rich documents (PDF, DOCX, XLSX, PPTX, HTML, CSV, images, ZIP) via anydoc, returned as Markdown.
Execution
execute
Run a shell command. 150+ built-in commands run in-process via bashkit — no forking; external commands fork-exec and need an execute grant (or a container). Filesystem access is governed by read/write policy.
Search
search_content
Regex search across files. Skips hidden directories and binaries. Max 500 matches, 1 MB per file.
find_files
Glob-based file search. Results sorted alphabetically, truncated at 500.
Web
web_fetch
Fetch a URL and return text, markdown, or HTML. Max 5 MB response.
web_search
Search via the configured provider ladder, with a stealth-browser fallback. Returns titles, URLs, and snippets. Max 20 results.
download_file
Download a URL to disk. Max 5 MB. Requires write permission on the destination.
Browser
browser_navigate
Navigate the headless browser to a URL. Returns the page title and content size. Requires web-fetch permission.
browser_click
Click an element by CSS selector, navigating first if a URL is given.
browser_get_content
Get the full page content in markdown or raw HTML (after a navigate).
browser_get_element
Extract a DOM element by CSS selector in markdown or raw HTML.
browser_evaluate
Execute JavaScript on the current page and return the result as JSON.
Memory & other
memory_add
Store a fact with optional tags and origin (user/agent). Returns a key. Upserts near-duplicates.
memory_search
Semantic search over memory and past transcripts. Returns best matches with keys and scores.
memory_get
Fetch one memory entry by key, with its full text, tags, origin, and source.
memory_delete
Delete a memory entry by key.
load_skill
Load a skill's instructions by name, plus the absolute paths of its bundled files.
manual
Look up this documentation by topic (commands, flags, configuration, behavior).
get_current_time
Return the current date and time.
exit_program
End an interactive session (or ai setup) when the user asks to quit.
Inline Help
The agent has a manual tool that serves this documentation, the example config, and the generated CLI help. Ask it questions about ai itself — flags, config keys, or how a feature works — and it answers from the manual rather than guessing.
In an interactive session, /help lists the slash commands and reminds you that you can just ask.
Output & Thinking
Assistant markdown is rendered to ANSI on a terminal and left as raw markdown when piped. A first-token spinner appears while waiting. Use --no-color (or NO_COLOR) to disable styling.
Thinking tokens are counted in the token stats, shown as (in, thinking, out).
Setup
ai setup has two phases. First a deterministic wizard: reuse an existing config or detected credentials, otherwise pick a provider and model — browsing the models.dev catalog or entering a custom URL — and confirm with a small connection test. Then an AI conversation edits the rest of the config, saving through a sandboxed, approval-gated tool. The API key is never sent to the model, and an existing config is backed up to config.yaml.bak.
Prefer api_key: env:VAR_NAME so keys stay out of the file. Afterwards, ai is ready to use.