# Development and testing

> Backend go build and test, frontend pnpm scripts, gqlgen and graphql:generate, ctester container tests, etester embeddings, ftester tool calling, and local compose for contributors.

- 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

- `CLAUDE.md`
- `backend/go.mod`
- `frontend/package.json`
- `backend/cmd/ctester/main.go`
- `backend/cmd/etester/main.go`
- `backend/cmd/ftester/main.go`
- `backend/gqlgen/gqlgen.yml`
- `README.md`

---

---
title: "Development and testing"
description: "Backend go build and test, frontend pnpm scripts, gqlgen and graphql:generate, ctester container tests, etester embeddings, ftester tool calling, and local compose for contributors."
---

PentAGI is a monorepo: `backend/` is a Go 1.24 module (`module pentagi`) that builds the API server and tester binaries; `frontend/` is a React + TypeScript Vite app managed with `pnpm@10`. Contributors run unit tests with `go test` and Vitest, regenerate GraphQL stubs after schema edits, and use three in-tree utilities—`ctester`, `etester`, and `ftester`—to validate LLM agents, embeddings, and tool execution against a live or mock stack.

## Prerequisites

| Tool | Role |
|---|---|
| Go (matches `backend/go.mod`, currently `go 1.24.1`) | Backend build, tests, gqlgen |
| Node.js + pnpm 10 | Frontend install, dev server, Vitest, GraphQL codegen |
| Docker + Docker Compose | Core stack, sandboxed workers, image builds |
| PostgreSQL with pgvector | Database for local API and embedding tests |
| commitlint | Conventional commits (repo expectation) |
| Optional: `swag`, `golangci-lint`, `sqlc`, `fern-api` | REST docs, lint, ORM gen, Langfuse SDK gen |

Copy `.env.example` to `.env` and set at least `DATABASE_URL` and one LLM provider key before running the API or tester binaries. Provider and search keys are BYOK: point env vars at any compatible endpoint; no hosted vendor is required for local development.

## Repository layout

```text
pentagi/
├── backend/
│   ├── cmd/pentagi/     # Main API server
│   ├── cmd/ctester/     # LLM agent / provider config tester
│   ├── cmd/etester/     # Embedding + pgvector tester
│   ├── cmd/ftester/     # Tool and agent function tester
│   ├── cmd/installer/   # Interactive TUI deploy wizard
│   ├── gqlgen/gqlgen.yml
│   ├── pkg/graph/       # schema.graphqls + gqlgen output
│   ├── sqlc/            # SQL → Go generation
│   └── migrations/sql/  # goose migrations (auto-run at startup)
├── frontend/
│   ├── package.json     # pnpm scripts
│   ├── graphql-codegen.ts
│   └── src/graphql/     # Generated Apollo types (do not hand-edit)
├── docker-compose.yml   # Core stack
├── docker-compose-*.yml # Observability, Langfuse, Graphiti overlays
└── Dockerfile           # Multi-stage: UI + pentagi/ctester/etester/ftester
```

## Backend build, test, and lint

Run from `backend/`:

```bash
go mod download
go build -trimpath -o pentagi ./cmd/pentagi
go test ./...
go test ./pkg/foo/... -v -run TestName
golangci-lint run --timeout=5m
```

The production `Dockerfile` builds with `CGO_ENABLED=0` and `-trimpath`, and emits four binaries under `/opt/pentagi/bin/`: `pentagi`, `ctester`, `etester`, and `ftester`. Locally, the same packages can be run with `go run`.

### Local API process

```bash
cd backend
# Load env (or export vars from .env)
go run cmd/pentagi/main.go
```

Useful local overrides (often set in `.vscode/launch.json`):

| Variable | Purpose | Typical local value |
|---|---|---|
| `DATABASE_URL` | Postgres connection | `postgres://postgres:postgres@localhost:5432/pentagidb?sslmode=disable` |
| `DOCKER_HOST` | Docker SDK socket | macOS Docker Desktop raw socket path |
| `SERVER_PORT` | HTTP listen port | `8443` (default) |
| `SERVER_USE_SSL` | TLS for the API | `false` for plain local HTTP |

