Contributing
How to contribute to City Scrapers - both the code and the docs.
Contributing
Editing the docs
These docs live in content/docs/ in the Meetings Viewer repo. They're written
in MDX, which is Markdown with support for React components.
The git path (for developers)
- Edit the
.mdxfiles incontent/docs/. - Run
npm run devand check your changes at http://localhost:3000/docs. - Open a PR. Vercel will generate a preview URL.
The visual editor path (for everyone)
A Keystatic editor is mounted at /keystatic for mentors, PMs,
and anyone who prefers not to use the terminal.
Three things to know about how it works:
- Two storage modes. Until the GitHub app env vars exist, the editor
runs
localmode - no login, saves write straight into the working tree on the machine runningnext dev. OnceNEXT_PUBLIC_KEYSTATIC_GITHUB_APP_SLUGis set (created via/keystatic/setup), it switches togithubmode: OAuth login required, only people with repo write access can save. - In GitHub mode, saves go through a PR. The editor works on
keystatic/*branches; on first save a GitHub Action opens a PR against the default branch automatically. The PR gets the normal review and drift check before merge - editor commits never land on the default branch directly. - Component-importing pages are prose-editable only. Pages using live
components -
<RepoScope>,<SchemaTable>,<Steps>,<RubricReport>- render them as labeled blocks. Make prose edits in the editor; make structural changes (adding, reordering, or removing components) in the repo.
On GitHub without a local checkout, use github.dev -
press . on any GitHub page to open a full browser-based editor. Fork the
repo, edit the MDX, and open a PR.
Editing the code
The Meetings Viewer is a Next.js 16 app using MUI 9 and Tailwind CSS 4.
Project structure
app/
(landing)/ - landing page
(docs)/ - documentation routes (Fumadocs)
(viewer)/ - scraper viewer routes
(keystatic)/ - visual editor mount
layout.tsx - root layout with MUI theme
theme.ts - MUI theme definition
globals.css - CSS layers + Fumadocs theme mapping
components/
layout/ - site header, footer, chrome, docs search
landing/ - landing page components
scrapers/ - scraper workspace components
ui/ - shared UI components (StatusChip, etc.)
docs/ - MDX components (RepoScope, SchemaTable, ...)
lib/
docs-source.ts - Fumadocs content source
scraper-data.ts - MeetingRecord type + data loading
duplicate-detection.ts - duplicate detection logic
meeting-columns.ts - table column definitions
meeting-utils.ts - meeting record utilities
content/docs/ - MDX documentation content
docs-platform/ - docs-only engine, sources, generated artifacts, playbooksCode organization
Code is organized by what kind of thing it is (pure logic vs. UI vs.
constant) and how far it reaches (used in one place vs. shared), with the
three surfaces kept separate: landing under components/landing/, docs
under components/docs/ + content/docs/ + docs-platform/, viewer under
components/scrapers/ + app/(viewer)/.
- Pure logic with no JSX that operates on data belongs in
lib/- meeting-specific helpers inlib/meeting-utils.ts, otherwise the relevantlib/module. A hook or component needing this logic imports it fromlib/, never from another component. - A presentational component used by two or more parents belongs in
components/ui/. - A feature or page component belongs in its surface's folder
(
components/landing/,components/scrapers/,components/docs/). - A sub-component used by exactly one parent stays un-exported in that parent's file.
- Constants live at the smallest scope that needs them: local to a file,
bound to the component that owns them, or in the shared
lib//components/ui/module they belong to if genuinely shared across files. - Docs-platform internals (drift engine, mirrored sources, generated
artifacts, prose/vocab config) live under
docs-platform/- not the repo root - unless the framework requires it (e.g.keystatic.config.ts,.vale.ini).
Running locally
npm install
npm run devThe dev server starts at http://localhost:3000.
Docs commands
npm run docs:drift # rewrite findings.json + report.md
npm run docs:drift:check # same, exiting 1 on blocking findings
npm run docs:drift:test # fixture-corpus recall/precision test
npm run docs:schema # regenerate docs-platform/generated/meeting-schema.json
npm run docs:schema:check # fail if the generated schema is stale
npm run docs:links # internal link + anchor check over content/docs
npm run docs:sync # re-sync mirrored upstream sourcesOpening a PR
- Create a branch from the current production branch.
- Make your changes.
- Run
npm run lintandnpm run buildto verify. - Open a PR with a clear description of what changed and why.
If you're changing documentation that describes code behavior (e.g. the schema
fields, the end default, the duplicate detection algorithm), make sure the
docs match the code. The drift check will flag disagreements - see
/docs/conflicts for the standing view - but it's faster to
get it right in the PR.
Last updated on