# Interactive installer

> TUI installer wizard: system checks, .env generation, LLM and search setup, SSL hardening, compose deploy, and admin password reset maintenance paths.

- Repository: vxcontrol/pentagi
- GitHub: https://github.com/vxcontrol/pentagi
- Human docs: https://grok-wiki.com/public/docs/vxcontrol-pentagi-eca0cf4de5f5
- Complete Markdown: https://grok-wiki.com/public/docs/vxcontrol-pentagi-eca0cf4de5f5/llms-full.txt

## Source Files

- `backend/cmd/installer/main.go`
- `backend/docs/installer.md`
- `backend/cmd/installer/wizard`
- `backend/cmd/installer/processor`
- `backend/cmd/installer/checker`
- `backend/cmd/installer/hardening`
- `README.md`

---

---
title: Interactive installer
description: TUI installer wizard — system checks, .env generation, LLM and search setup, SSL hardening, compose deploy, and admin password reset maintenance paths.
---

The interactive installer is a Terminal User Interface (TUI) wizard that configures and deploys PentAGI on a host with Docker. It creates or updates `.env`, runs system readiness checks, hardens default secrets, extracts compose overlays, applies Docker Compose stacks, and exposes maintenance operations (start/stop/update/purge and admin password reset).

Use this path when you want guided setup instead of hand-editing `.env` and composing services manually. Manual compose remains valid; the installer is the recommended operator path for first install and day-2 stack control.

## What the installer does

| Phase | Outcome |
| --- | --- |
| Bootstrap | Resolve `-e` env path, create `.env` from embedded template if missing, load dirty state under `.state/` |
| Migrate / sync | Rewrite legacy path vars; pull `HTTP(S)_PROXY` and Docker client env into `.env` when unset |
| System checks | Docker API/compose, worker Docker, CPU/memory/disk, network (including Docker Hub DNS), stack presence |
| Hardening | Replace known default secrets (Postgres, scraper, Langfuse, Neo4j, cookie salt) when volumes are not already present |
| Wizard | EULA, main menu configuration (LLM, search, tools, monitoring, server), commit via **Apply changes** or **Install** |
| Processor | Extract compose files, ensure Docker networks, `docker compose` lifecycle, worker image ops, password reset |

Stacks the processor can manage:

| Stack | Compose / role |
| --- | --- |
| `pentagi` | Core app (`docker-compose.yml`) |
| `graphiti` | Knowledge graph (`docker-compose-graphiti.yml`) |
| `langfuse` | LLM analytics (`docker-compose-langfuse.yml`) |
| `observability` | OTEL/Grafana stack (`docker-compose-observability.yml`) |
| `worker` | Worker / pentest images |
| `installer` | Self-update of the installer binary |
| `all` / `compose` | Aggregate operations |

## Prerequisites

- Docker Engine and Docker Compose available to the process (socket or remote `DOCKER_HOST`)
- Writable directory for the env file (default `.env` next to the installer)
- Network access for image pulls and optional update checks (`https://update.pentagi.com`); Docker Hub reachability is part of readiness
- Privilege to talk to Docker: run as root (`sudo ./installer`) or as a user in the `docker` group
- Rough resource floors used by readiness checks (scale with enabled optional stacks):
  - Memory base ~0.5 GB plus stack add-ons (Graphiti ~2 GB, Langfuse ~1.5 GB, Observability ~1.5 GB)
  - Disk from ~5 GB baseline up to ~25 GB when worker images are required

<Note>
Adding a user to the `docker` group is root-equivalent. Prefer `sudo ./installer` for production hosts.
</Note>

## Get and run

### Prebuilt binary

Platform archives (amd64/arm64) are published under `https://pentagi.com/downloads/{linux\|windows\|darwin}/{arch}/installer-latest.zip`.

<Steps>
  <Step title="Create a work directory">
    ```bash
    mkdir -p pentagi && cd pentagi
    ```
  </Step>
  <Step title="Download and extract">
    ```bash
    wget -O installer.zip https://pentagi.com/downloads/linux/amd64/installer-latest.zip
    unzip installer.zip
    ```
  </Step>
  <Step title="Run with Docker access">
    ```bash
    sudo ./installer
    # or: ./installer -e /path/to/.env
    # or: ./installer -v
    ```
  </Step>
</Steps>

### Build from source

From `backend/`:

```bash
go build -o ../build/installer ./cmd/installer
../build/installer -e ../.env
```

Do not `go run` the TUI in the same session you develop in; build a binary and run it separately so the terminal is not corrupted.

### CLI flags