First start downloads Docker worker images and can take several minutes.

### Connection pool defaults

PentAGI opens two pools to the same Postgres instance:

| Pool | Env var | Default |
|---|---|---|
| Shared `sql.DB` (sqlc / GORM) | `DATABASE_MAX_OPEN_CONNS` | `25` |
| Shared `pgxpool` (pgvector) | `DATABASE_VECTOR_MAX_CONNS` | `10` |

Also: `DATABASE_MAX_IDLE_CONNS` (default `5`). Defaults target roughly ten parallel flows against the stock `vxcontrol/pgvector` image (`max_connections=100`).

## Code generation

### GraphQL (gqlgen)

Schema lives in `backend/pkg/graph/schema.graphqls`. Config is `backend/gqlgen/gqlgen.yml`:

- **Schema glob:** `pkg/graph/*.graphqls`
- **Exec output:** `pkg/graph/generated.go`
- **Models:** `pkg/graph/model/models_gen.go`
- **Resolvers:** `follow-schema` layout → `pkg/graph/{name}.resolvers.go`
- **ID scalar:** primarily `graphql.Int64`

After schema changes:

```bash
cd backend
go run github.com/99designs/gqlgen --config ./gqlgen/gqlgen.yml
```

### Swagger (REST)

Install once, then regenerate after handler annotation changes:

```bash
go install github.com/swaggo/swag/cmd/swag@v1.8.7
cd backend
swag init -g ../../pkg/server/router.go -o pkg/server/docs/ \
  --parseDependency --parseInternal --parseDepth 2 -d cmd/pentagi
```

Swagger UI is served at `/api/v1/swagger` when the API is running.

### sqlc

```bash
cd backend
docker run --rm -v $(pwd):/src -w /src --network pentagi-network \
  -e DATABASE_URL="{URL}" \
  sqlc/sqlc:1.27.0 generate -f sqlc/sqlc.yml
```

### Langfuse SDK (optional)

```bash
pnpm add -g fern-api
cd backend && fern generate --local
```

### Frontend GraphQL types

`frontend/graphql-codegen.ts` reads the backend schema and `./graphql-schema.graphql` documents, then writes Apollo hooks to `src/graphql/types.ts` (post-write Prettier):

```bash
cd frontend
pnpm install
pnpm run graphql:generate
```

Regenerate after any backend schema or frontend operation document change. Do not hand-edit `src/graphql/types.ts`.

## Frontend scripts

Package manager: `pnpm@10.32.1` (`packageManager` field in `package.json`).

| Script | Command | Purpose |
|---|---|---|
| Install | `pnpm install` | Dependencies |
| Dev | `pnpm run dev` | Vite dev server (default host `0.0.0.0`, port `8000`) |
| Build | `pnpm run build` | `tsc && vite build` |
| Test | `pnpm run test` | `vitest run` |
| Coverage | `pnpm run test:coverage` | Vitest + v8 coverage |
| Watch tests | `pnpm run test:watch` | Interactive Vitest |
| Lint | `pnpm run lint` / `lint:fix` | ESLint on `src/**/*.{ts,tsx,js,jsx}` |
| Format | `pnpm run prettier` / `prettier:fix` | Prettier check / write |
| GraphQL | `pnpm run graphql:generate` | Codegen from schema |
| SSL | `pnpm run ssl:generate` | Dev certs (also auto on `dev`) |

Vite env (frontend launch config):

| Variable | Meaning | Notes |
|---|---|---|
| `VITE_API_URL` | Backend host:port | Omit scheme (`localhost:8080`, not `http://…`) |
| `VITE_USE_HTTPS` | Frontend HTTPS | Default `false` |
| `VITE_PORT` | Dev port | Default `8000` |
| `VITE_HOST` | Bind address | Default `0.0.0.0` |

## Local stack with Compose

From the repo root:

