Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

34. The community package index: a second static site

  • Status: Accepted
  • Date: 2026-09-05

Context

ADR 0031 makes packages discoverable only by already knowing their git URL. Something has to let people find out a package exists in the first place — "a second site alongside this one indexing shared libraries, fed by a submission process," per the project's own roadmap. The user locked in, ahead of any design work here: no submission-form backend, no Cloudflare Pages Function, no KV/D1 — a GitHub-PR curated list instead. This ADR designs the concrete shape of that, following ADR 0031's own governing constraint: no new hosted infrastructure.

korrin-web/ (the existing docs/landing site) is the direct precedent for what "static site on Cloudflare Pages" already looks like in this project — scripts/deploy-site.sh, wrangler.toml (pages_build_output_dir = "korrin-web"), a hand-written index.html plus style.css. editors/vscode/ is the precedent for "a self-contained, non-Rust tool in its own directory, with its own build and its own review scope" (ADR 0030).

Decision

A new sibling directory, korrin-packages/, deployed the same way korrin-web/ is

korrin-packages/
  index.html          # hand-written, vanilla JS — mirrors korrin-web/index.html's style
  style.css
  packages.json        # generated: the merged, machine-readable index
  data/packages/
    requests.json         # one file per submission
    json.json
  wrangler.toml
  CONTRIBUTING.md           # what a submission PR needs to contain

A second instance of the exact deploy pattern korrin-web/ already uses (a static directory, its own wrangler.toml, pushed with wrangler pages deploy) — not a new kind of infrastructure. It is not built with mdBook: mdBook is the right tool for docs/'s prose, the wrong one for a searchable, tabular listing with no chapters. The only build step is a small, dependency-free script that globs data/packages/*.json into packages.json; index.html fetches and renders that client-side — simpler than korrin-web/'s own mdbook build phase, not more complex.

One JSON file per package, not one shared array

{
  "name": "requests",
  "git": "https://github.com/alice/korrin-requests",
  "description": "HTTP client for Korrin, built on io.",
  "tags": ["http", "network"]
}

data/packages/<name>.json, one file per submission. This keeps a submission PR's diff to exactly one new file, avoids merge conflicts between two people submitting packages around the same time, and keeps a reviewer's job trivial — the same reason curated-list projects (Awesome-lists, deno.land/x) generally adopt this shape over one shared array everyone edits.

JSON, not TOML, deliberately: this is data a static page's own client-side JavaScript consumes, not a Rust-ecosystem manifest. Matching korrin.toml's format for consistency's sake would only add a conversion step for no benefit — the data is authored directly as the format the page needs.

Submission is a PR, moderation is review

korrin-packages/CONTRIBUTING.md states the requirement: a submission PR adds exactly one data/packages/<name>.json file with the fields above; the package it names must have a korrin.toml at its git root and a working src/lib.kor. A lightweight CI job in this directory validates that the JSON parses and the required fields are present — schema validation, not moderation. Whether a package is a good fit for the index is a human PR review question, same as any other contribution to this project.

Consequences

  • No new infrastructure exists anywhere: no server, no database, no form endpoint. The entire "backend" is Cloudflare Pages serving static files, identical to how korrin-web/ already works.
  • Submitting a package is exactly as much friction as any other open-source contribution — a PR — which is a real barrier compared to a self-serve form, and a deliberate one: it puts a human reviewer between "anyone can type a URL" and "it appears on the index," with no code required to enforce that.
  • The index can go stale — a listed package can be deleted, renamed, or abandoned upstream with nothing here noticing automatically, since there is no backend to periodically check anything. A "does this still resolve" CI job is realistic future work; not built now.
  • Two entirely separate Cloudflare Pages projects (korrin-lang for korrin-web/, a new one for korrin-packages/) means two deploy targets to remember, documented in korrin-packages/'s own DEPLOY.md, mirroring korrin-web/DEPLOY.md.

Alternatives considered

  • A submission form with a backend. Explicitly ruled out by the user ahead of this ADR — would need a Cloudflare Pages Function, a loosened _headers CSP (the current one blocks all form submissions via form-action 'none'), and a storage backend (KV or D1) that doesn't exist anywhere in this project today.
  • One shared packages.json array, edited in place by every submission PR. Simpler to read as a single file, but every concurrent submission becomes a merge conflict against the same line range, and a reviewer has to diff a bigger file to see what one submission actually changed.
  • A new page on the existing korrin-web/docs/ mdBook site, rather than a second site. Would need no new wrangler.toml/deploy target, but forces a searchable/filterable listing through a prose-book renderer built for chapters, not tables — the wrong tool, and it conflates "the language's own documentation" with "a community-maintained list of third-party code," which are different trust levels worth keeping visibly separate.
  • Building this on mdBook anyway, generating one page per package from the same data/packages/*.json files. Would give consistent site chrome with korrin-web/ for free, but the JSON-per-package shape doesn't map cleanly to mdBook's chapter/heading model without real per-page templating work korrin-web/ doesn't already have a pattern for — not worth it for a first cut when a plain fetch-and-render page does the whole job in far less code.