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

# First-Run Provisioning

> How the Desktop app installs its own Python runtime on first launch

The first time you launch PraisonAI Desktop, it installs its own Python runtime and the `praisonaiagents` package into your user data folder — no terminal, no `pip`.

On later launches, the app compares a record of what it installed against the requirement shipped with the current build. If a fix in `praisonaiagents` raised the floor, or a new package was added, the app re-runs the install step once — the tray reads `Engine: updating…` while it runs — and starts the engine against the up-to-date venv. This is why raising the pin in one release actually reaches you on the next launch, instead of only reaching brand-new installs.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

agent = Agent(
    name="Assistant",
    instructions="You are a helpful assistant.",
)
# The Desktop app provisions the environment that runs this agent for you.
agent.start("Hello")
```

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    Uv[⬇️ Fetch uv] --> Py[🐍 Install Python 3.12]
    Py --> Venv[📦 Create environment]
    Venv --> Agents[✅ Install PraisonAI]

    classDef fetch fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef py fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef venv fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef done fill:#10B981,stroke:#7C90A0,color:#fff

    class Uv fetch
    class Py py
    class Venv venv
    class Agents done
```

## Quick Start

<Steps>
  <Step title="Launch the app">
    On a clean machine the app opens straight onto the first-run screen instead of the chat.
  </Step>

  <Step title="Watch the four stages">
    Each stage flips from pending to running to done as the runtime is built.
  </Step>

  <Step title="Start chatting">
    When the last stage completes, the window switches to chat — the environment is ready.
  </Step>
</Steps>

***

## How It Works

The app locates or fetches `uv`, has it install a pinned CPython, creates a venv in your data directory, then installs the engine's dependencies into it.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant You as 👤 You
    participant App as 🖥️ App
    participant Uv as ⬇️ uv
    participant Venv as 📦 venv

    You->>App: first launch
    App->>Uv: locate or fetch installer
    App->>Uv: install Python 3.12
    Uv->>Venv: create environment
    App->>Venv: install praisonaiagents
    Venv-->>You: ready to chat
```

The runtime is pinned, not "latest": the app installs **Python 3.12** and a floor of **`praisonaiagents>=1.7.2`** so a first run cannot land on a bad interpreter or a broken release.

<Note>
  On first launch (or any launch where setup is still needed), the app briefly forces the **Chat** view while the async engine health check runs. This prevents a saved **Train** view from hiding the setup wizard behind its CSS (`body.training #thread { display: none }`). The switch is not persisted, and as soon as setup completes the app re-applies your saved view **in the same session** — so a deliberate Train choice returns the instant the engine is ready, with no relaunch. Introduced in PraisonAI [#4471](https://github.com/MervinPraison/PraisonAI/pull/4471); the same-session restore was added in [#4623](https://github.com/MervinPraison/PraisonAI/pull/4623). Both close [#4441](https://github.com/MervinPraison/PraisonAI/issues/4441).
</Note>

***

## Keeping the venv current

The venv is provisioned once, but its package set is not frozen. Each launch writes a small `.praisonai-packages` stamp inside the venv recording which requirements are currently installed. When the shipped requirement changes — a raised floor for `praisonaiagents`, an added dependency — the stamp no longer matches, and the app re-runs the install step exactly once before the engine starts. `uv` is near-instant when nothing changed, so a no-drift launch is not slowed. On failure the engine still starts and the UI reports whatever version is actually installed, so a bad update never blocks chat; the stamp is only written on install success, so a failed update is retried on the next launch rather than silently recorded as done.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    Launch[🚀 Launch] --> Read{Stamp<br/>matches?}
    Read -->|yes| Start[✅ Engine: starting…]
    Read -->|no / missing| Update[⚙️ Engine: updating…]
    Update --> Install{Install ok?}
    Install -->|yes| Stamp[💾 Rewrite stamp]
    Install -->|no| Fallback[⚠️ Start with what is installed]
    Stamp --> Start
    Fallback --> Start

    classDef q fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef work fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef ok fill:#10B981,stroke:#7C90A0,color:#fff
    classDef bad fill:#8B0000,stroke:#7C90A0,color:#fff

    class Launch,Read,Install q
    class Update,Stamp work
    class Start ok
    class Fallback bad
