> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ziro-agent.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Installation

> Prerequisites, dependency groups, model pre-caching, dev and production storage modes, and where Ziro keeps its state.

## Prerequisites

| Requirement                      | Needed for         | Notes                                                     |
| -------------------------------- | ------------------ | --------------------------------------------------------- |
| Python 3.12+                     | Everything         | The runtime targets 3.12 and above                        |
| [uv](https://docs.astral.sh/uv/) | Dependency install | Drives the workspace and its optional groups              |
| A model provider API key         | Every model call   | OpenRouter, Anthropic, OpenAI, or a custom endpoint       |
| Docker                           | Optional           | PostgreSQL + pgvector, SearXNG, and the PDF sandbox image |

## Choose an install path

<Tabs>
  <Tab title="Install script">
    The recommended way in. The script creates an isolated environment under
    `~/.ziro/venv`, installs Ziro into it, and puts a `ziro` command on your PATH.
    It needs nothing but Python 3.11.9 or newer: no pipx, no uv, no admin rights.

    <CodeGroup>
      ```bash macOS and Linux theme={"theme":{"light":"github-light","dark":"github-dark"}}
      curl -fsSL https://ziro-agent.com/install.sh | bash
      ```

      ```powershell Windows theme={"theme":{"light":"github-light","dark":"github-dark"}}
      iwr -useb https://ziro-agent.com/install.ps1 | iex
      ```
    </CodeGroup>

    Run `ziro` when it finishes. The first launch walks you through setup.

    <Tip>
      Piping a script from the internet into a shell is worth being careful about.
      Read it first: both are served as plain text over HTTPS at
      [ziro-agent.com/install.sh](https://ziro-agent.com/install.sh) and
      [ziro-agent.com/install.ps1](https://ziro-agent.com/install.ps1).
    </Tip>

    Both scripts accept the same options:

    | Option          | Effect                                                                |
    | --------------- | --------------------------------------------------------------------- |
    | `--version <v>` | Install a specific version instead of the latest                      |
    | `--uninstall`   | Remove the environment and the shims. Your settings and data are kept |
    | `--help`        | Print usage (`Get-Help` on the PowerShell script)                     |

    Configuration is by environment variable, so the options survive being piped
    to a shell: `ZIRO_HOME`, `ZIRO_BIN_DIR`, `ZIRO_VERSION`, `ZIRO_PYTHON`,
    `ZIRO_INDEX_URL`, `ZIRO_EXTRA_INDEX`, and on Windows `ZIRO_NO_MODIFY_PATH`.
  </Tab>

  <Tab title="pip">
    Ziro is a normal Python package, so any installer that makes isolated
    environments works. Point it at the release index:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    pipx install --index-url https://test.pypi.org/simple/ \
      --pip-args="--extra-index-url https://pypi.org/simple/" ziro
    ```

    The two indexes are needed because Ziro publishes to TestPyPI today while its
    third-party dependencies resolve from prod PyPI. This is the same pair
    `ziro upgrade` uses.
  </Tab>
</Tabs>

### What the install script does

<Steps>
  <Step title="Finds a suitable Python">
    Checks the `py` launcher and the usual interpreter names for one at 3.11.9 or
    newer, and stops with a clear message rather than failing deep inside pip.
    Set `ZIRO_PYTHON` to force a specific interpreter.
  </Step>

  <Step title="Creates an isolated environment">
    A plain `venv` at `~/.ziro/venv`. Nothing is installed into your system or
    user site-packages, and an existing environment is reused and upgraded in
    place.
  </Step>

  <Step title="Installs from the release index">
    Ziro from TestPyPI, dependencies from prod PyPI.
  </Step>

  <Step title="Puts a command on your PATH">
    Small wrapper scripts for `ziro`, `ziro-once`, and `manage-agents` in
    `~/.local/bin` (macOS and Linux) or `%LOCALAPPDATA%\Programs\ziro\bin`
    (Windows). Only those three are exposed; the environment's own `python` and
    `pip` stay off your PATH. On Windows the directory is added to your user PATH
    and to the current session. On macOS and Linux the script prints the line to
    add if the directory is not already there.
  </Step>

  <Step title="Verifies">
    Confirms the package reports a version and that the `ziro` command exists
    before claiming success.
  </Step>
</Steps>

<Tip>
  Re-running the script upgrades an existing install in place. `ziro upgrade` does
  the same thing from inside the app, and works here because pip lives in the
  environment the script creates.
</Tip>

`uv sync` installs the runtime plus the local guardrail backends, Presidio for PII
detection and Llama Guard for content safety, so guardrails work without any cloud
service.

### Optional dependency groups

<Tabs>
  <Tab title="Local voice">
    Push-to-talk speech in and out, running entirely on your machine: faster-whisper
    for speech-to-text and Piper for text-to-speech. No cloud key required.

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    uv sync --group voice-local
    ```

    Voice is off by default and must also be enabled in the agent's
    `voice_policy.yaml`. Launch with `python -m app.main --user <USER_ID> --voice`, or
    toggle it in-session with `/voice`. See [Voice](/guides/voice).
  </Tab>

  <Tab title="Dev extras">
    Some tooling is only needed for development. The ASCII graph renderer, for
    instance, wants `grandalf`:

    ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
    uv sync --group dev
    python -m app.cli.show_graph
    ```

    `show_graph` also emits Mermaid and PNG via `--format mermaid` or `--format png`
    (PNG needs the graphviz system package).
  </Tab>
</Tabs>

## Pre-cache the local models

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
python -m app.cli.startup
```

This downloads only what is missing:

| Asset                         | Used by                                | Why it matters                                              |
| ----------------------------- | -------------------------------------- | ----------------------------------------------------------- |
| `all-MiniLM-L6-v2` embeddings | RAG, skills search, tool discovery     | Roughly 20 seconds cold on first use, mostly network checks |
| spaCy model                   | The Presidio PII guardrail backend     | Presidio cannot run without it                              |
| Llama Guard 3 1B GGUF         | The Llama Guard content-safety backend | Large file; you do not want it downloading mid-conversation |
| Default Piper voice           | Local text-to-speech                   | Only fetched when the `voice-local` group is installed      |

<Tip>
  Run this before your first launch. Once the embeddings model is cached on disk, Ziro
  sets Hugging Face to offline mode at import, which removes roughly nine seconds of
  Hub metadata checks from every startup. A machine with nothing cached stays online
  and downloads once.
</Tip>

Embedding warmup is deliberately kept off the startup critical path: the UI appears
before the model is ready, and any consumer that needs it waits for the real model
rather than falling back to a degraded result.

## Storage modes

The storage backend is selected by one environment variable. Set `DATABASE_URL` and
Ziro runs in production mode; leave it unset and it runs entirely on local files.

| Mode | Trigger            | Long-term memory                     | Checkpoints                                  | Vectors  |
| ---- | ------------------ | ------------------------------------ | -------------------------------------------- | -------- |
| Dev  | no `DATABASE_URL`  | `SqliteStore` (`./data/memories.db`) | `AsyncSqliteSaver` (`./data/checkpoints.db`) | FAISS    |
| Prod | `DATABASE_URL` set | `PostgresStore`                      | `AsyncPostgresSaver`                         | pgvector |

### Dev mode

Nothing to do. Dev mode needs no infrastructure. SQLite files and a FAISS index
under `./data/` are created on demand.

### Production mode

Start PostgreSQL with the pgvector extension:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
docker compose up -d
```

Then point Ziro at it by setting `DATABASE_URL`, either in `~/.ziro/.env` directly,
or through the wizard's **Advanced** section (`ziro setup`) or the in-session
`/settings` command. On the next build, the store, the checkpointer, and the vector
store all switch over. See [Environment variables](/reference/environment).

<Note>
  The two modes are not synchronized. Threads and memories written in dev mode live in
  SQLite and are not visible after switching to PostgreSQL, and vice versa.
</Note>

## Where state lives

Ziro keeps configuration and per-user state outside the repository, so an installed
package behaves the same as a source checkout.

| Path                            | Contents                                                                    |
| ------------------------------- | --------------------------------------------------------------------------- |
| `~/.ziro/.env`                  | API key, default model, Langfuse keys, `DATABASE_URL`                       |
| `~/.ziro/users.json`            | The users registry, most-recently-used order, and the last user and flavour |
| `<DATA_DIR>/threads.json`       | Per-workspace thread metadata: user, agent, flavour, title, timestamps      |
| `~/.ziro/projects/<key>/`       | Per-project memory, keyed by a stable workspace key                         |
| `~/.ziro/agents/<id>/`          | Your overrides for a bundled agent, or an agent you added yourself          |
| `~/.ziro/custom_providers.json` | Custom LLM provider labels (any OpenAI- or Anthropic-compatible endpoint)   |
| `~/.ziro/plugins/`              | Installed plugins at user scope                                             |
| `./data/`                       | SQLite databases, the FAISS index, the model catalog cache, UI preferences  |

Checkpoints remain the source of truth for conversation content; `threads.json` only
carries metadata. The workspace key is `<basename>-<sha256 of the real path, first 8
chars>`, so two same-named repositories in different directories never collide.

### Config layering

Agent configuration resolves **most-specific-first** across three roots:

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
<project>/.ziro/agents/<id>/  →  ~/.ziro/agents/<id>/  →  the bundled package
```

That means you configure an installed Ziro by dropping files under
`~/.ziro/agents/<id>/` without ever editing the package. A file missing at every
layer degrades to built-in defaults. See [Configuration](/guides/configuration).

<Warning>
  Files that can execute or widen access (`permissions.yaml`, `mcp_servers.yaml`,
  `hooks.yaml`, `plugin_config.yaml`) are skipped when they come from an **untrusted**
  project `.ziro` directory. Folder trust is content-hashed, so editing one of these
  files revokes trust until you confirm it again.
</Warning>

## Re-run the wizard

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
ziro setup
```

This re-opens the first-run wizard with every field prefilled, even when a key is
already configured. Use it to re-key, switch the default model or provider, change
theme, or add a custom provider. The same sections are reachable in-session with
`/settings`.

## Upgrade

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
ziro upgrade
```

Upgrades the installed `ziro` distribution from its release index. The index host is
configurable with `ZIRO_PYPI_HOST` and defaults to `test.pypi.org`.

## Optional extras

| Extra                 | Command                            | What it gives you                                                                                                                                                                                                         |
| --------------------- | ---------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SearXNG               | `docker compose up -d searxng`     | A self-hosted backend for `web_search`. Set `provider: searxng` and `searxng_url` in the agent's `websearch_policy.yaml`. The default backend is keyless DuckDuckGo, so this is only needed if you want your own instance |
| PDF sandbox image     | `docker compose build pdf-sandbox` | Builds `ziro-pdf:latest`, the container the `researcher_docker` agent runs `run_shell` inside                                                                                                                             |
| PostgreSQL + pgvector | `docker compose up -d`             | Production storage backend                                                                                                                                                                                                |

<Note>
  There is no automatic fallback between web-search backends. If you configure
  `searxng` and the container is not running, the tool returns a readable error rather
  than silently switching to DuckDuckGo.
</Note>

## Index your own content

Two indexers extend what the agent can retrieve:

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
python -m ziro.rag.indexer ./my-docs/   # index a directory, a .txt, or a .pdf
python -m skills.loader                 # index every SKILL.md under ./skills/
python -m ziro.tools.indexer            # re-index tool descriptions
```

<Note>
  Use `python -m ziro.<module>` for the indexers. The `app.*` import alias redirects
  normal imports to their `ziro.*` equivalents, but `python -m` needs the real module
  path.
</Note>

## Verify the install

```bash theme={"theme":{"light":"github-light","dark":"github-dark"}}
python -m app.cli.manage_agents list
```

This lists every agent with its on/off state and does not need a model call. It is a quick
confirmation that the package, the agent folders, and the config layers all resolve.

## Next steps

<Columns cols={2}>
  <Card title="Quickstart" icon="rocket" href="/quickstart">
    Run the wizard and hold your first conversation.
  </Card>

  <Card title="Environment variables" icon="key" href="/reference/environment">
    Every variable Ziro reads and what it changes.
  </Card>

  <Card title="Providers" icon="plug" href="/guides/providers">
    OpenRouter, Anthropic, OpenAI, and custom endpoints.
  </Card>
</Columns>
