Developing WhyGraph¶
Working on WhyGraph itself (not using it) takes four make targets from a checkout:
| Command | Mode | What it runs |
|---|---|---|
make dev-local |
Development, native | The portal from your checkout on :8777, restarted on every backend change, plus the Vite dev server with hot reload on :5173, against the dev Postgres from make dev-db (started for you). Fastest; your IDE's debugger works. |
make dev-docker |
Development, in Docker | The same, inside the WhyGraph image through the real whygraph up shim, with your checkout mounted read-only over the installed package. |
make prod |
Production | The image built exactly like a release (pinned CodeGraph, the pyproject.toml version), run through the shim with no source mounted: what users get. |
make check |
Before a pull request | Both ruff checks, pytest, the frontend typecheck / tests / build, the Playwright suite, then the release smoke test against a freshly built image. Stops at the first failure. |
dev-local and dev-docker run in the foreground: open http://localhost:5173, and press
Ctrl-C to stop everything. prod serves the built UI itself on http://127.0.0.1:8777.
The portal database in development¶
The portal keeps its own data in Postgres, so every mode needs one:
make dev-localdepends onmake dev-db, which starts (or reuses) a container,whygraph-dev-postgres, laid out like the shim's database container (the same pinned image, read fromPOSTGRES_IMAGEincli/commands/install.py, a per-majorPGDATA, your user, the same health check) but published on127.0.0.1:55432(PG_DEV_PORT=...to change it) with the dev-only passwordwhygraph-dev. Its files are in$TMPDIR/whygraph-dev/local/postgres, beside the dev data directory.make dev-dbwaits until it is healthy;make dev-localthen points the portal at it withWHYGRAPH_DATABASE_URL=postgresql+psycopg://whygraph:whygraph-dev@127.0.0.1:55432/whygraph.make dev-db-downstops and removes the container and keeps its files; delete the directory for a fresh database.make dev-dockerandmake prodgo through the real shim, so they get their own database container,whygraph-portal-dev-postgres/whygraph-portal-prod-postgres, which their Ctrl-Cwhygraph downstops with the portal.make e2estarts a throwaway Postgres (in memory) for its portal and removes it afterwards.
make dev-db and make dev-db-down are listed by make like every other helper.
Which one to use¶
dev-localfor most work: the UI, routes, MCP tools, chat. A saved.pyfile undersrc/whygraph/restarts the portal within a few seconds (RELOAD=0turns that off); a saved.tsxfile hot-reloads in the browser.dev-dockerfor anything that behaves differently in the container: the shim (cli/commands/install.py), the Dockerfile, file ownership, paths, the environment a scan gets, and the in-imagegit/gh/codegraph. It rebuilds the image only when its inputs change (pyproject.toml,uv.lock, the Dockerfile,package-lock.json); everyday edits reach the container through the mount.make checkalways, before pushing. Its smoke test catches whatdev-localcannot see.
What stays isolated¶
Every mode keeps to itself, so none of them touches your own portal:
- its own container name (
whygraph-portal-dev,whygraph-portal-prod, andwhygraph-portal-smokefor the smoke test), data directory andHOME, all under$TMPDIR/whygraph-dev; - one scratch folder of repos,
$TMPDIR/whygraph-dev/repos, shared by every mode and created offline on first use: a copy of your checkout (git clone --no-hardlinks, real history to dogfood) and a tiny three-commit demo repo. Delete one to get a fresh copy next time.
Your checkout itself is never added to a dev portal, so it never gets WhyGraph's hooks or markers
and whygraph scan keeps working in it.
The three run modes share port 8777, so run one at a time. Override it with DEV_PORT=....
Helpers¶
| Command | What it does |
|---|---|
make test |
pytest only |
make e2e |
The Playwright suite against a throwaway portal and a fake scanner, both themes (ARGS="--project=light" for one) |
make inspect SLUG=<slug> |
The MCP Inspector against a project's /mcp/<slug> on the running dev portal |
make db SLUG=<slug> |
A DBGate viewer on :8081 for a scratch repo's two databases, plus a Portal connection to the make dev-db Postgres (through host.docker.internal:55432). Copy docker-compose.example.yml to docker-compose.yml first; an older copy needs refreshing to get the Portal connection |
make dev-db / make dev-db-down |
Start (and wait for) / stop the dev portal's Postgres; see above |
make image |
Build the image like the release does (IMAGE=... to retag) |
make docs / make docs-build |
Serve this site with live reload / build it strictly, as CI does |
Requirements and gotchas¶
- Node 22.12 or newer for the playground toolchain (
nvm use 22). - Docker for
dev-local(its Postgres),dev-docker,prod,make e2eandmake check. - The tests need a Postgres. The portal tests run against a real one: by default
pyteststarts a throwaway container of the pinned image for the session (on a random loopback port, in memory) and gives every test its own database, so plainuv run pytestneeds Docker. Without Docker, setWHYGRAPH_TEST_DATABASE_URLto an admin URL of a Postgres you run (the role needsCREATEDB), for examplepostgresql+psycopg://postgres:test@127.0.0.1:5432/postgres; CI does exactly that with a service container.WHYGRAPH_TEST_POSTGRES_IMAGEreplaces the throwaway server's image, for a registry mirror. With neither Docker nor the URL, the portal tests fail with a message saying so - they are never skipped. uv runsyncs first, which fails behind a TLS-intercepting proxy. Run the targets withUV_NO_SYNC=1 make ...(orUV_RUN="uv run --no-sync") there.- The Docker modes use two development-only shim settings,
WHYGRAPH_DEV_SRCandWHYGRAPH_PORTAL_NAME. They are not part of the supported interface.