<ParamField body="-e" type="string" default=".env">
Path to the environment file. Absolute path is resolved; missing parent dirs are created; a missing file is seeded from the embedded `.env` template with mode `0600`.
</ParamField>

<ParamField body="-v" type="boolean" default="false">
Print binary version and exit.
</ParamField>

<RequestExample>
```bash
./installer
./installer -e config/.env
./installer -v
```
</RequestExample>

## Startup pipeline

On launch the binary:

1. Parses flags and cancels on `SIGINT` / `SIGTERM`
2. Validates or creates the env file
3. Loads `state` (env vars + optional `.state/<envname>.state` dirty overlay and EULA consent)
4. Runs `DoMigrateSettings` (legacy host paths → container mount paths)
5. Runs `DoSyncNetworkSettings` (OS `HTTP_PROXY` / `HTTPS_PROXY` → `PROXY_URL`; OS Docker client vars when `.env` Docker connection keys are empty)
6. Gathers `CheckResult` facts
7. Runs `DoHardening` (secrets only when matching containers/volumes do not already exist)
8. Enters the Bubble Tea wizard

If the state is still dirty when you exit, the process reminds you to re-run and commit.

```mermaid
flowchart TD
  A[Parse flags -e / -v] --> B[Load or create .env]
  B --> C[State + migrations + proxy/Docker sync]
  C --> D[System checks]
  D --> E[Hardening defaults]
  E --> F[Welcome screen]
  F -->|Ready + Enter| G{EULA consent?}
  G -->|No| H[EULA screen]
  G -->|Yes| I[Main menu]
  H --> I
  I --> J[Config forms]
  J --> K[Apply changes or Install]
  K --> L[Processor: networks + compose]
  I --> M[Maintenance]
  M --> N[Start / stop / update / purge / reset password]
```

## System checks

The Welcome screen shows check results. **Enter** is accepted only when `IsReadyToContinue()` is true:

| Gate | Meaning |
| --- | --- |
| Env file exists and dir writable | Can persist configuration |
| Docker API accessible | Host Docker client works |
| Worker env API accessible | Worker Docker endpoint (local or remote) works |
| Docker Compose installed + version OK | Compose CLI usable |
| Docker version OK | Engine meets installer expectations |
| Network OK | DNS/connectivity including Docker Hub-related checks |
| CPU / memory / disk OK | Host resources vs enabled stack footprint |

The main menu also surfaces live status for Docker, PentAGI, Langfuse, and Observability.

<Warning>
If Docker Hub DNS or HTTPS is blocked, installer network checks fail even when PentAGI HTTP proxy vars are set. Configure the Docker daemon/registry mirror separately; `PROXY_URL` does not proxy image pulls.
</Warning>

## Wizard navigation

| Control | Behavior |
| --- | --- |
| Enter | Advance from Welcome when ready; select menu items; submit forms |
| Tab / Shift+Tab | Move between form fields |
| Ctrl+H | Toggle masked secrets |
| Ctrl+S | Save without always closing (where supported, e.g. password reset) |
| ESC | Return to Welcome (clears nested stack) |
| Ctrl+C | Exit |

Screens use composite IDs (`screen§arg…`) so parameterized forms (provider type, processor op) restore selection after navigation.

### Main menu

Always available configuration entries:

- **LLM Providers** — OpenAI, Anthropic, Gemini, Bedrock, Ollama, DeepSeek, GLM, Kimi, Qwen, Custom
- **Embedder** — embedding provider settings
- **Summarizer** — general and assistant context budgets
- **Tools** — AI agent limits, search engines, scraper, Graphiti, Docker sandbox
- **Monitoring** — Langfuse and Observability (embedded / external / disabled patterns)
- **Server settings** — listen host/port, public URL, CORS, proxy, timeouts, SSL paths, license key, data dirs

Conditionally shown:

| Item | When |
| --- | --- |
| **Apply changes** | Dirty env state (`IsDirty()`) |
| **Install PentAGI** | No pending dirty state and core stack not installed |
| **Maintenance** | At least one lifecycle op applies (start/stop/update/reset/etc.) |

## Configuration surfaces

Forms write through a controller into dirty state; values land in `.env` only after **Apply changes** or an operation that commits.

### LLM providers (BYOK)

Each provider form maps to the corresponding env keys (API keys, base URLs, optional config paths). At least one working provider is required for real flows after deploy; the installer does not force a single vendor.

