This repository tracks community metrics for Lance and LanceDB, stores them in LanceDB Enterprise, and renders a read-only dashboard frontend.
Architecture split:
- Write path: Python ingestion jobs run on a private host (for example EC2 + cron).
- Read path: Next.js dashboard app serves
/api/v1/dashboard/dailyand is deployed to Vercel.
- SDK downloads:
pylance(PyPI)lance(crates.io)lancedb(PyPI)@lancedb/lancedb(npm)lancedb(crates.io)
- GitHub stars:
lance-format/lancelancedb/lancedblance-format/lance-graphlance-format/lance-context
- DuckDB
lanceextension downloads:- core repository:
extensions.duckdb.org - community repository:
community-extensions.duckdb.org
- core repository:
- Python managed with
uv - Frontend managed with
npm - A running LanceDB Enterprise cluster
Create .env in the repo root (or update existing):
LANCEDB_API_KEY=...
LANCEDB_HOST_OVERRIDE=https://<your-enterprise-host>
LANCEDB_REGION=us-east-1
# Strongly recommended for scheduled ingestion:
GITHUB_TOKEN=...
# Required only for weekly LLM guidance generation:
OPENAI_API_KEY=...GITHUB_TOKEN should stay configured on the machine running scheduled updates.
OPENAI_API_KEY is only used by generate_signal_guidance; dashboard requests do not call OpenAI.
Tables:
metrics: metric definitionsstats: daily observations keyed by(metric_id, period_end)history: ingestion run logsdashboard_metric_rollups: derived dashboard windows and growth comparisonsevidence_items: derived/manual community evidence, currently not used by Insightssignal_candidates: derived DevRel signal candidates generated from metric rollupssignal_guidance: weekly cached LLM guidance generated from metric signals and rollupsduckdb_lance_extension_downloads_monthly: monthly DuckDBlanceextension downloads split by core/community repository
metrics, stats, and history are the source-of-truth tables. The dashboard-derived
tables can be recreated from source data and external evidence collectors.
DuckDB extension download rows are isolated in their own monthly table and do not modify
metrics, stats, history, or the derived dashboard tables.
Daily row semantics in stats:
period_start == period_end- routine provenance:
api_daily - recompute provenance:
recomputed - download
source_window:1d - star
source_window:cumulative_snapshot
All writes happen directly through LanceDBStore.
No FastAPI/uvicorn runtime is required.
uv run python -m community_metrics.jobs.bootstrap_tables
uv run python -m community_metrics.jobs.update_all --lookback-days 90uv run python -m community_metrics.jobs.daily_refreshFor ad-hoc correction windows:
uv run python -m community_metrics.jobs.daily_refresh --lookback-days 7Registry requests use a descriptive user agent plus bounded retry/backoff for HTTP
429 and transient 5xx responses. If an otherwise successful registry response omits
a target day, the refresh leaves that (metric_id, period_end) absent instead of
writing a synthetic zero; the next incremental run retries it. After a collection
outage or suspected stale zero, recompute a bounded window with --lookback-days.
One-time star-history backfill for newly added GitHub repos:
uv run python -m community_metrics.jobs.update_daily_stars --lookback-days 180One-time download snapshot backfill for older month-end history:
uv run python one_time_snapshot_backfill.py
uv run python one_time_snapshot_backfill.py --applyMonthly DuckDB lance extension download refresh:
uv run python -m community_metrics.jobs.update_duckdb_extension_downloadsThis recomputes monthly rows from January 2026 through the current month, marks the
current month as partial, and writes only duckdb_lance_extension_downloads_monthly.
Run daily at 09:00 UTC:
0 9 * * * cd /path/to/community-metrics && /usr/bin/env -S bash -lc 'uv run python -m community_metrics.jobs.daily_refresh >> /var/log/community-metrics/daily_refresh.log 2>&1'Run monthly DuckDB extension refresh at 10:00 UTC on the first day of each month:
0 10 1 * * cd /path/to/community-metrics && /usr/bin/env -S bash -lc 'uv run python -m community_metrics.jobs.update_duckdb_extension_downloads >> /var/log/community-metrics/update_duckdb_extension_downloads.log 2>&1'The dashboard lives in src/dashboard and fetches:
GET /api/v1/dashboard/daily?days=180- Google SSO (restricted to
@lancedb.comaccounts)
cd src/dashboard
npm install
npm run devSet these frontend env vars in src/dashboard/.env.local (local) or Vercel project settings (deployment):
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
NEXTAUTH_SECRET=...
NEXTAUTH_URL=http://127.0.0.1:3000For local dashboard testing only, Google auth can be bypassed:
DISABLE_AUTH_LOCAL=1This flag is only honored when Next.js runs with NODE_ENV=development; production builds still require Google SSO.
Restart npm run dev after changing .env.local because Next.js reads these values at server startup.
Google OAuth app setup must include this callback URI:
http://127.0.0.1:3000/api/auth/callback/googleSet these in the Vercel project:
LANCEDB_API_KEY=...
LANCEDB_HOST_OVERRIDE=https://<your-enterprise-host>
LANCEDB_REGION=us-east-1
GOOGLE_CLIENT_ID=...
GOOGLE_CLIENT_SECRET=...
NEXTAUTH_SECRET=...
NEXTAUTH_URL=https://<your-dashboard-domain>The route is read-only by code path and only queries bounded dashboard windows. If/when available, use a dedicated read-scoped key for Vercel.
- Download chart points are monthly totals.
- Download card headline values are the last full-month totals.
- The dashboard now fetches 730 days of history by default so seeded monthly snapshots remain visible.
- Through
2025-11-30, download points come from seeded discrete snapshots. - If the live table is missing a
2025-11-30snapshot row, the dashboard synthesizes that month from the arithmetic mean of the October 2025 and December 2025 monthly values. - From
2025-12-01onward, monthly download points are aggregated from daily rows. - Star charts remain daily cumulative series.
- Total stars combine all tracked GitHub star repos.
- DuckDB
lanceextension downloads start at January 2026 and are read fromduckdb_lance_extension_downloads_monthly; the widget displays the latest community+core total with community and core monthly lines on one chart. - The Insights tab reads precomputed
signal_candidates,dashboard_metric_rollups, andsignal_guidance. - HN/manual mention bursts are disabled for Insights and guidance because the signal is too noisy.
- LLM guidance is cached in
signal_guidance; the dashboard never calls OpenAI during page load.
Derived jobs keep dashboard reads small and avoid recomputing expensive windows at request time:
uv run python -m community_metrics.jobs.derive_dashboardWhat is precomputed:
dashboard_metric_rollups: 7d, 15d, 30d, 90d, and last-full-month values; prior-window values; deltas; percent changes; SDK share; SDK share deltas; recent trend slope.signal_candidates: deterministicdownload_spike,sustained_growth, andsdk_share_shiftsignals for DevRel review.evidence_items: HN/manual evidence remains stored if collected, but is excluded from Insights, social burst generation, and guidance prompts.signal_guidance: weekly OpenAI-generated DevRel guidance with citations to concrete signal and rollup IDs.
First-time setup or backfill for the Insights tab:
# 1. Ensure source tables are current.
uv run python -m community_metrics.jobs.daily_refresh --lookback-days 30
# 2. Build derived rollups and deterministic signal candidates.
uv run python -m community_metrics.jobs.derive_dashboard
# 3. Generate cached LLM guidance for the latest weekly signal window.
uv run python -m community_metrics.jobs.generate_signal_guidance --window-days 7Normal weekly LLM guidance cadence:
uv run python -m community_metrics.jobs.daily_refresh --lookback-days 7
uv run python -m community_metrics.jobs.derive_dashboard
uv run python -m community_metrics.jobs.generate_signal_guidance --window-days 7generate_signal_guidance uses the latest 7d rollups as the primary assessment window, compares against 15d and 30d rollups, excludes HN/manual evidence, and keeps generated numbers to at most 1 decimal place. Defaults:
COMMUNITY_METRICS_OPENAI_MODEL=gpt-5.5COMMUNITY_METRICS_OPENAI_REASONING_EFFORT=highCOMMUNITY_METRICS_GUIDANCE_PROMPT_VERSION=v2COMMUNITY_METRICS_OPENAI_TIMEOUT_SECONDS=600
The guidance job requires OPENAI_API_KEY. It writes to signal_guidance and may be safely rerun for the same weekly window; rows are upserted by guidance ID. The dashboard will show "guidance pending" for any signal that does not yet have a matching guidance row.
HN/manual evidence collection is intentionally excluded from the current Insights and guidance path. Future GitHub downstream dependency evidence should only count exact dependencies found in package manifests or lockfiles.
| Job | Use this for | Command |
|---|---|---|
daily_refresh |
Normal daily updates (scheduled) | uv run python -m community_metrics.jobs.daily_refresh |
update_all |
Recompute/backfill a full lookback window | uv run python -m community_metrics.jobs.update_all --lookback-days 90 |
bootstrap_tables |
Destructive reset/recreate before rebuild | uv run python -m community_metrics.jobs.bootstrap_tables |
collect_hn_evidence |
Collect recent Hacker News evidence into derived evidence table, currently excluded from Insights/guidance | uv run python -m community_metrics.jobs.collect_hn_evidence --lookback-days 30 |
derive_dashboard |
Recompute dashboard rollups and signal candidates | uv run python -m community_metrics.jobs.derive_dashboard |
generate_signal_guidance |
Generate weekly cached LLM guidance for the Insights tab | uv run python -m community_metrics.jobs.generate_signal_guidance --window-days 7 |
update_duckdb_extension_downloads |
Refresh monthly DuckDB lance extension downloads |
uv run python -m community_metrics.jobs.update_duckdb_extension_downloads |
debug.py reads LanceDB Enterprise tables directly (no REST API required):
uv run debug.py metrics
uv run debug.py stats --metric-id downloads:lance:python --days 30
uv run debug.py history --start-date 2026-01-01 --end-date 2026-12-31 --limit 200
uv run debug.py allFormat and lint Python:
uv run ruff format .
uv run ruff check --fix --select I .Run tests:
uv run pytest -q