```bash
# Core services (API, UI assets in image, pgvector, scraper, …)
docker compose up -d

# Optional overlays
docker compose -f docker-compose.yml -f docker-compose-observability.yml up -d
docker compose -f docker-compose.yml -f docker-compose-langfuse.yml up -d
docker compose -f docker-compose.yml -f docker-compose-graphiti.yml up -d

# Local image
docker build -t local/pentagi:latest .
```

Compose stack URL: `https://localhost:8443`. Create Docker networks via the core file first if overlays fail with missing network names.

### Contributor local workflows

<Tabs>
  <Tab title="Split process (API + UI)">
    1. Start Postgres (pgvector) and ensure Docker is available.
    2. From `backend/`: configure `.env`, run `go run cmd/pentagi/main.go`.
    3. From `frontend/`: `pnpm install && pnpm run dev`.
    4. Point `VITE_API_URL` at the backend listen address.
  </Tab>
  <Tab title="Full Compose">
    1. Copy `.env.example` → `.env` with DB and at least one LLM key.
    2. `docker compose up -d`.
    3. Open `https://localhost:8443`, change default admin credentials, create a flow.
    4. Use `docker exec -it pentagi /opt/pentagi/bin/{ctester,etester,ftester}` for in-container tests.
  </Tab>
</Tabs>

## Utility binaries

| Binary | Package | Purpose |
|---|---|---|
| `ctester` | `backend/cmd/ctester` | Parallel LLM agent capability tests and markdown reports |
| `etester` | `backend/cmd/etester` | Embedding provider + pgvector ops (`test`, `info`, `flush`, `reindex`, `search`) |
| `ftester` | `backend/cmd/ftester` | Invoke tools/agents with mock or real flow context |
| `installer` | `backend/cmd/installer` | TUI wizard for deploy-time `.env` and compose setup |

Image paths: `/opt/pentagi/bin/ctester`, `/opt/pentagi/bin/etester`, `/opt/pentagi/bin/ftester`.

## ctester — LLM agent testing

`ctester` loads `.env` (or `-env`), builds a provider of type `-type`, runs the shared tester suite, prints a summary, and optionally writes `-report`.

### Flags

| Flag | Default | Description |
|---|---|---|
| `-env` | `.env` | Environment file |
| `-type` | `custom` | `custom`, `openai`, `anthropic`, `gemini`, `bedrock`, `ollama`, `deepseek`, `glm`, `kimi`, `qwen` |
| `-name` | empty | Sets provider name used when building custom config |
| `-config` | empty | Provider YAML path (overrides `LLM_SERVER_CONFIG` / `OLLAMA_SERVER_CONFIG`) |
| `-tests` | empty | Custom tests YAML |
| `-report` | empty | Markdown report output path |
| `-agents` | `all` | Comma-separated agent option types |
| `-groups` | `all` | Comma-separated test groups |
| `-workers` | `4` | Parallel workers |
| `-verbose` | false | Verbose output |

**Agent names:** `simple`, `simple_json`, `primary_agent`, `assistant`, `generator`, `refiner`, `adviser`, `reflector`, `searcher`, `enricher`, `coder`, `installer`, `pentester`.

**Test groups:** `basic`, `advanced`, `json`, `knowledge` (all selected when `-groups all`).

### Local examples

```bash
cd backend
go run cmd/ctester/*.go -verbose
go run cmd/ctester/*.go -config ../examples/configs/openrouter.provider.yml -verbose
go run cmd/ctester/*.go -agents simple,simple_json,primary_agent -groups basic,advanced -verbose
go run cmd/ctester/*.go -config ../examples/configs/deepinfra.provider.yml -report ../test-report.md
```

### Docker examples

```bash
docker run --rm -v $(pwd)/.env:/opt/pentagi/.env \
  vxcontrol/pentagi /opt/pentagi/bin/ctester -verbose

docker exec -it pentagi /opt/pentagi/bin/ctester -type openai
docker exec -it pentagi /opt/pentagi/bin/ctester \
  -config /opt/pentagi/conf/openrouter.provider.yml -verbose
```

Sample reports for many providers live under `examples/tests/`. Example provider YAMLs ship in `examples/configs/` and are copied into the image at `/opt/pentagi/conf/`.