| Provider ID | Typical keys |
| --- | --- |
| `openai` | Base URL + API key |
| `anthropic` | Base URL + API key |
| `gemini` | Base URL + API key |
| `bedrock` | Region, auth modes (default / bearer / access+secret), optional session token and base URL |
| `ollama` | Base URL, optional API key, model, config path, pull/load options |
| `deepseek` / `glm` / `kimi` / `qwen` | Base URL + API key (+ optional provider name for gateways) |
| `custom` | OpenAI-compatible `LLM_SERVER_*` style endpoint, config path, legacy reasoning flags |

Embedded example YAMLs ship with the installer (`example.custom.provider.yml`, `example.ollama.provider.yml`).

### Search engines and tools

Under **Tools → Search engines**: DuckDuckGo (enable, region, safe search, time range), Sploitus, Google CSE, Tavily, Traversaal, Perplexity, Searxng — matching the server-side search env surface.

Also under Tools: AI agent supervision settings, scraper credentials/URLs, Graphiti URL mode, Docker socket/network/image options.

### Monitoring and Graphiti

| Product | Modes | Default embedded endpoints |
| --- | --- | --- |
| Observability | Embedded when `OTEL_HOST` is the in-compose collector; else external/disabled | `otelcol:8148` |
| Langfuse | Embedded when `LANGFUSE_BASE_URL` is in-compose web; else external/disabled | `http://langfuse-web:3000` |
| Graphiti | Embedded when `GRAPHITI_URL` is in-compose; else external/disabled | `http://graphiti:8000` |

Embedded stacks pull the matching compose overlay and start containers; switching away removes containers but keeps extracted files for re-enable.

### Server settings and SSL

Server form fields include license key, listen IP/port, public URL, CORS, proxy URL/user/password, HTTP and terminal timeouts, and SSL-related paths:

- `PENTAGI_SSL_DIR` — directory with `server.crt` / `server.key` (PEM; cert may be full chain); overrides default generated cert behavior
- `EXTERNAL_SSL_CA_PATH` — custom CA inside the container (typically under `/opt/pentagi/ssl/`)
- `EXTERNAL_SSL_INSECURE` — skip TLS verify for outbound provider calls (testing only)

Default compose data includes volumes such as `pentagi-ssl` and `scraper-ssl`. Hardening covers cookie signing, DB passwords, and scraper auth used with HTTPS scraper URLs—not a separate “generate cert” menu step.

## Hardening and migrations

### Automatic secret hardening

When PentAGI / Langfuse / Graphiti are **not** already installed and their data volumes do **not** exist, the installer replaces documented defaults with random values and commits:

| Area | Examples |
| --- | --- |
| PentAGI | `COOKIE_SIGNING_SALT`, `PENTAGI_POSTGRES_PASSWORD`, scraper user/password, synced `SCRAPER_PRIVATE_URL` |
| Graphiti | `NEO4J_PASSWORD` |
| Langfuse | DB/ClickHouse/Redis/S3 secrets, salt, encryption key, NextAuth secret, project public/secret keys; signup disabled by policy |

Policies use hex, UUID-with-prefix, or alphanumeric lengths. Existing volumes are left alone so credentials stay consistent with data already on disk.

Also set: `INSTALLATION_ID` from the host installation identity; invalid `LICENSE_KEY` values are cleared after introspection.

### Path migrations

| Legacy | Migrated |
| --- | --- |
| Host `DOCKER_CERT_PATH` (real dir) | `PENTAGI_DOCKER_CERT_PATH` host path; `DOCKER_CERT_PATH` reset to container default |
| Host custom `LLM_SERVER_CONFIG_PATH` | `PENTAGI_LLM_SERVER_CONFIG_PATH` + container default path |
| Host custom `OLLAMA_SERVER_CONFIG_PATH` | `PENTAGI_OLLAMA_SERVER_CONFIG_PATH` + container default path |

## Apply changes vs install

Both operations go through the processor with an embedded terminal for compose output.

### Apply changes

Shown when state is dirty.

1. Commit dirty vars to `.env` and clear `.state` overlay  
2. Re-gather checker facts  
3. Ensure Docker networks (`pentagi-network`, `observability-network`, `langfuse-network` as needed)  
4. Phase order: Observability → Langfuse → Graphiti → PentAGI  
5. Per stack: extract/verify compose files, then update/start or remove if switched to external/disabled  

### Install

Shown when core is not installed and there is no dirty buffer.

Same network ensure + phased stack apply, but only for stacks not already installed. Prefer finishing configuration first, then Install; use Apply changes for later env edits on a live install.

## Maintenance

Menu items appear only when the corresponding checker helper is true.

