Skip to content

Latest commit

 

History

History
145 lines (104 loc) · 10.7 KB

File metadata and controls

145 lines (104 loc) · 10.7 KB

Contributing to Career-Ops

Thanks for your interest in contributing! Career-Ops is built with Claude Code, and you can use it for development too.

Why contribute here

career-ops is a great place to make your first open-source contribution — and a great line on your résumé.

  • You already get it. This is a job-search tool. If you're job-hunting, you understand the problem better than most — which makes you a better contributor.
  • A real merged PR, on something people use. 55K+ stars, shipping most weeks. Your name in the history of a real project, not a toy repo.
  • We answer fast. Open an issue or PR and you'll hear back, usually within a day or two. No black holes.
  • Tiny on-ramps. Browse good first issue — each is scoped small, with a time estimate, the pattern to copy, and a clear "done", so your first PR is a win, not a maze.
  • Your human work gets a real review. We read every PR. We don't drown contributors in bot noise, and we don't merge AI-slop — put thought in, get thought back.
  • A path forward. Consistent, high-quality contributors get credited publicly and invited into bigger roles (reviewer, then maintainer).

New to all this? That's the point. Claim an issue with a comment, ask anything in Discord, and we'll help you land it.

Before Submitting a PR

For a new feature, a new mode or command, or an architecture change, please open an issue first. It saves you from investing time in something we'd have to redirect, and lets us align on direction before you write code.

Going straight to a PR is welcome — no issue needed — for: bug fixes, new zero-auth scanner providers, docs, and translations. Don't let process slow these down; these are the contributions we most want.

A large feature PR that skipped this step may be asked to start with an issue if it doesn't fit the architecture or roadmap — that's a scope conversation, never a judgment on your work.

The review process you'll experience here is documented end-to-end in Agentic maintenance: how this repo is run: why a first-timer's CI waits for human approval, why review comments arrive with test evidence, and what happens between your push and the merge.

What makes a good PR

  • Fixes a bug listed in Issues
  • Addresses a feature request that was discussed and approved
  • Includes a clear description of what changed and why
  • Follows the existing code style and project philosophy (simple, minimal, quality over quantity)

Quick Start

  1. Open an issue to discuss your idea
  2. Fork the repo
  3. Create a branch (git checkout -b feature/my-feature)
  4. Make your changes
  5. Test with a fresh clone (see docs/SETUP.md)
  6. Commit and push
  7. Open a Pull Request referencing the issue

What to Contribute

Good first contributions:

  • Add companies to templates/portals.example.yml
  • Translate modes to other languages
  • Improve documentation
  • Add example CVs for different roles (in examples/)
  • Report bugs via Issues

Bigger contributions:

  • New evaluation dimensions or scoring logic
  • Dashboard TUI features (in dashboard/)
  • New skill modes (in modes/)
  • Script improvements (.mjs utilities)

The contribution ladder

There's a clear path here — we promote people who show up:

  1. First-time contributor — you landed a PR. Welcome aboard.
  2. Trusted contributor — a few solid merges; we fast-track your PRs and tag you on related work.
  3. Reviewer — you help triage and review others' PRs. We invite you.
  4. Maintainer — you help steer the project.

We credit contributors publicly and invite high-signal folks up the ladder. Want to help more? Just say so in an issue.

Scope: the core vs. the shared layer

career-ops core is local-first and human-in-the-loop by design — it runs on your machine and drafts applications for you to review and submit. Centralized infrastructure — hosted job aggregation, a shared matching service, proxies or Workers the project would operate — is not part of the core: it's heavier than a free local tool should carry, and it's where the project is headed as a separate, opt-in service. See the direction here: Where career-ops is going.

Rule of thumb before you build: provider modules, languages, CLI support, modes on the core path, dashboard, docs and fixes → the core. Bigger centralized or automation ideas (a hosted layer, auto-apply, scraping infrastructure) → start in that discussion, so we can route them together instead of a large PR that can't merge.

What belongs in core (the parallel-feature test)