```

***

## Event Stream

The first-run screen renders `provision` events from the `provision_engine` command. Each event carries an `id`, a `label`, a `state`, and an optional `detail`.

| Stage `id` | Label                    |
| ---------- | ------------------------ |
| `uv`       | Fetching the installer   |
| `python`   | Installing Python        |
| `venv`     | Creating the environment |
| `deps`     | Installing PraisonAI     |

Each stage moves through four states:

| `state`   | Meaning                                                     |
| --------- | ----------------------------------------------------------- |
| `pending` | Not started yet                                             |
| `running` | In progress                                                 |
| `done`    | Finished successfully                                       |
| `error`   | Failed — the **Retry** button re-invokes `provision_engine` |

<Note>
  The dependencies stage installs the whole set in **one** `uv pip install` invocation, so `uv` resolves the packages together rather than one at a time.
</Note>

***

## Where Things Go

The environment is built inside your user data folder, never inside the read-only app bundle.

The data folder itself is created when the app opens, ahead of provisioning. The venv and engine files land inside it when you click **Get started**.

| Path                                                               | Contents                             |
| ------------------------------------------------------------------ | ------------------------------------ |
| `<data folder>/venv/`                                              | The provisioned Python environment   |
| `<data folder>/venv/bin/python3` (`Scripts\python.exe` on Windows) | The interpreter the engine runs from |

The `<data folder>` is the per-platform data directory — see [Data & Privacy](/docs/features/desktop/data#where-data-lives) for each path. Override it with `PRAISONAI_DESKTOP_HOME` if you want the venv somewhere else.

<Note>
  Automatic reconciliation of a drifted venv landed in PraisonAI [#4670](https://github.com/MervinPraison/PraisonAI/pull/4670) (closes [#4668](https://github.com/MervinPraison/PraisonAI/issues/4668)). On earlier releases the venv was frozen at whatever the first-run set installed, so a library fix shipped in `praisonaiagents` never reached existing installs unless you deleted the venv by hand.
</Note>

***

## Bring Your Own Runtime

If you already have `praisonaiagents`, you can skip provisioning entirely.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    Q{Do you already have<br/>praisonaiagents?} -->|Yes| Own[Set PRAISONAI_PYTHON<br/>skip provisioning]
    Q -->|No| Manage[Let first-run finish<br/>app manages the runtime]

    classDef q fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef own fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef manage fill:#10B981,stroke:#7C90A0,color:#fff

    class Q q
    class Own own
    class Manage manage
```

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Point the engine at your own interpreter and skip the managed venv.
export PRAISONAI_PYTHON=/absolute/path/to/venv/bin/python3
```

Reconciliation only touches the venv the app provisioned itself (`<data folder>/venv`). If `PRAISONAI_PYTHON` points the engine at your own interpreter, the app never rewrites its packages — you own that environment and its versions.

***

## Best Practices

<AccordionGroup>
  <Accordion title="Let the first run finish uninterrupted">
    Provisioning downloads an interpreter and resolves packages. Leave the window open until all four stages are done — quitting mid-run leaves a partial venv.
  </Accordion>

  <Accordion title="Retry from where it stopped">
    If a stage errors (usually a network drop while fetching `uv` or Python), the **Retry** button re-runs `provision_engine` from the current stage rather than starting over.
  </Accordion>

  <Accordion title="Own the runtime for reproducible installs">
    Set `PRAISONAI_PYTHON` to a venv you control when you need a pinned, reproducible environment. The app then runs the engine against your interpreter and never provisions its own.
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Window & Lifecycle" icon="window-restore" href="/docs/features/desktop/window-and-lifecycle">
    Tray, single-instance, and orphan reclamation
  </Card>

  <Card title="Troubleshooting" icon="stethoscope" href="/docs/features/desktop/troubleshooting">
    Read the engine log and fix startup failures
  </Card>
</CardGroup>
