Browse documentation ↓

Native development

Use the Docker quickstart for the shortest setup. For direct service development, use Rust 1.98, Node 24, pnpm 11.19.0, Python 3.12, and PostgreSQL 18, matching the product build environment.

Install the toolchains listed in the main README: Rust, Node with pnpm, Python and PostgreSQL. .NET 8 is needed only for the C# SDK and four-language contract tests.

cd /path/to/pragma_change  # replace with your checkout
python3 scripts/setup-env.py                # creates .env; skip if it already exists
python3 scripts/setup-env.py --expansion    # creates .env.expansion and .secrets/credential-key
python3 -m venv services/trainer/.venv
services/trainer/.venv/bin/pip install -r services/trainer/requirements.lock
pnpm --dir apps/portal install --frozen-lockfile
cargo build -p pragma-api -p pragma-behavior -p pragma-engine

Both setup commands refuse to replace existing files. If you already configured working behavior or vault credentials, retain them instead of generating replacements. The vault key encrypts SSH/provider credentials; the partition secrets preserve identity continuity. Back up these files privately with the database and artifacts. They are ignored by Git. Creating new secrets does not reset existing credentials in a database.

For a new local PostgreSQL installation, create two databases as the database administrator. These commands prompt for passwords instead of putting them into shell history. Skip databases/users you already provisioned:

sudo -u postgres createuser --pwprompt pragma
sudo -u postgres createdb --owner=pragma pragma
sudo -u postgres createuser --pwprompt pragma_behavior
sudo -u postgres createdb --owner=pragma_behavior pragma_behavior

Add your connection strings to the private .env file; URL-encode special characters in passwords. Use the passwords chosen above, not necessarily the Compose passwords generated by the setup script. The databases must be distinct: they have independent migrations.

DATABASE_URL=postgres://pragma:[email protected]:5432/pragma
BEHAVIOR_DATABASE_URL=postgres://pragma_behavior:[email protected]:5432/pragma_behavior
TRAINER_URL=http://127.0.0.1:8001
API_URL=http://127.0.0.1:8080
BIND_ADDR=127.0.0.1:8080
BEHAVIOR_BIND_ADDR=127.0.0.1:8090

Load your private settings in each terminal before its start command:

set -a
source .env
source .env.expansion
set +a

Terminal 1: Python forest trainer

services/trainer/.venv/bin/uvicorn app:app --app-dir services/trainer --host 127.0.0.1 --port 8001

Runs Isolation Forest training. It is not needed for behavior sequence training.

Terminal 2: Rust behavior API and sequence-training worker

cargo run -p pragma-behavior

Runs collection, evaluations, offline behavior imports and the durable sequence-training worker on port 8090. It applies behavior migrations automatically. Put this service near application servers, away from Nginx by default.

Terminal 3: Rust management API and job workers

cargo run -p pragma-api

Runs the management API on port 8080, applies management migrations and runs forest-training, remote-deployment and assisted-setup jobs. BEHAVIOR_URL links it to the service above. CREDENTIAL_KEY_FILE enables encrypted SSH/Claude credentials.

Terminal 4: Portal

pnpm --dir apps/portal dev --hostname 127.0.0.1 --port 3000

Open http://localhost:3000. Sign in with the private .env administrator settings. For a production-mode local build, replace that command with:

pnpm --dir apps/portal build
pnpm --dir apps/portal start

The portal's origin must equal PUBLIC_ORIGIN. A different portal port needs a matching origin. Cross-machine connections require appropriate private transport/TLS and explicit listener configuration; the loopback defaults intentionally serve only the local machine.

Check running services

curl --fail http://127.0.0.1:8001/health  # Python trainer
curl --fail http://127.0.0.1:8090/health  # Rust behavior service
curl --fail http://127.0.0.1:8080/health  # Rust management API
curl --fail --output /dev/null http://localhost:3000  # portal HTTP response

Health responses check listeners, not successful model training or remote deployment. Inspect job results in the portal.

Optional local Compose alternative

Use this instead of running the foreground services on the same ports. It also starts separate management and behavior PostgreSQL containers. These commands retain their data volumes:

docker compose --env-file .env --env-file .env.expansion -f compose.yaml -f compose.behavior.yaml up --build -d
docker compose --env-file .env --env-file .env.expansion -f compose.yaml -f compose.behavior.yaml ps
docker compose --env-file .env --env-file .env.expansion -f compose.yaml -f compose.behavior.yaml logs --tail 100 api behavior trainer
docker compose --env-file .env --env-file .env.expansion -f compose.yaml -f compose.behavior.yaml stop

This base overlay does not mount the credential-vault key. To enable remote management/Claude in containers, provide a read-only bind mount at /run/secrets/pragma-credentials, set the API's CREDENTIAL_KEY_FILE to that container path, and make that file readable by the container's API user (UID 10001). Keep its host parent directory private; do not make it world-readable. The native setup above reads the generated key directly. Do not use down -v unless you intend to delete the databases and artifact volume.