| Operation | Condition (summary) |
| --- | --- |
| Start / Stop / Restart | Installed-not-running / any stack running |
| Download worker image | Worker image missing |
| Update worker / stacks / installer | Image or stack outdated; installer needs update server access |
| Factory reset | Any compose stack installed |
| Remove / Purge | Any stack installed (purge is more destructive) |
| Reset admin password | `PentagiRunning` |

### Reset admin password

Resets `admin@pentagi.com` in PostgreSQL while the stack is up.

<Steps>
  <Step title="Confirm PentAGI is running">
    Maintenance only lists **Reset Admin Password** when the core container is running and port `5432` is reachable on `127.0.0.1` with credentials from `.env` (`PENTAGI_POSTGRES_USER` / `PASSWORD` / `DB`, defaults `postgres` / `postgres` / `pentagidb`).
  </Step>
  <Step title="Enter and confirm password">
    Installer validation: non-empty, minimum **5** characters, both fields match. Passwords are masked; Ctrl+H toggles visibility.
  </Step>
  <Step title="Apply">
    Enter runs reset and returns on success; Ctrl+S runs reset and stays on the form. The processor bcrypt-hashes the password and runs  
    `UPDATE users SET password = $1, status = 'active' WHERE mail = 'admin@pentagi.com'`.
  </Step>
</Steps>

<Note>
Default first-login credentials after a fresh deploy remain `admin@pentagi.com` / `password` until changed in the UI or via this maintenance path. Prefer a strong password in production; UI registration rules may be stricter than the installer’s 5-character floor.
</Note>

## State and files on disk

| Path | Role |
| --- | --- |
| `.env` (or `-e` path) | Authoritative env after commit; mode `0600` on create |
| `.state/<env-basename>.state` | Dirty vars + navigation stack before commit |
| `.state` EULA consent marker | Skips EULA after acceptance |
| Working dir compose files | Extracted from embedded FS (`docker-compose*.yml`, provider examples) |
| Docker volumes | e.g. `pentagi-postgres-data`, `pentagi-data`, `pentagi-ssl`, `scraper-ssl` |

## Troubleshooting

| Symptom | What to check |
| --- | --- |
| Welcome blocks Enter | Docker socket permissions; compose install; disk/memory; Docker Hub DNS; env dir writability |
| “System is not ready” at startup | Same gates as Welcome; fix host before relying on the menu |
| Compose commands fail in TUI | Narrow terminals force `COMPOSE_ANSI=never`; widen if output is unreadable |
| Apply/install fails mid-stack | Read terminal pane errors; fix registry auth/mirror; re-run after partial extract |
| Password reset fails | Stack not running; Postgres not published on localhost:5432; wrong `PENTAGI_POSTGRES_*`; admin row missing |
| Secrets “reset” unexpectedly | Hardening only when volumes absent—do not delete volumes if you need stable credentials |
| Proxy works for app but not pulls | Configure Docker daemon proxy/mirror, not only `PROXY_URL` |
| Dirty state after quit | Re-run installer and **Apply changes** or discard by resetting state carefully |

Debug during development: write logs via the wizard logger to `log.json` and `tail -f log.json` in another terminal—never `fmt.Printf` inside the TUI.

## Verify a successful install

1. Welcome checks all green; EULA accepted  
2. At least one LLM provider configured and applied  
3. Install or Apply completes without processor errors  
4. Open `https://localhost:8443` (or your public URL/port)  
5. Sign in, change default admin password if still default  
6. Create a test flow and confirm provider health  

## Related pages

<CardGroup cols={2}>
  <Card title="Installation" href="/installation">
    Manual compose, SSL volumes, and optional overlays without the TUI.
  </Card>
  <Card title="Quickstart" href="/quickstart">
    First login, change defaults, and create a flow after deploy.
  </Card>
  <Card title="Configure LLM providers" href="/configure-llm-providers">
    Env keys and UI profiles for each BYOK provider.
  </Card>
  <Card title="Search engines" href="/search-engines">
    Search provider env and tool gating details.
  </Card>
  <Card title="Environment variables" href="/environment-variables">
    Full Config and `.env.example` reference.
  </Card>
  <Card title="Observability and Langfuse" href="/observability-and-langfuse">
    Optional monitoring and LLM analytics stacks.
  </Card>
  <Card title="Knowledge graph" href="/knowledge-graph">
    Graphiti and Neo4j compose enablement.
  </Card>
  <Card title="Authentication and API tokens" href="/auth-and-api-tokens">
    Default admin account and session/API auth after install.
  </Card>
</CardGroup>
