Skip to content

Polyglot repository layout (Python + web viewer)

This repository is Python-first: the package, CLI, tests, and Makefile live at the repo root. The GI/KG viewer (RFC-062) is a separate Node project under web/gi-kg-viewer/.

Treat them as two toolchains that share one git tree, not one unified npm workspace (by design).


Quick comparison

Area Location Install / run
Python app (CLI, pipeline, FastAPI server) Repo root (pyproject.toml, src/) python3 -m venv .venv, source .venv/bin/activate, make init or pip install -e ".[…]"
Viewer UI (Vue 3 + Vite + TypeScript) web/gi-kg-viewer/ (package.json) cd web/gi-kg-viewer && npm install; npm run dev / npm run build / npm run test:*

End-to-end viewer (API + built SPA in one process): install [dev], build dist/ under web/gi-kg-viewer, then python -m podcast_scraper.cli serve --output-dir …. See Server Guide and web/gi-kg-viewer/README.md.


Environment files (two purposes)

File Purpose
config/examples/.env.example Copy to repo root .env for Python: API keys, CACHE_DIR, logging, optional PODCAST_SCRAPER_*, etc. (CONFIGURATION.md; twelve-factor config).
web/gi-kg-viewer/.env.example Copy to web/gi-kg-viewer/.env for Vite only: VITE_DEFAULT_CORPUS_PATH (pre-fills the shell corpus path for Graph tab auto-load — API corpus path only; offline file-picker loads skip topic_clusters.json fetch and sibling merge), VITE_CLUSTER_SIBLING_EPISODE_CAP (Graph tab topic-cluster sibling auto-load), VITE_DEFAULT_GRAPH_LENS_DAYS (Graph time-lens lower bound on first auto-load: positive integer = "last N days" — production default 7; 0 or empty = "all time", used by the stack-test viewer build so static fixture publish dates aren't filtered out). Vite loads .env* next to the app by default.

Root .gitignore already ignores .env, .env.local, and similar patterns so secrets are not committed from either location.


Git ignores (viewer)

Node / Vite / Playwright artifacts for the viewer (node_modules/, dist/, Playwright reports, log files, etc.) are listed under web/gi-kg-viewer/ in the repository root .gitignore. There is no separate web/gi-kg-viewer/.gitignore.


Makefile targets (run from repo root)

All of these assume an activated Python venv when Python is involved.

The viewer directory is WEB_VIEWER_DIR in the root Makefile (default web/gi-kg-viewer). You can override it for a one-off command, e.g. make serve-ui WEB_VIEWER_DIR=path/to/viewer.

Target What it does
make serve SERVE_OUTPUT_DIR=… Parallel: FastAPI (serve-api) + Vite dev (serve-ui); UI usually on 5173, API on 8000.
make serve-api SERVE_OUTPUT_DIR=… FastAPI only.
make serve-ui Vite only in web/gi-kg-viewer (proxies /api8000).
make serve-e2e-mock E2E fixture HTTP server (RSS + mock API paths) on 127.0.0.1; default port 18765 (E2E_MOCK_PORT). Use --feeds-spec with fixture URLs on that host/port (primary p01–p05 + long-form p07–p09; skips p06 edge cases) (E2E Testing Guide).
make test-ui Vitest unit tests for TS utils under web/gi-kg-viewer (no browser).
make test-ui-e2e Playwright E2E (Firefox); installs npm deps and browsers as needed.
make verify-gil-offsets-strict Validates GIL Quote offsets against FAISS transcript chunk spans on disk (GIL_OFFSET_VERIFY_DIR). See Semantic Search Guide.

CI runs the same web/gi-kg-viewer paths; see .github/workflows/python-app.yml.


Invoking viewer tools — npm / ./node_modules/.bin/ (not npx)

The Node analog of Python's .venv is web/gi-kg-viewer/node_modules/ — a per-project, gitignored dependency folder. Use it the same way you'd use .venv/bin/<tool> for Python: invoke project-pinned binaries, not ambient ones.

Python Node (viewer)
.venv/bin/python node_modules/.bin/<tool>
pyproject.toml / requirements.txt package.json (deps + lockfile)
source .venv/bin/activate npm run <script> (auto-prepends node_modules/.bin to PATH for that script)

Use these:

cd web/gi-kg-viewer
npm install                       # creates / updates node_modules
npm run test:e2e                  # Playwright via project-pinned CLI
npm run test:unit                 # Vitest
npm run dev                       # Vite dev server
./node_modules/.bin/playwright test some.spec.ts -g "..."  # equivalent direct invocation

Avoid npx <tool> for viewer tooling. The viewer pins @playwright/test (which exposes its CLI as node_modules/.bin/playwright) but not a separate package literally named playwright. npx playwright doesn't find a playwright package in node_modules, silently fetches a fresh copy from the npm registry into a temp dir, and runs that. The freshly-fetched runner then loads spec files whose import { test } from '@playwright/test' resolves to the project's node_modules/@playwright/testtwo module instances at the same version, no shared internal state. The runner's internal test registry rejects test.describe() calls from the spec with:

Error: Playwright Test did not expect test.describe() to be called here. … You have two different versions of @playwright/test.

The worker process crashes; the parent shell sees exit code 137 (SIGKILL). Easy to misread as "user canceled" or OOM. The smoking gun is npm warn exec The following package was not found and will be installed: playwright@… near the top of the output.

npx is not the Node equivalent of python -m. python -m only loads from the current interpreter; npx falls back to fetching from the registry if the literal name isn't in node_modules. Reach for npm run … or ./node_modules/.bin/… instead.