DocsDemoGitHub
§11.1

Run it locally

Docker Compose brings up PostgreSQL 19, applies the committed migrations, loads the seed, and serves the graph over MCP.

From the repository rootdocker compose -f deploy/docker-compose.yml up -d --build

The build context is the repository root, so schema/ is reachable; run it from anywhere else and the mounts will not resolve. Tear it down, database included, with:

docker compose -f deploy/docker-compose.yml down -v

What comes up

postgreslong-runningpostgres:19beta2, pinned to the same tag gopgql targets. SQL/PGQ is a PostgreSQL 19 feature; there is no fallback on 18. Published on loopback only.
migrateone-shotApplies schema/migrations/ with goose, then exits. Everything downstream waits on it completing successfully.
seedone-shotLoads deploy/seed/seed.sql. The only writer M1 has, and the one service that goes away at M2.
mcplong-runninggopgql-mcp --sdl /schema/codiq.graphql on127.0.0.1:8080, with /healthz next to/mcp.

Ports and credentials

postgres 127.0.0.1:5432 codiq / codiq / codiq mcp 127.0.0.1:8080/mcp 127.0.0.1:8080/healthz

Both are bound to loopback on purpose: an example database with example credentials has no business being reachable from the network.

SPEC.md §11.1 shows GOPGQL_DATABASE_URL. The binaries do not read that — both gopgql and gopgql-mcp readGOPGQL_DSN, and the compose file binds the one connection string to that name. CODIQ_DATABASE_URL is the separate name §11.1 gives the same value for CodiQ's own ingestion service, which arrives at M2; theseed service reads it today. Setting onlyGOPGQL_DATABASE_URL gets you a server that cannot find the database.

Talking to the property graph directly

The CREATE PROPERTY GRAPH view is named app_graph — gopgql's default, with no flag to change it. You need the name only for hand-written SQL/PGQ; the GraphQL surface never mentions it.

SELECT * FROM GRAPH_TABLE(app_graph MATCH (o IS occurrence) COLUMNS (o.name, o.role, o.descriptor) ) LIMIT 5;

Check it came up

docker compose -f deploy/docker-compose.yml ps -a SERVICE STATE STATUS mcp running Up 25 seconds (healthy) migrate exited Exited (0) 28 seconds ago postgres running Up About a minute (healthy) seed exited Exited (0) 26 seconds ago

migrate and seed exiting 0 is the success case — they are one-shot jobs, not services that died. The migration log names both files:

migrate-1 | OK 0001_core_tables.sql (111.4ms) migrate-1 | OK 0002_core_graph.sql (109.98ms) migrate-1 | goose: successfully migrated database to version: 2 migrate-1 | gopgql: applied /migrations

Point an agent at it

.mcp.json{ "mcpServers": { "codiq": { "type": "http", "url": "http://127.0.0.1:8080/mcp" } } }

The server is long-running and speaks streamable HTTP, so several agents can share one process. It exposes two tools — introspect, for finding out what is queryable without touching the database, andquery, for running a GraphQL operation against it. Seethe demo for five worked exchanges against the corpus this seed loads.

Talking to Postgres directly

M1 has no ingestion pipeline, so inserting rows by hand is the supported way to get data in — that is what the seed does.

psql postgres://codiq:codiq@127.0.0.1:5432/codiq codiq=# \dt codiq=# SELECT path, lang, pkg_name FROM file; codiq=# SELECT role, symbol_kind, name, descriptor FROM occurrence ORDER BY file_id, range_start;

Re-running the seed is a no-op rather than a duplicate corpus: it deletes everything owned by its three files and rewrites it, in the same shape §6 gives the real reduce phase.

deploy/gopgql.Dockerfile builds gopgql andgopgql-mcp from commit 85a2f68, because gopgql has cut no v* tag and ghcr.io/gaarutyunov/gopgql does not exist yet — the escape hatch §14 M1 allows. The ref is a commit rather than a branch so that a rebuild is the same stack on a different day. That makes the first--build slow (it compiles two Go binaries) and subsequent ones cached. Swapping to the published image later is deleting that file and giving the two services an image: line.

Not running yet

deploy/initdb/01-dbos.sql creates the codiq_dbosdatabase on first boot so it is there when M3 needs it; nothing reads it until then. The codiq ingestion service and the sharedartifacts volume are commented out in the compose file, ready to slot in at M2 and M5 without a reshuffle. Seethe pipeline.