career-ops says yes to a lot: providers, languages, CLI support, fixes. Where we are deliberately picky is parallel features: things adjacent to the job-search path that would each be useful on their own. Every merged feature is a promise to maintain it forever (docs, tests, agent context, upgrade paths), so "is it well built?" is not the bar. Before proposing one, run it through the four questions we use ourselves:

  1. Is it on the core path? The core path is: discover postings, evaluate, tailor, apply, track, close the loop. Infrastructure that strengthens that path is core even when invisible (dedup, atomic writes, the transition ledger). A feature that lives next to the path (contact management, calendaring, note-taking) starts as a plugin.
  2. Who pays the maintenance? A feature that solves one workflow brilliantly but adds surface for everyone (a new data file, a new script, a new mode) needs either demonstrated demand (issues from several people, not one) or a plugin home.
  3. Plugin-first, with graduation. Adjacent features start as plugins (see docs/PLUGINS.md): you own the release cycle, we list it in the registry. If a plugin earns real adoption, we will consider graduating it into core. Evidence-based promotion, not gatekeeping: it is how WordPress runs feature-projects.
  4. Does it match the project's shape? A mode or API that breaks established patterns creates cognitive load for every future user and contributor, even when it works. Expect us to ask for the spelling that matches the codebase before the merge.

Failing one of these is a routing, not a rejection. Open the issue first and we will tell you which door fits: core, plugin, or separate project. The plugin registry gives real distribution, and an idea that is wrong for core today can still be the most useful thing you ship.

Guidelines

  • Keep modes language-agnostic when possible (Claude handles both EN and ES)
  • Scripts should handle missing files gracefully (check existsSync before readFileSync)
  • Dashboard changes require a build (npm run build:dashboard) — test with real data before submitting
  • Don't commit personal data (cv.md, profile.yml, applications.md, reports/)

What we do NOT accept

  • PRs that scrape platforms prohibiting automated access (LinkedIn, etc.). We actively reject these to respect third-party ToS.
  • PRs that enable auto-submitting applications without human review. career-ops is a decision-support tool, not a spam bot.
  • PRs that add external API dependencies without prior discussion in an issue.
  • Feature PRs against bundled plugins (plugins/apify, plugins/gmail, plugins/notion). Bundled plugins are stable reference seeds — to extend one, publish your own career-ops-plugin-<id> and we'll register it as the maintained successor that takes precedence once installed (see docs/PLUGINS.md). Bundled plugins only take security/compat fixes.
  • PRs that add centralized or hosted infrastructure to the core (proxies, aggregation services, shared Workers). That's the separate opt-in service, not the open-core — bring it to the direction discussion first.
  • Integrations that send your data to a third-party service — providers or sync features that require a third-party account or push your CV, pipeline, or notes out to an external service. career-ops is local-first and zero-keys: your job-search data stays on your machine. Reading public job-listing APIs locally is welcome (that's how the built-in providers work); routing your personal data through someone else's service is not.
  • PRs that add third-party hosted entry-points or service badges to the README — links or embeds that route users' resumes or job data through a service the project doesn't operate. The README stays to assets the project controls, and the official online experience is something we keep first-party (see The Vision). Projects built on career-ops are welcome — share them in the Discord or Discussions, just not on the front page.
  • PRs containing personal data (real CVs, emails, phone numbers). Use examples/ with fictional data instead.

Development

# Scripts
npm run doctor                # Setup validation
node verify-pipeline.mjs     # Health check
node cv-sync-check.mjs        # Config check

# Dashboard
npm run build:dashboard       # go build with platform-correct binary name
npm run serve:dashboard       # launch the TUI against the repo root

# Tests
node test-all.mjs             # Full suite — run before pushing/opening a PR
node test-all.mjs --quick     # Full suite, skipping the dashboard build
node test-all.mjs --only providers/themuse   # Run just one provider's test(s)

Adding a test for a new scanner provider: add one file at tests/providers/{name}.test.mjs — it's auto-discovered (tests/**/*.test.mjs), no registration needed. Do not add a section to test-all.mjs for this.

--only is a dev convenience, not a PR gate: it runs only the discovered tests/ files matching the given substring and skips every inline core section (syntax, scripts, dashboard, data contract, personal data, paths, etc.). A green --only run is not a green suite — always run the full node test-all.mjs before pushing.

Brand and Trademark

Contributions to the codebase are governed by the MIT LICENSE. The "career-ops" name itself is governed by TRADEMARK.md. If you fork the project for commercial use, you're welcome to do so under MIT — please give it your own product name and follow the trademark policy regarding commercial naming and endorsement claims.

Need Help?