## etester — embeddings and pgvector

`etester` requires a working `DATABASE_URL` and embedding config from the environment. Default command is `test`.

### Commands

| Command | Behavior |
|---|---|
| `test` | Probe embedding provider and pgvector connectivity |
| `info` | Collection / embedding table statistics |
| `flush` | Delete all embedding documents (destructive) |
| `reindex` | Recalculate embeddings for all documents |
| `search` | Similarity search with optional filters |

### Flags

| Flag | Default | Description |
|---|---|---|
| `-env` | `.env` | Environment file |
| `-verbose` | false | Verbose output |
| `-help` | false | Help |

Search options (from `search -help` / README): `-query` (required), `-doc_type` (`answer`, `memory`, `guide`, `code`), `-flow_id`, `-answer_type`, `-guide_type`, `-limit` (default `3`), `-threshold` (default `0.7`).

```bash
cd backend
go run cmd/etester/main.go test -verbose
go run cmd/etester/main.go info
go run cmd/etester/main.go search -query "How to install PostgreSQL" -limit 5

# Destructive: after switching embedding provider
go run cmd/etester/main.go flush
go run cmd/etester/main.go reindex
```

```bash
docker exec -it pentagi /opt/pentagi/bin/etester test
docker exec -it pentagi /opt/pentagi/bin/etester search \
  -query "Security vulnerability" -doc_type guide -threshold 0.8
```

<Warning>
Changing embedding providers breaks vector compatibility. Run `flush` or `reindex` so the store is not mixed-dimension or mixed-semantic.
</Warning>

## ftester — tools and agent functions

`ftester` wires config, Postgres, Docker, provider controller, optional Langfuse/OTEL, and a tools executor. With `-flow 0` (default) it uses mock proxies; a non-zero `-flow` binds real flow/task/subtask context.

### Global flags

| Flag | Default | Description |
|---|---|---|
| `-env` | `.env` | Environment file |
| `-provider` | `custom` | `openai`, `anthropic`, `gemini`, `bedrock`, `ollama`, `deepseek`, `glm`, `kimi`, `qwen`, `custom` |
| `-flow` | `0` | Flow ID; `0` = mock mode |
| `-user` | `0` | User ID (admin is typically `1`) |
| `-task` | unset | Task ID when non-zero |
| `-subtask` | unset | Subtask ID when non-zero |

Usage pattern:

```bash
cd backend
go run cmd/ftester/main.go [function] -[arg] [value]
go run cmd/ftester/main.go [function] -help   # per-function params
go run cmd/ftester/main.go                    # list functions
```

### Function groups

| Group | Functions |
|---|---|
| Environment | `terminal`, `file` |
| Search | `browser`, `google`, `duckduckgo`, `tavily`, `traversaal`, `perplexity`, `sploitus`, `searxng` |
| Vector memory | `search_in_memory`, `search_guide`, `search_answer`, `search_code` |
| Agents | `advice`, `coder`, `maintenance`, `memorist`, `pentester`, `search` |
| Utility | `describe` (flows/tasks/subtasks inspection) |

### Examples

```bash
# Mock terminal
go run cmd/ftester/main.go terminal -command "ls -la" -message "List files"

# Real flow context
go run cmd/ftester/main.go -flow 123 terminal -command "whoami" -message "Check user"

# Agent in task/subtask scope
go run cmd/ftester/main.go -flow 123 -task 456 -subtask 789 \
  pentester -message "Find vulnerabilities"

# Stuck-flow diagnosis
go run cmd/ftester/main.go describe
go run cmd/ftester/main.go -flow 123 describe -verbose

# Config smoke tests
go run cmd/ftester/main.go google -query "pentesting tools"
go run cmd/ftester/main.go browser -url "https://example.com"
```

```bash
docker exec -it pentagi /opt/pentagi/bin/ftester -flow 123 describe
docker exec -it pentagi /opt/pentagi/bin/ftester -flow 123 \
  terminal -command "ps aux" -message "List processes"
```

When Langfuse / OTEL are configured, ftester calls emit traces and metrics (same observer path as the main server). Interactive mode prompts for missing args when you pass only a function name.

