Skip to content

Contributing

jamesconwaydev edited this page Nov 6, 2026 · 2 revisions

Want to fix a bug, tighten a check or make the site nicer? Good. The rules for contributing live in CONTRIBUTING.md, and this page doesn't repeat them. What it adds is the map: which bot does what, and where your change fits.

Just want a repo listed? You don't need any of this. Use the Submit a repo form.

The short version of CONTRIBUTING.md

  • Fork, branch from main, make your change with tests, and open a pull request.

  • Run the checks before you push:

    python3 -m unittest discover -s scripts -t .
    npm --prefix site test
    npx prettier --check .
  • Use Conventional Commits for the PR title, such as fix(submit): reject repos with no README, in 72 characters or fewer. PRs are squash-merged, so the title becomes the commit.

  • Every PR needs an approving review and passing checks.

  • Planning something big? Start a thread in Ideas first.

  • Never edit data/entries.json by hand in a PR. The bot owns it.

Everything you contribute is released under CC0.

What's where

Path What it holds
data/entries.json Every entry: repo, category, description, status. The single source of truth.
data/schema.json The JSON Schema that entries.json must pass.
data/categories.json The 13 categories.
data/osi-licenses.json The OSI-approved license IDs the license check accepts.
scripts/ The bots, in Python 3.12 with the standard library only. Tests are in scripts/tests/.
scripts/devstream/ Shared modules: trust, quality, license_detect, description, issue_form, likes and the GitHub client.
scripts/blocklist.txt The spam wording the description filter rejects.
site/ The Astro site, with a little vanilla JavaScript for sorting and filtering.
fuzz/ Fuzz targets for the parsers.

There's also a stats branch that only the bot writes to. It holds the Like counts (likes.json), the entry-to-Discussion map (discussions.json), daily snapshots, burst flags, health-check state and the trust cache. Keeping all that off main means the hourly Likes sync never touches the protected branch.

How the bots fit together

Every bot is a GitHub Actions workflow in .github/workflows/ that runs a script in scripts/. They write as a GitHub App, devstreamhq-bot.

Submit form ─> submit.yml ─> bot PR ─> pr-checks.yml + auto-approve.yml ─> merge
                                                                             │
                     on-merge.yml (creates the entry's Discussion) <─────────┘
                                         │
             likes.yml (hourly) ─> stats branch ─> deploy.yml ─> the site
             rot.yml (weekly)  ─> bot PR for warnings, archives, removals
Report form ─> reports.yml ─> label, hide PR, or a one-repo rot.yml run
Workflow Runs What it does Script
submit.yml A submission issue is opened Checks the account and the repo against the Quality Bar. On a pass, opens a PR adding the entry and turns on auto-merge. On a fail, comments the reasons and closes the issue. scripts/submit.py
pr-checks.yml Every PR to main validate (entries against the schema), test (the unit tests) and lint (Prettier). scripts/validate_data.py
auto-approve.yml A bot PR is opened Approves the bot's own PRs, only when they change nothing but data/entries.json.
on-merge.yml entries.json changes, and hourly Opens a Discussion for each new entry and records it on the stats branch. scripts/on_merge.py
likes.yml Hourly Counts trusted 👍 reactions, ranks entries, runs the burst and drip checks, writes the stats branch. scripts/sync_likes.py
deploy.yml After merges, Likes syncs and site changes Builds the site from main plus stats, and deploys it.
rot.yml Mondays at 06:00 UTC, or one repo on demand The health check. Opens a PR for any status change, then comments on the affected Discussions. scripts/rot.py
reports.yml A report issue is opened Labels the report, queues a health check, or opens a PR hiding the entry. See Reporting an Entry. scripts/reports.py
sweep.yml Every 15 minutes Re-runs submissions and reports that no run finished, re-runs an overdue health check, and clears abandoned bot branches. scripts/sweep.py
stars.yml Daily Opens one issue when the repo reaches 100 stars. scripts/stars.py
codeql.yml, scorecard.yml, cflite_pr.yml PRs, pushes and a schedule Code scanning, the OpenSSF Scorecard and fuzzing.
release.yml A v* tag is pushed Tests and builds the site, then publishes a GitHub release with the source and site tarballs.

House rules for workflow code

If you touch .github/workflows/, the review looks for these:

  • Actions are pinned to a full commit SHA, with the version in a comment.
  • Permissions start at {} and each job asks only for what it needs.
  • Text from issues never goes into ${{ }} inside run:. Pass it through env: or a file. Issue text is written by strangers.
  • Deciding and writing are separate jobs. The job that reads an issue and decides runs with a read-only token. Only a later job gets the App token.
  • No pull_request_target checkout of PR code.

The bot's public comments use fixed strings and the normalised owner/name, never text copied from the issue. Keep it that way, so nobody can make the bot say something or ping someone.

Where to start

Issues labelled good first issue are small and well-scoped. The Roadmap shows what's planned for each milestone. Questions go to Discussions Q&A.

Found a security problem while you were in there? Don't open a PR or an issue. See Security.

Clone this wiki locally