Thanks for helping out! Contributions of every size are welcome — from adding one company to building a whole new ATS adapter. This guide explains how the project is laid out, how to set up, the conventions we follow, and step-by-step recipes for the most common contributions.
- Add a company to the Open Job Graph — a one-line change to
registry/companies.json. - Add a common answer to the answer-bank defaults.
- Report a bug if an ATS adapter mis-parses a real posting (open an issue with the org slug).
- Add an ATS adapter for a new applicant-tracking system.
- Add an MCP tool or a GUI feature.
This is an npm workspaces monorepo:
packages/core → the engine (published as `crosswalk-mcp`, the MCP server)
store/ services/ ats/ exporters/ tools/ sampling/ + runtime.ts
apps/web → the Next.js GUI (private package `@crosswalk/web`)
scripts/ → watch.mjs (the always-on watcher daemon)
docs/ → ARCHITECTURE.md + superpowers/ (specs & implementation plans)
registry/ → companies.json + h1b.json (the Open Job Graph)
Read docs/ARCHITECTURE.md for the deep dive.
Requires Node.js 24+.
git clone https://github.com/Mohakgarg5/crosswalk-mcp.git
cd crosswalk-mcp
npm install
npm test # run the test suite (vitest)
npm run lint # type-check core + web (tsc --noEmit, strict)
npm run build:core # build the engine
npm run gui # build core + start the GUI at localhost:3000
npm run watch # run the always-on watcherOptional, for browser automation work:
npx crosswalk-mcp install-browser # or: npm i playwright && npx playwright install chromium- TDD. Write a failing test first, then the implementation. Every behavior change ships with a test.
- Small PRs, frequent commits. Keep changes focused and reviewable.
- Strict TypeScript.
npm run lintistsc --noEmit; it must be clean. Noanyunless unavoidable (prefer typed shapes). - ESM +
.tsimports. Source uses explicit.tsextensions (bundler resolution). Match the surrounding style. - Commit messages: short, conventional-style prefix (
feat:,fix:,docs:,test:,refactor:,build:), present tense. - Truthfulness & safety. Résumé tailoring must never fabricate facts; auto-submit stays opt-in and clearly labeled.
npm test # all green
npm run lint # clean (core + web)
npm run build:core # buildsUpdate README.md / docs/ARCHITECTURE.md if you changed behavior or commands.
Append an entry to packages/core/registry/companies.json:
{ "id": "acme", "name": "Acme", "ats": "greenhouse", "atsOrgSlug": "acme" }atsmust be one of the supported adapters (greenhouse, lever, ashby, workable, smartrecruiters, bamboohr, recruitee, personio, workday, icims).atsOrgSlugis the company's identifier on that ATS (e.g. the token in its Greenhouse board URL).- Optionally add an H-1B confidence in
registry/h1b.json.
That's it — the registry is MIT-licensed and seeds on first run.
Edit COMMON_DEFAULTS in packages/core/src/store/answerBank.ts. Keep EEO answers neutral ("decline to self-identify"). Add a case to tests/answerBank.test.ts if it's a new kind of match.
- Create
packages/core/src/ats/<name>.tsexporting a const that callsregisterAdapter(...)(copyats/greenhouse.tsas a template; it conforms to theATSAdapterinterface inats/types.ts). - Add a checked-in fixture under
packages/core/tests/fixtures/<name>-jobs.json(or.xml). - Add
packages/core/tests/ats.<name>.test.tsthat mocksfetchagainst the fixture. - Register the side-effect import (
import './ats/<name>.ts';) in every adapter list that enumerates them:src/server.ts,src/runtime.ts,src/tools/fetch_jobs.ts, andsrc/cli.ts(the doctor's adapter check). Tip:grep -rl "ats/greenhouse" packages/core/srcshows the current set. - Add the new slug to
KNOWN_ATS(and theCompany['ats']union) insrc/store/company.ts. - Add a few companies to
registry/companies.jsonusing the new slug.
- Create
packages/core/src/tools/<name>.tsexporting a zod input schema + handler. - Register it in
src/tools/index.ts(toolDefinitions). - Add
tests/tools.<name>.test.ts. - Update the expected tool list in
tests/server.tools.test.tsand the count intests/cli.doctor.test.ts.
Migrations are append-only in packages/core/src/store/migrations.ts:
- Append a new object with the next
id— never edit a shipped migration. - Update the expected id list in
packages/core/tests/store.test.ts. (Thedoctorcommand derives the expected set from the migrations array, so it needs no change.)
- Tests run with vitest and an in-memory SQLite (
openDb(':memory:')) — hermetic, no temp files. - No live network/AI/browser calls in tests. Mock
fetchfor adapters, stub theSamplingClientfor AI, and inject a fakeBrowser(orimportPlaywright) for browser logic. See existing tests for the patterns. - If a test depends on the current date (recency filters), pin the clock with
vi.useFakeTimers()+vi.setSystemTime(...)— except in the auto-apply path, where the.docxgenerator's timers don't like fake timers (use real timers + a small delay there).
Open a GitHub issue. For adapter parsing bugs, include the org slug and the field that's wrong. For app bugs, include what you did, what happened, and any console output.
By contributing, you agree your contributions are licensed under the project's MIT License.