Skip to content

Local Development

Running Vega locally means starting a FastAPI backend, a React frontend, and optionally ingest and scan worker processes — all on your machine. The default configuration stores all data in JSON files under data/, so you don't need a database or AWS account to get started.

Before you begin

You'll need:

  • Python 3.12+ for the backend
  • Node.js 18+ for the frontend
  • Git with submodule support (the scan engine is a submodule)
  • Docker if you want local scans to run the Codex container

Clone the repo and initialize the scan engine submodule:

git clone <repo-url>
cd vega-backend
git submodule update --init --recursive

Submodule required

The vega-core/ directory is a git submodule. If you skip git submodule update, the backend will fail to import the scan engine and scans will not work.

Step 1 — Start the backend

python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --reload --reload-dir app

The API starts on http://localhost:8000. All routes are under /api (e.g., http://localhost:8000/api/healthz). The /v1 prefix is also accepted as a compatibility alias.

--reload --reload-dir app watches the app/ directory and automatically restarts the server when you change Python files.

Step 2 — Start the frontend

In a second terminal:

cd frontend
npm install
npm run dev

The Vite dev server starts on http://localhost:5173. It automatically proxies /api/* and /v1/* requests to the backend on port 8000, so the frontend and backend talk to each other without any extra configuration.

Step 3 — Log in

Open http://localhost:5173 in a browser. The default dev credentials are:

Field Value
Email debug@example.com
Password vega-debug-password

To test login from the command line:

curl -s http://localhost:8000/api/auth/login \
  -H 'content-type: application/json' \
  -d '{"email":"debug@example.com","password":"vega-debug-password"}'

The response includes an access_token you can use in subsequent requests with -H "Authorization: Bearer <token>".

Debug auth is local-only

These credentials only work when VEGA_AUTH_PROVIDER=custom (the default). In AWS, Cognito handles authentication and these credentials are disabled.

Step 4 (optional) — Run workers

By default, VEGA_SCAN_EXECUTION_MODE=thread, which means the API process runs scans directly inside a background thread. This is the simplest setup.

For a more realistic setup that mirrors production, set VEGA_SCAN_EXECUTION_MODE=external for the API and run the scan worker separately:

# Terminal 1 — API with external scan execution
VEGA_SCAN_EXECUTION_MODE=external uvicorn app.main:app --reload --reload-dir app

# Terminal 2 — scan worker
python scripts/run-scan-worker.py

Similarly, if you want ingest to run asynchronously:

# Terminal 1 — API with external ingest
VEGA_REPO_INGEST_EXECUTION_MODE=sqs uvicorn app.main:app --reload --reload-dir app

# Terminal 2 — ingest worker
python scripts/run-repo-ingest-worker.py

In these modes, the API queues jobs and the workers claim and execute them. See Scan Lifecycle for details.

Step 5 (optional) — Build the Codex runner image

Local scans invoke Codex in an isolated Docker container by default. Before running your first scan locally, build the Codex runner image:

scripts/build-codex-runner-image.sh

This builds vega-codex-runner:latest from docker/codex-runner/Dockerfile. Skip this if you're overriding VEGA_CORE_CODEX_BIN to point to a direct codex binary.

Running tests

pytest

For faster feedback while working on a subsystem:

pytest tests/application/             # use-case logic
pytest tests/api/                     # route handlers
pytest tests/domain/                  # domain boundary validation

What lives in data/

When running with the default JSON persistence (VEGA_PERSISTENCE_BACKEND=json), all state is stored under data/:

data/
├── projects.json
├── repositories.json
├── scans.json
├── findings.json
├── events.json
├── ingest_jobs.json
├── snapshots/        ← extracted source ready for scanning
├── artifacts/        ← scan output files
├── uploads/          ← uploaded zip archives
└── git/              ← cloned git repos

To start fresh, stop the processes and delete the data/ directory. The backend will recreate it.

Using Postgres locally

If you prefer a real database locally (useful for testing queries or migrations):

# Start Postgres (Docker example)
docker run -d --name vega-pg -p 5432:5432 \
  -e POSTGRES_USER=vega -e POSTGRES_PASSWORD=vega -e POSTGRES_DB=vega \
  postgres:16

# Apply migrations
VEGA_DATABASE_URL=postgresql://vega:vega@localhost:5432/vega \
python scripts/run-db-migrations.py

# Start the API with Postgres
VEGA_PERSISTENCE_BACKEND=postgres \
VEGA_DATABASE_URL=postgresql://vega:vega@localhost:5432/vega \
uvicorn app.main:app --reload --reload-dir app