{"id":45627198,"url":"https://github.com/mchmarny/devpulse","last_synced_at":"2026-04-01T17:51:55.916Z","repository":{"id":37541075,"uuid":"489787696","full_name":"mchmarny/devpulse","owner":"mchmarny","description":"Community health analytics for GitHub organizations and repositories","archived":false,"fork":false,"pushed_at":"2026-03-21T00:06:13.000Z","size":94547,"stargazers_count":6,"open_issues_count":0,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-21T05:14:53.458Z","etag":null,"topics":["cli","cmd","cncf","developer","entitity","golang","sql","sqlite"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mchmarny.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-05-07T21:43:46.000Z","updated_at":"2026-03-21T00:06:17.000Z","dependencies_parsed_at":"2024-06-20T21:51:06.133Z","dependency_job_id":"5652f804-f2a8-427c-ab9f-1e5ac61e3ce1","html_url":"https://github.com/mchmarny/devpulse","commit_stats":{"total_commits":63,"total_committers":3,"mean_commits":21.0,"dds":"0.23809523809523814","last_synced_commit":"957715ed8075d64314ca5aff41e68c3b19c5c3f0"},"previous_names":["mchmarny/devpulse"],"tags_count":100,"template":false,"template_full_name":"mchmarny/cli","purl":"pkg:github/mchmarny/devpulse","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mchmarny%2Fdevpulse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mchmarny%2Fdevpulse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mchmarny%2Fdevpulse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mchmarny%2Fdevpulse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mchmarny","download_url":"https://codeload.github.com/mchmarny/devpulse/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mchmarny%2Fdevpulse/sbom","scorecard":{"id":1243845,"data":{"date":"2026-02-22T21:48:20Z","repo":{"name":"github.com/mchmarny/devpulse","commit":"3d3f26453915481d8d41ed3d1b9b1874f5bb983b"},"scorecard":{"version":"v5.3.0","commit":"c22063e786c11f9dd714d777a687ff7c4599b600"},"score":7.6,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#code-review"}},{"name":"CI-Tests","score":-1,"reason":"no pull request found","details":null,"documentation":{"short":"Determines if the project runs tests before pull requests are merged.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#ci-tests"}},{"name":"Maintained","score":10,"reason":"30 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 10","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":10,"reason":"GitHub workflow tokens follow principle of least privilege","details":["Info: jobLevel 'contents' permission set to 'read': .github/workflows/codeql-analysis.yaml:25","Info: jobLevel 'actions' permission set to 'read': .github/workflows/codeql-analysis.yaml:24","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/release-on-tag.yaml:26","Warn: jobLevel 'contents' permission set to 'write': .github/workflows/release-on-tag.yaml:63","Info: jobLevel 'actions' permission set to 'read': .github/workflows/scan-on-schedule.yaml:36","Info: jobLevel 'contents' permission set to 'read': .github/workflows/scan-on-schedule.yaml:37","Info: jobLevel 'contents' permission set to 'read': .github/workflows/test-on-call.yaml:14","Info: topLevel 'contents' permission set to 'read': .github/workflows/codeql-analysis.yaml:16","Info: topLevel 'contents' permission set to 'read': .github/workflows/release-on-tag.yaml:13","Info: topLevel 'contents' permission set to 'read': .github/workflows/scan-on-schedule.yaml:21","Info: topLevel 'contents' permission set to 'read': .github/workflows/score-on-schedule.yaml:11","Info: topLevel 'contents' permission set to 'read': .github/workflows/test-on-call.yaml:7","Info: topLevel 'contents' permission set to 'read': .github/workflows/test-on-push.yaml:16"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#token-permissions"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dangerous-workflow"}},{"name":"Dependency-Update-Tool","score":10,"reason":"update tool detected","details":["Info: detected update tool: Dependabot: .github/dependabot.yml:1"],"documentation":{"short":"Determines if the project uses a dependency update tool.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#dependency-update-tool"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: Apache License 2.0: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#license"}},{"name":"SAST","score":10,"reason":"SAST tool detected: CodeQL","details":["Info: SAST configuration detected: CodeQL","Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#vulnerabilities"}},{"name":"Pinned-Dependencies","score":8,"reason":"dependency not pinned by hash detected -- score normalized to 8","details":["Warn: goCommand not pinned by hash: vendor/modernc.org/sqlite/tpch.sh:6","Info:  14 out of  14 GitHub-owned GitHubAction dependencies pinned","Info:   6 out of   6 third-party GitHubAction dependencies pinned","Info:   0 out of   1 goCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#pinned-dependencies"}},{"name":"Signed-Releases","score":8,"reason":"5 out of the last 5 releases have a total of 5 signed artifacts.","details":["Info: signed release artifact: checksums-sha256.txt.sigstore.json: https://github.com/mchmarny/devpulse/releases/tag/v0.6.4","Info: signed release artifact: checksums-sha256.txt.sigstore.json: https://github.com/mchmarny/devpulse/releases/tag/v0.6.3","Info: signed release artifact: checksums-sha256.txt.sigstore.json: https://github.com/mchmarny/devpulse/releases/tag/v0.6.2","Info: signed release artifact: checksums-sha256.txt.sigstore.json: https://github.com/mchmarny/devpulse/releases/tag/v0.6.1","Info: signed release artifact: checksums-sha256.txt.sigstore.json: https://github.com/mchmarny/devpulse/releases/tag/v0.6.0","Warn: release artifact v0.6.4 does not have provenance: https://api.github.com/repos/mchmarny/devpulse/releases/289198002","Warn: release artifact v0.6.3 does not have provenance: https://api.github.com/repos/mchmarny/devpulse/releases/289196437","Warn: release artifact v0.6.2 does not have provenance: https://api.github.com/repos/mchmarny/devpulse/releases/289174066","Warn: release artifact v0.6.1 does not have provenance: https://api.github.com/repos/mchmarny/devpulse/releases/289172247","Warn: release artifact v0.6.0 does not have provenance: https://api.github.com/repos/mchmarny/devpulse/releases/289163269"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#signed-releases"}},{"name":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/release-on-tag.yaml:21"],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#packaging"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: some github tokens can't read classic branch protection rules: https://github.com/ossf/scorecard-action/blob/main/docs/authentication/fine-grained-auth-token.md","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#branch-protection"}},{"name":"Contributors","score":10,"reason":"project has 5 contributing companies or organizations","details":["Info: found contributions from: NVIDIA, dapr, knative, nvidia, tektoncd"],"documentation":{"short":"Determines if the project has a set of contributors from multiple organizations (e.g., companies).","url":"https://github.com/ossf/scorecard/blob/c22063e786c11f9dd714d777a687ff7c4599b600/docs/checks.md#contributors"}}]},"last_synced_at":"2026-02-23T01:51:46.761Z","repository_id":37541075,"created_at":"2026-02-23T01:51:46.762Z","updated_at":"2026-02-23T01:51:46.762Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290633,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","cmd","cncf","developer","entitity","golang","sql","sqlite"],"created_at":"2026-02-23T21:14:30.579Z","updated_at":"2026-04-01T17:51:55.907Z","avatar_url":"https://github.com/mchmarny.png","language":"Go","readme":"# devpulse\n\n[![Build Status](https://github.com/mchmarny/devpulse/actions/workflows/test-on-push.yaml/badge.svg)](https://github.com/mchmarny/devpulse/actions/workflows/test-on-push.yaml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/mchmarny/devpulse)](https://goreportcard.com/report/github.com/mchmarny/devpulse)\n[![Go Reference](https://pkg.go.dev/badge/github.com/mchmarny/devpulse.svg)](https://pkg.go.dev/github.com/mchmarny/devpulse)\n[![License: Apache 2.0](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](LICENSE)\n\nCommunity health analytics for GitHub organizations and repositories. `devpulse` imports contribution data from the GitHub API, enriches it with developer affiliations, and surfaces project health insights through a local dashboard. \n\n\u003e Motivation and the drivers behind this project are covered in the blog post [here](https://blog.chmarny.com/posts/devpulse-community-health-analytics-for-the-rest-of-us/)\n\n## Features\n\n**Project Health**\n- **Bus factor / pony factor** -- minimum developers or organizations producing 50% of contributions\n- **Repository Status** -- stars, forks, open issues, language, license with 30-day sparkline\n- **Stars \u0026 forks trends** -- daily star and fork counts over the last 30 days with historical backfill\n- **Community Profile** -- badges for README, Contributing, Code of Conduct, and issue/PR templates\n\n![](docs/img/health.png)\n\n**Activity \u0026 Code**\n- **Activity trends** -- monthly event volume (PRs, reviews, issues, comments, forks) with total and 3-month moving average\n- **PR size distribution** -- pull requests bucketed by lines changed (S/M/L/XL) per month\n- **Forks \u0026 activity** -- monthly fork count vs total event activity\n- **Issue Open/Close Ratio** -- monthly opened vs closed issues\n\n![](docs/img/activity.png)\n\n**Velocity**\n- **Lead time (PR to merge)** -- average days from PR creation to merge\n- **Change failure rate** -- percentage of deployments causing failures (bug issues near releases + revert PRs)\n- **Release cadence** -- monthly release counts (total, stable, deployments) with merge-to-main fallback\n- **Release downloads** -- monthly download trends and top releases by download count\n- **Time to First Response** -- average hours to first review or comment on PRs\n\n![](docs/img/velocity.png)\n\n**Quality**\n- **PR review ratio** -- PRs to reviews per month with ratio trend line\n- **Review latency** -- average hours from PR creation to first review\n- **Time to close** -- average days to close all issues vs bug issues near releases\n- **Contributor reputation** -- two-tier scoring (shallow local, deep GitHub API) with known bot filtering\n\n![](docs/img/quality.png)\n\n**Community**\n- **Contributor retention** -- new vs returning contributors per month\n- **Contributor momentum** -- rolling 3-month active contributor count with month-over-month delta\n- **First-time contributor funnel** -- new contributor milestones per month (first comment, first PR, first merge)\n- **Entity affiliations** -- top contributing companies/orgs with drill-down to individual developers (GitHub profile + CNCF gitdm)\n\n![](docs/img/community.png)\n\n**Insights**\n- **LLM-generated observations** -- AI-powered analysis of repository health, trends, and action items per repo\n\n**Dashboard**\n- **Global summary banner** -- organizations, repositories, events, contributors, and last import timestamp (GMT) at a glance\n- **Tabbed layout** -- Health, Activity, Velocity, Quality, Community, Insights, and Events tabs with lazy-loaded charts\n- **Event search filters** -- filter by type, date range, username, or entity from the Events tab\n- **Adjustable time period** -- dropdown adapts to available data range per search scope\n- **Unified search** -- `org:name` or `repo:name` prefix syntax; all panels respect scope\n\n![](docs/img/global.png)\n\n## Install\n\n### Homebrew (macOS / Linux)\n\n```shell\nbrew tap mchmarny/tap\nbrew install devpulse\n```\n\n### Binary releases\n\nVisit [latest releases](https://github.com/mchmarny/devpulse/releases/latest) page.\n\n### Build from source\n\nRequires [Go](https://go.dev/) 1.26+.\n\n```shell\ngit clone https://github.com/mchmarny/devpulse.git\ncd devpulse\nmake build\n```\n\nSee [DEVELOPMENT.md](DEVELOPMENT.md) for details.\n\n## Quick start\n\n### 1. Authentication\n\n`devpulse` uses GitHub's device flow for OAuth. By default the token requests the `repo` scope for private repository access. Use `--public` to skip the `repo` scope when you only work with public repos. The token is stored in your OS keychain.\n\n```shell\ndevpulse auth            # private + public repo access (default)\ndevpulse auth --public   # public repo access only\n```\n\nAlternatively, set `GITHUB_TOKEN` to skip the auth command entirely:\n\n```shell\nexport GITHUB_TOKEN=ghp_...\n```\n\n### 2. Data import\n\nImport events, affiliations, metadata, releases, and reputation for an org:\n\n```shell\ndevpulse import --org \u003corg\u003e\n```\n\nOr target specific repos:\n\n```shell\ndevpulse import --org \u003corg\u003e --repo \u003crepo1\u003e --repo \u003crepo2\u003e\n```\n\nUse `--fresh` to clear pagination state and re-import from scratch:\n\n```shell\ndevpulse import --org \u003corg\u003e --fresh\n```\n\nUpdate all previously imported data (no flags needed):\n\n```shell\ndevpulse import\n```\n\nControl how many repos import in parallel (default: 3):\n\n```shell\ndevpulse import --concurrency 2\n```\n\nSee [docs/IMPORT.md](docs/IMPORT.md) for all import options.\n\n### 3. Reputation score\n\nImport computes basic reputation scores automatically. For deeper scoring using GitHub API signals (profile age, org membership, PR history, etc.):\n\n```shell\ndevpulse score --org \u003corg\u003e                      # deep-score 5 lowest in org (default)\ndevpulse score --org \u003corg\u003e --repo \u003crepo\u003e        # scope to a specific repo\ndevpulse score --org \u003corg\u003e --count 20           # deep-score 20 lowest\n```\n\nRun incrementally — each invocation scores the next batch of lowest-reputation contributors. See [docs/SCORE.md](docs/SCORE.md) for details.\n\n### 4. Scheduled sync\n\nFor automated, scheduled imports, `sync` reads a config file and imports + scores one repo per run using hour-based round-robin rotation:\n\n```shell\ndevpulse sync --config sync.yaml\ndevpulse sync --config https://raw.githubusercontent.com/org/repo/main/config/sync.yaml\n\n# Override round-robin to sync a specific repo\ndevpulse sync --config sync.yaml --org NVIDIA --repo DCGM\n\n# Sync a specific repo without a config file (uses hardcoded defaults)\ndevpulse sync --org NVIDIA --repo DCGM\n```\n\nConfig format (all `reputation` and `insight` fields are optional with sensible defaults):\n\n```yaml\nrepos:\n  - name: repo1\n    org: myorg\n    reputation:\n      scoreCount: 50        # contributors to deep-score per run (default: 50)\n      staleAfter: \"3d\"      # re-score after this duration (default: 3d)\n    insight:\n      periodMonths: 3       # months of data for insights (default: 3)\n      staleAfter: \"3d\"      # regenerate insights after this (default: 3d)\n  - name: repo2\n    org: myorg\n  - name: devpulse\n    org: mchmarny\n```\n\nThe `--config` flag (or `DEVPULSE_SYNC_CONFIG` env var) accepts a local file path or HTTP(S) URL. Each run picks one repo from the list based on `UTC hour % total repos`, runs a full import, then deep-scores the lowest-reputation contributors. With 9 repos on an hourly schedule, each repo is imported 2-3 times per day while staying within GitHub's 5,000 requests/hour API rate limit. Reputation and insight thresholds are configured per-repo in the YAML file.\n\n### 5. Dashboard view\n\n```shell\ndevpulse server\n```\n\nOpens your browser to `http://127.0.0.1:8080`. Use `--port` to change the port or `--no-browser` to suppress auto-open.\n\nThe dashboard shows a global summary banner (orgs, repos, events, contributors, last import timestamp in GMT) and organizes insights into seven tabs: **Health**, **Activity**, **Velocity**, **Quality**, **Community**, **Insights**, and **Events**. Charts load lazily per tab.\n\nYou can run `devpulse import` in a separate terminal or cron job while the server is running — the dashboard picks up new data immediately after each import transaction commits. See [docs/SERVER.md](docs/SERVER.md) for details.\n\nUse the search bar with prefix syntax to scope the dashboard:\n\n| Prefix | Example | Scope |\n|--------|---------|-------|\n| `org:` | `org:myorg` | All repos in an organization |\n| `repo:` | `repo:skyhook` | Single repository |\n\nNo prefix defaults to org search.\n\n### 6. Programmatic query\n\n`devpulse` also exposes data as JSON for scripting:\n\n```shell\ndevpulse query events --org knative --repo serving --type pr --since 2024-01-01\ndevpulse query developer list --like mark\ndevpulse query entity detail --name GOOGLE\n```\n\nSee [docs/QUERY.md](docs/QUERY.md) for all query options.\n\n### 7. Data deletion\n\nRemove imported data for a specific org or repo:\n\n```shell\ndevpulse delete --org \u003corg\u003e                          # delete all data for org\ndevpulse delete --org \u003corg\u003e --repo \u003crepo\u003e            # delete data for specific repo\ndevpulse delete --org \u003corg\u003e --repo \u003crepo\u003e --force    # skip confirmation prompt\n```\n\n### 8. Full reset\n\nDelete all imported data and start fresh:\n\n```shell\ndevpulse reset\n```\n\nPrompts for confirmation before deleting the database.\n\n## Data sources\n\n| Source | Data |\n|--------|------|\n| [GitHub API](https://docs.github.com/en/rest) | PRs, issues, comments, reviews, forks, repo metadata, releases |\n| [cncf/gitdm](https://github.com/cncf/gitdm) | Developer-to-company affiliations |\n\nEntity names are normalized automatically. Use `devpulse substitute` to correct misattributions:\n\n```shell\ndevpulse substitute --type entity --old \"INTERNATIONAL BUSINESS MACHINES\" --new \"IBM\"\n```\n\n## Database\n\nBy default, data is stored locally in [SQLite](https://www.sqlite.org/) (`~/.devpulse/data.db`). No external services required.\n\n### PostgreSQL\n\nTo use PostgreSQL instead, pass a `postgres://` connection URI via `--db` or `DEVPULSE_DB`:\n\n```shell\ndevpulse import --db \"postgres://user:pass@host:5432/dbname?sslmode=disable\" --org \u003corg\u003e --repo \u003crepo\u003e\ndevpulse server --db \"postgres://user:pass@host:5432/dbname?sslmode=disable\"\n```\n\nOr via environment variable:\n\n```shell\nexport DEVPULSE_DB=\"postgres://user:pass@host:5432/dbname?sslmode=disable\"\ndevpulse import --org \u003corg\u003e --repo \u003crepo\u003e\n```\n\nMigrations run automatically on first connection. Special characters in the password must be URL-encoded (e.g., `/` → `%2F`, `@` → `%40`).\n\nFor Google Cloud AlloyDB, connect through the [AlloyDB Auth Proxy](https://cloud.google.com/alloydb/docs/auth-proxy/overview) with `--public-ip` and use `127.0.0.1` as the host.\n\n### LLM (Insights tab)\n\nThe Insights tab uses an LLM to generate observations and action items. Configure via environment variables:\n\n```shell\nexport ANTHROPIC_API_KEY=\"sk-ant-...\"        # required for Insights tab\nexport ANTHROPIC_BASE_URL=\"https://...\"      # optional, override API endpoint\nexport ANTHROPIC_MODEL=\"claude-...\"          # optional, override model selection\n```\n\n## Architecture\n\nSee [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for details.\n\n## Verification\n\nRelease binaries are signed and attested in CI. No private keys — everything uses keyless [Sigstore](https://www.sigstore.dev/) OIDC via GitHub Actions.\n\n### Verify checksum signature\n\n```shell\ncosign verify-blob \\\n  --bundle checksums-sha256.txt.sigstore.json \\\n  --certificate-identity-regexp 'github.com/mchmarny/devpulse' \\\n  --certificate-oidc-issuer https://token.actions.githubusercontent.com \\\n  checksums-sha256.txt\n```\n\n### Verify build provenance\n\n```shell\ngh attestation verify \u003cbinary\u003e -R mchmarny/devpulse\n```\n\n### Inspect SBOM\n\nEach binary has a corresponding SBOM (SPDX JSON) attached to the release.\n\n## Contributing\n\nContributions are welcome. Please open an issue before submitting large changes. See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines and [DEVELOPMENT.md](DEVELOPMENT.md) for setup.\n\n1. Fork and clone the repository\n2. Create a feature branch\n3. Run `make qualify` (tests, lint, vulnerability scan)\n4. Submit a pull request\n\n## License\n\n[Apache 2.0](LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmchmarny%2Fdevpulse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmchmarny%2Fdevpulse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmchmarny%2Fdevpulse/lists"}