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 |
|---|---|
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