> ## 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.

# Getting Started

> Clone, run in the webview, and get a chat answering on a simulator.

The shortest path from clone to a running chat.

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
git clone https://github.com/MervinPraison/PraisonAI
cd PraisonAI/src/praisonai-mobile
npm install && npm run check
```

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    Clone[📦 Clone] --> Install[⚙️ npm install]
    Install --> Check[✅ npm run check]
    Check --> Build[🪟 npm run build]
    Build --> Device[📱 Simulator]

    classDef step fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef start fill:#8B0000,stroke:#7C90A0,color:#fff
    classDef done fill:#10B981,stroke:#7C90A0,color:#fff

    class Clone start
    class Install,Check,Build step
    class Device done
```

## Quick Start

**1. Install**

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
cd PraisonAI/src/praisonai-mobile
npm install
```

The package is private and needs Node `>=22.18`. Runtime dependencies load through adapters, so there is no runtime `dependencies` block.

**2. Run the gates**

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
npm run typecheck
npm run test
npm run check
```

`check` chains `typecheck`, `boundaries`, and `test`.

**3. Build the webview bundle**

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
npm run build
```

***

## Package Scripts

Every script the package ships, from `package.json`.

| Script | What it does |
| - | - |
| `typecheck` | `tsc -p tsconfig.json`. |
| `test` | Runs the `node --test` suite across every layer. |
| `boundaries` | Fails the build if an import crosses a seam. |
| `build` | Builds the webview bundle. |
| `test:bundle` | Runs the bundle-gate's own suite. |
| `check` | `typecheck` + `boundaries` + `test`. |
| `check:upstream` | Checks the real `Agent` still satisfies the port. |
| `build:webview` | Same as `build`. |

***

## Platform projects are already committed

The repo ships committed iOS and Android platform projects at `src-tauri/gen/apple` and `src-tauri/gen/android`, so nothing extra is needed to *build* the mobile apps — CI proves both build on every PR touching `src/praisonai-mobile/**`. See [Platform Builds](https://praison.ai/docs/features/mobile/platform-builds.md) for the workflow and the local build commands.

***

## Swap the Engine

Which engine answers is a setting, read at boot in `app/src/main.ts`. Change one value.

```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import { appEngines, defaultEngineIdFor } from "praisonai-mobile/app/main";

const booted = await createApp({
  storage: platform.storage,
  secrets: platform.secrets,
  time: platform.time,
  shell: platform.shell,
  engines: (persistence, settings, onIgnored) =>
    appEngines({ settings, http: platform.http, persistence, onIgnored }),
  settingDefs: SETTING_DEFS,
  // The first-launch default when no engineId is persisted. Chosen by
  // platform kind: `praisonai-ts` on tauri (a device), `remote-http` on
  // web (see Engines). A persisted engineId always wins over this.
  engineId: defaultEngineIdFor(platform.kind),
  onPublish: publish,
  now: () => Date.now(),
  newChatId: () => globalThis.crypto.randomUUID(),
});
```

`engineId` is no longer a literal — `defaultEngineIdFor(platform.kind)` picks it by platform kind: `"tauri"` (a device, including desktop Tauri) defaults to the in-process `praisonai-ts`, `"web"` to `remote-http` (see [Engines → First-Launch Default](https://praison.ai/docs/features/mobile/engines.md#first-launch-default) for why). A persisted `engineId` still wins over this default.

> [!NOTE]
>
> `mount(deps)` also takes an optional `locales?: readonly string[]` alongside `now` and `newChatId`. Injecting it makes locale-dependent layout deterministic in a test; when omitted it defaults to the host's `navigator.languages`. See [i18n & A11y → `MountDeps.locales`](https://praison.ai/docs/features/mobile/i18n-and-a11y#mountdeps-locales-injectable-deterministic).
>
> ```ts theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
> import { mount } from "praisonai-mobile/app/main";
>
> await mount({
>   root,
>   now: () => Date.now(),
>   newChatId: () => globalThis.crypto.randomUUID(),
>   locales: ["ar", "en"], // optional; defaults to navigator.languages
> });
> ```

The in-process engine's factory is supplied by `appEngines`, so `praisonai-ts` is on offer in real builds, and the picker (`SETTING_DEFS.engineId.choices`) now lists **both** `remote-http` and `praisonai-ts`. The shipping build can construct the in-process engine because its module ships as a lazy chunk fetched through `import("praisonai/mobile")` — so offering it in the picker is offering a choice the build can honour, not a brick.

> [!NOTE]
>
> The app runs on a device today with the in-process engine: it boots into `praisonai-ts` and reaches a first turn. The remaining gap is not the module — that ships — but the **API-key setting**, which the registry does not yet declare, so a real first turn fails **recoverably** at the model layer (a named `error` row, not a crash). A key setting is a tracked follow-up. See [Engines → The known API-key gap](https://praison.ai/docs/features/mobile/engines.md#the-known-api-key-gap).

***

## First launch

The first screen tells a new user what the app is and that it needs a key — before any message is sent.

**1. Install and open**

On a fresh install, the chat screen shows the **"Add an API key to start"** panel, a one-sentence explanation of what the app does, and an **"Open settings"** button — not a blank screen and not a raw SDK error. See [Empty Chat](https://praison.ai/docs/features/mobile/empty-chat.md).

**2. Paste a key and return to Chat**

After pasting an OpenAI key in [API Keys](https://praison.ai/docs/features/mobile/api-keys.md) and returning to Chat, the panel switches to the welcome copy — **"Ask something to begin."** and one line saying what the app does. The chat is ready.

***

## Best Practices

> [accordion] Run npm run check before every commit
>
> The bundle gate catches Node builtins and top-level `process.env` that pass in Node but blank the webview on device.

> [accordion] Use remote-http for the desktop dev flow
>
> The first-launch default on a device is now the in-process engine (`praisonai-ts`). For iterating on a laptop, switch to `remote-http` in Settings: it speaks the full 11-event vocabulary against a running desktop engine, so you see tool rows and approvals while you work. The persisted choice wins, so the switch sticks.

> [accordion] Keep the engine choice in settings
>
> `engineId` is read from settings at boot, so users switch runtimes without a rebuild.

***

## Related

> [card] [Agent Engine Port](https://praison.ai/docs/features/mobile/engines.md)
>
> The three shipped engines and the conformance harness.

> [card] [The Two Seams](https://praison.ai/docs/features/mobile/architecture.md)
>
> Why the boundaries are enforced by build.

> [card] [Shipping to Stores](https://praison.ai/docs/features/mobile/shipping-to-stores.md)
>
> The CSP, WebView floor, and monotonic versioning story.

> [card] [Empty Chat](https://praison.ai/docs/features/mobile/empty-chat.md)
>
> The first-launch panel and the four rules behind it.

**Next:** Ready to ship to a store? See [Shipping to iOS and Android](https://praison.ai/docs/features/mobile/shipping-to-stores.md) for the CSP, WebView floor, and monotonic versioning story.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.