SQLite-first pipeline importer and local UI for exploring GitLab CI timings as an end-to-end waterfall.
- Imports one GitLab pipeline run into SQLite.
- Stores:
- pipeline timestamps
- job timestamps
- parsed trace sections
- Renders one imported pipeline as a browser-network-tab style timeline.
SQLite is the system of record.
scraper.py: CLI importer (SQLite write path)data/: local DB (ignored by git)frontend/: Next.js app (SQLite read path)
- Python 3.11+
GITLAB_TOKENin the environment
- Create a virtualenv and install dependencies:
python3 -m venv .venv
. .venv/bin/activate
pip install -r requirements.txt- Initialize the database:
python3 scraper.py db-init- Import one pipeline by project path + pipeline id:
python3 scraper.py import-pipeline acme/frontend-app 2439631130- Import the most recent pipelines for one project:
python3 scraper.py import-recent acme/frontend-app --limit 5- Start the frontend:
cd frontend
npm install
npm run dev- Use a custom database path if needed:
python3 scraper.py --db-path ./data/custom.sqlite import-pipeline acme/frontend-app 2439631130GITLAB_TOKEN: personal access token with read access to the relevant GitLab projectsGITLAB_URL: optional, defaults tohttps://gitlab.comCI_EXPLORER_DB_PATH: optional frontend override for the SQLite database path
Default DB path:
./data/gitlab-ci.sqlite
Initialize schema:
python3 scraper.py db-initImport one pipeline:
python3 scraper.py import-pipeline <project-path> <pipeline-id>Import the most recent pipelines for one project:
python3 scraper.py import-recent <project-path> --limit 10gitlab_project: project identitygitlab_pipeline: pipeline-level timing envelopegitlab_job: job-level timeline anchors, including derivedstarted_queueing_at_utcgitlab_job_section: parsed trace sections, plus optional diagnostic details for enriched phases
The viewer will treat timestamps as canonical.
Important notes:
job.started_queueing_at_utcis derived from:job.started_at - job.queued_duration
job.created_at_utc -> job.started_queueing_at_utcrepresents blocked / dependency wait time.job.started_queueing_at_utc -> job.started_at_utcrepresents runnable queue time.
The primary view is one pipeline run:
- global time axis from
pipeline.created_at_utctopipeline.finished_at_utc - one row per job
- nested sections inside jobs
- visible blocked / queued / execution phases
Current enriched breakdowns:
prepare_script: scheduling, scale-up wait, pod startup, service startup, finalizerestore_cache: download, extractarchive_cache: pack, upload