## Image build

Version helpers inject package version into binaries:

```bash
source ./scripts/version.sh
docker build \
  --build-arg PACKAGE_VER=$PACKAGE_VER \
  --build-arg PACKAGE_REV=$PACKAGE_REV \
  -t pentagi:$PACKAGE_VER .
```

Multi-platform: `docker buildx build --platform linux/amd64,linux/arm64 …`. The multi-stage Dockerfile compiles the frontend with GraphQL schema present, builds all four Go binaries with version ldflags, and stages configs under `/opt/pentagi/conf/`.

## Verification checklist

<Steps>
  <Step title="Backend unit tests">
    `cd backend && go test ./...` — all packages green.
  </Step>
  <Step title="Frontend unit tests and lint">
    `cd frontend && pnpm run test && pnpm run lint && pnpm run prettier` — Vitest and style gates pass.
  </Step>
  <Step title="Schema parity">
    After GraphQL edits: run gqlgen in `backend/`, then `pnpm run graphql:generate` in `frontend/`. Confirm resolvers compile and UI types update.
  </Step>
  <Step title="Provider readiness">
    `go run cmd/ctester/*.go -type <provider> -groups basic -verbose` (or Docker equivalent) before relying on a new model for flows.
  </Step>
  <Step title="Embeddings">
    `go run cmd/etester/main.go test -verbose` against the same `DATABASE_URL` the API uses.
  </Step>
  <Step title="Tools / sandbox">
    `go run cmd/ftester/main.go terminal -command "echo ok" -message "smoke"` with Docker available; use `-flow` when validating against a real engagement.
  </Step>
</Steps>

## Common failure modes

| Symptom | Likely cause | Action |
|---|---|---|
| Provider create fails in ctester | Missing API key / URL for `-type` | Set provider env vars or use `-config` YAML |
| etester cannot connect | Bad `DATABASE_URL` or no pgvector | Start Postgres; confirm extension |
| Poor vector search after model change | Mixed embedding spaces | `flush` / `reindex` |
| ftester Docker errors | No Docker socket / wrong `DOCKER_HOST` | Fix socket path (macOS raw socket often required) |
| Frontend cannot reach API | Wrong `VITE_API_URL` scheme or port | Host:port only; match backend listen |
| gqlgen / codegen drift | Schema edited without regen | Re-run gqlgen + `graphql:generate` |
| Overlay compose network missing | Core stack never started | `docker compose up` core first |

## Adding an LLM provider (dev impact)

When introducing a new provider type, update the Go adapter, register it in `pkg/providers`, whitelist it in `pkg/server/models/providers.go` `Valid()`, add config keys, ship a goose migration for `PROVIDER_TYPE`, add a frontend icon, and regenerate GraphQL/types if the API surface changes. Skipping the REST whitelist yields **422 Unprocessable Entity** on provider APIs.

## Related pages

<CardGroup cols={2}>
  <Card title="Contributing" href="/contributing">
    License-compatible dependencies, generate-licenses.sh, and PR expectations.
  </Card>
  <Card title="Installation" href="/installation">
    Compose stack, .env, SSL, volumes, and optional overlays.
  </Card>
  <Card title="Environment variables" href="/environment-variables">
    Full Config / .env.example reference for local and production.
  </Card>
  <Card title="GraphQL API" href="/graphql-api">
    schema.graphqls operations that gqlgen and frontend codegen consume.
  </Card>
  <Card title="Configure LLM providers" href="/configure-llm-providers">
    Env wiring for OpenAI, Anthropic, Gemini, Bedrock, and others used by ctester.
  </Card>
  <Card title="Example provider configs" href="/example-provider-configs">
    YAML samples under examples/configs for local agent testing.
  </Card>
  <Card title="Interactive installer" href="/installer">
    TUI path when you prefer guided .env and compose setup over hand-editing.
  </Card>
  <Card title="Docker sandbox and workers" href="/docker-sandbox-workers">
    Socket, images, and multi-host constraints that ftester and the API share.
  </Card>
</CardGroup>
