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

# Local development setup

# Local development setup

**Last Updated:** 2026-05-23
**Status:** Alpha

This is the end-to-end walkthrough for getting Poindexter running on
your own machine. If you only want "one command to a working
pipeline," run `poindexter setup --auto` — read
[Quick Start in the README](../../README#quick-start) first.

This document covers the longer form: what the setup wizard does
under the hood, how to verify each layer, and how to troubleshoot
when something doesn't come up.

## Minimum hardware

| Tier        | GPU VRAM | What it unlocks                                                                                                            |
| ----------- | -------- | -------------------------------------------------------------------------------------------------------------------------- |
| Minimum     | 8 GB     | Runs smaller Ollama models only; writer model will be constrained to 7B range                                              |
| Recommended | 16 GB    | Supports Q4 quantized 7B–14B models at full quality                                                                        |
| Optimal     | 24 GB+   | Q4\_K\_M 32B writer models; comfortable headroom for image-gen + Ollama simultaneously                                     |
| CPU-only    | no GPU   | Fallback available via `pipeline_writer_model=ollama/gemma2:2b-instruct-q4_K_M` but output quality will be noticeably poor |

RAM: 32 GB minimum, 64 GB recommended (the full stack including Langfuse, ClickHouse, and Grafana
uses 8–12 GB resident at idle).

Disk: 100 GB free for model weights, Docker images, and generated media.

## 1. Prerequisites

| Tool           | Version  | Purpose                                  | Required?   |
| -------------- | -------- | ---------------------------------------- | ----------- |
| Docker         | 20.10+   | Runs the entire backend stack            | Yes         |
| Ollama         | 0.1.40+  | Local LLM inference                      | Yes         |
| Node.js        | 22+      | Frontend (Next.js) and lint-staged hooks | Yes         |
| Git + Git Bash | any      | start-stack.sh uses `bash`               | Yes         |
| Python         | 3.13+    | CLI + running worker outside Docker      | Yes         |
| GPU            | 8GB VRAM | Ollama inference is far faster with CUDA | Recommended |

**Windows note.** Run all commands from Git Bash or WSL. Native
`cmd.exe` and PowerShell do not work with the start scripts.
Docker Desktop must be configured to use WSL2 backend.

**Linux note.** Stock Docker Engine on Linux does not automatically
resolve `host.docker.internal` — this is a Docker Desktop feature.
The compose files add `extra_hosts: ["host.docker.internal:host-gateway"]`
to every service that calls a host-side endpoint (Ollama, image-gen, voice
bridge). `host-gateway` is a Docker built-in alias that resolves to the
host's IP and is supported on Docker Engine 20.10+. No manual
configuration is needed; the `extra_hosts` entries are already present in
both `docker-compose.yml` and `docker-compose.local.yml`.

**GPU note.** You can run Poindexter on CPU, but content generation
that takes 30 seconds on an RTX 4090 can take 10+ minutes on CPU.
Not practical for daily use.

## 2. Clone and setup

```bash theme={null}
git clone https://github.com/Glad-Labs/poindexter.git
cd poindexter
pip install -e src/cofounder_agent
poindexter setup          # interactive wizard
# or: poindexter setup --auto   (spins up a local Docker Postgres)
# or: poindexter setup --db-url "postgresql://..."  (non-interactive)
```

The setup wizard does the following:

1. **Prompts for a database URL** (or auto-provisions a local Docker
   Postgres with `--auto`).
2. **Tests the database connection** and reports success/failure.
3. **Runs migrations** against the target database. Safe to re-run —
   migrations are idempotent.
4. **Generates secrets** — creates random `local_postgres_password`,
   `grafana_password`, and `pgadmin_password`.
5. **Writes `~/.poindexter/bootstrap.toml`** with the database URL +
   generated secrets. This is the only config file on disk.
6. **Provisions the initial CLI OAuth client** — registers a row in
   `oauth_clients`, encrypts the credentials into
   `app_settings.cli_oauth_client_id` / `cli_oauth_client_secret`, and
   prints the plaintext secret once for capture. (Worker auth uses
   OAuth 2.1 only as of Glad-Labs/poindexter#249.)

No `.env` file is created. All secrets live in `bootstrap.toml`
(safe permissions, never committed to git).

## 3. Pull AI models

```bash theme={null}
ollama pull gemma3:27b       # 16GB — QA reviews, fallback critic
ollama pull qwen3:8b         # 5GB — fast tasks (SEO, image decisions)
ollama pull nomic-embed-text # 274MB — embeddings for semantic search
```

Total first-run download: \~21GB. For better writing quality, also pull
a larger writer model:

```bash theme={null}
ollama pull qwen3:30b        # 18GB — good balance of speed and quality
```

## 4. Bring up the full stack

```bash theme={null}
bash scripts/start-stack.sh
```

This reads `~/.poindexter/bootstrap.toml`, exports the values as env
vars, and runs `docker compose -f docker-compose.local.yml up -d`.
No `.env` file needed.

This starts the core containers (cross-referenced against the CLAUDE.md Quick-Links table for ports + purposes):

| Container                     | Purpose                                                                   | Port  |
| ----------------------------- | ------------------------------------------------------------------------- | ----- |
| `poindexter-worker`           | FastAPI backend, content pipeline                                         | 8002  |
| `poindexter-brain-daemon`     | Health probes + self-healing loop                                         | —     |
| `poindexter-postgres-local`   | PostgreSQL 16 + pgvector                                                  | 5433  |
| `poindexter-grafana`          | Monitoring dashboards                                                     | 3000  |
| `poindexter-prometheus`       | Metric scraper                                                            | 9091  |
| `poindexter-image-gen-server` | image-gen image generation (GPU)                                          | 9836  |
| `poindexter-pgadmin`          | Database GUI                                                              | 18443 |
| `poindexter-langfuse`         | LLM trace explorer + prompt UI (UnifiedPromptManager edits land here)     | 3010  |
| `poindexter-glitchtip`        | Self-hosted Sentry — runtime errors from worker / brain / voice agent     | 8080  |
| `poindexter-prefect`          | Orchestration UI for the Prefect server (flow runs, schedules)            | 4200  |
| `poindexter-pyroscope`        | Continuous profiler — flame graphs from worker / brain / voice            | 4040  |
| `poindexter-loki`             | Log storage (consumed via Grafana Explore — Loki datasource)              | 3100  |
| `poindexter-tempo`            | Trace storage (consumed via Grafana Explore — Tempo datasource)           | 3200  |
| `poindexter-alertmanager`     | Alert-routing UI                                                          | 9093  |
| `poindexter-livekit`          | Local LiveKit server (Tailscale Serve fronts `/voice/join`, tailnet-only) | 7880  |

Stop optional containers if you don't need them:

```bash theme={null}
docker compose -f docker-compose.local.yml stop poindexter-pgadmin
```

## 5. Verify

```bash theme={null}
# Worker health (expect "healthy" for every subsystem)
curl http://localhost:8002/api/health

# Mint a JWT for the CLI client (printed plaintext during `poindexter
# setup`; if you missed it, re-run `poindexter auth migrate-cli` to
# rotate to a new client).
JWT=$(poindexter auth mint-token \
  --client-id <pdx_xxx> --client-secret <secret>)

# Create a task end-to-end
curl -X POST http://localhost:8002/api/tasks \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{"topic": "Why Docker changed everything", "category": "technology"}'
```

The task should move through `pending → in_progress → awaiting_approval`
within a few minutes. Follow along via:

```bash theme={null}
docker logs -f poindexter-worker
```

## 6. Frontend (optional for backend dev)

If you're only iterating on the backend, skip the frontend — the
worker's API and the Grafana dashboards are all you need. If you do
want the Next.js public site running locally:

```bash theme={null}
cd web/public-site
npm install
npm run dev
```

Open [http://localhost:3000](http://localhost:3000).

## 7. Run the tests

```bash theme={null}
cd src/cofounder_agent
poetry install
poetry run pytest tests/unit/ -q
```

> The unit suite runs **lean** — the cross-encoder reranker (`sentence-transformers`
>
> * `torch`) is an opt-in `rerank` extra that CI deliberately skips, and the tests
>   that touch it `importorskip`. Add `poetry install --extras rerank` only if you
>   want to exercise the reranker locally.

Expected: the full unit suite passes (several thousand cases). Some tests
that depend on the `brain` module or `sentry-sdk` are skipped when running
inside Docker (these pass on the host where all modules are available).

## 8. What to do when something breaks

See [troubleshooting.md](troubleshooting).

## Configuration

All runtime configuration lives in the `app_settings` Postgres
table, not env vars. After setup, change settings with:

```bash theme={null}
# Mint a JWT (or use `poindexter settings get/set` directly — the CLI
# handles auth for you). $JWT below is the value printed during setup
# or by `poindexter auth mint-token --client-id ... --client-secret ...`.

# View all settings
curl http://localhost:8002/api/settings \
  -H "Authorization: Bearer $JWT"

# Change a setting
curl -X PUT http://localhost:8002/api/settings/auto_publish_threshold \
  -H "Authorization: Bearer $JWT" \
  -H "Content-Type: application/json" \
  -d '{"value": "80"}'
```

See [environment-variables.md](environment-variables) for the
bootstrap-layer reference (the few env vars Docker still needs), and
[reference/app-settings.md](../reference/app-settings) for the
full DB-layer settings catalog.
