career-ops 开源贡献实战指南:从首个 good-first-issue 到维护者的协作全流程

career-ops 开源贡献实战指南:从首个 good-first-issue 到维护者的协作全流程 career-ops 开源贡献实战指南从首个 good-first-issue 到维护者的协作全流程【免费下载链接】career-opsOpen-source AI job search: scan job portals, evaluate listings into a structured A-H report with a global 1-5 score, tailor your CV, track applications — runs locally in your AI coding CLI (Claude Code, Codex, OpenCode, Antigravity…)项目地址: https://gitcode.com/GitHub_Trending/ca/career-opscareer-ops 是一个本地优先、人机协作的 AI 求职开源工具它扫描招聘网站、把职位评估为结构化的 A–H 报告并给出 1–5 分评分、为你量身定制简历并跟踪申请全部在你的 AI 编码 CLIClaude Code、Codex、OpenCode 等中本地运行。本文以仓库根目录的 CONTRIBUTING.md 为骨架系统拆解该项目的贡献协作流程——包括 PR 提交流程、核心与插件层Plugin的架构边界、Source Indexing Policy数据源索引政策的五条硬性规则、测试目录规范与本地开发命令并结合源码与你手把手上手第一个合并的 PR。一、为什么在 career-ops 做第一次开源贡献项目文档给出了几个非常实在的理由值得先建立共识你已经天然理解问题域。career-ops 是一个求职工具——如果你正在找工作你比多数人更懂它的痛点也天然是更好的贡献者。你的代码会被真实的人使用。贡献被合并后你的名字进入的是一个真实项目的历史而不是玩具仓库仓库文档记载该仓库已在 GitHub Trending 长期上榜、Star 数超过 55K。响应快。文档承诺开 issue 或 PR 通常一两天内就有回音没有黑洞。有极小的上坡路径tiny on-ramps。good first issue都被切成小块带时间预估、可复制的模式、明确的完成定义第一次 PR 是稳赢而不是迷宫。有真实的 Code Review。每个 PR 都会被人工阅读不淹没在 bot 噪声里也不合并AI 垃圾。有明确的晋升路径。持续高质量贡献者会得到公开署名并被邀请承担更大角色reviewer → maintainer。注意这些描述均来自 CONTRIBUTING.md 原文与仓库自身文档Star 数与增长数据仅作为仓库文档陈述引用不代表对当前时点的实时核验。二、提交 PR 之前先对方向再写代码Feature 类变更先开 issue对于新功能、新的 mode模式或命令、架构级变更文档要求先开 issue 讨论。原因是避免你在一个最终会被我们转向的方向上投入时间让大家在写代码之前先对齐方向。无需 issue、可直接 PR 的类别以下类别直通 PR 完全欢迎、不需要先开 issue因为流程不应拖慢它们且这正是项目最想要的贡献Bug 修复新的 zero-auth 扫描器 provider无需鉴权即可读取公开职位数据的接入模块文档翻译。文档同时提醒一个绕过此步的大型 feature PR如果不符合架构或路线图可能被要求先回到 issue——这是范围对话scope conversation而不是对你工作质量的否定。好 PR 的标准修复了 Issues 里列出的 bug解决了经过讨论并获批的功能请求包含改了什么、为什么改的清晰描述遵循现有代码风格与项目哲学简单、最小、质量优先于数量simple, minimal, quality over quantity。Quick Start 七步走开 issue 讨论你的想法Fork 仓库建分支git checkout -b feature/my-feature做改动用全新 clone 测试参见 docs/SETUP.mdCommit 并 push开 Pull Request 并引用该 issue。第 5 步强调fresh clone很有深意career-ops 是本地运行工具真实环境依赖Node 18、Chromium/Playwright、dashboard 的 Go 工具链见 package.json只有在干净环境里跑通才可靠。三、贡献什么好点子分级与认领机制入门级贡献贡献方向落点为职位门户表补充公司templates/portals.example.yml把 modes 翻译成其他语言modes/下各语言目录zh/、es/、de/、fr/等改进文档docs/、README.*.md为不同岗位添加示例简历examples/报 bug仓库 Issues更大规模的贡献新的评估维度或评分逻辑对应 A–H 报告与 1–5 评分体系Dashboard TUI 功能代码在 dashboard/是一个独立的 Go 模块含go.mod/go.sum/main.go与平台相关的open_*.go新的技能模式skill modes在 modes/脚本改进各种.mjs工具根目录下即可见大量入口。/assign认领机制如何保持公平对任意good first issue评论/assign即可认领无需等待维护者。公平性由三条规则保证认领会自动释放7 天无动静后第 3 天会收到友好提醒该 issue 回到可认领窗口不会卡死。/extend无理由重启计时/unassign干净放手只要挂着打开的 PR 就暂停计时。为新贡献者预留good-first-issue 面向在此仓库合并少于 3 个 PR 的人first-timers-only标签则严格要求是第一个一次只能认领一个确保首次贡献者永远有路可走。超过该阶段后help wanted标签是你的主战场。认领不是贡献的前提直接对任何未分配 issue 提 PR 永远欢迎。四、贡献者阶梯公开、可预期的晋升路径项目有明确梯队且公开署名、主动邀请首次贡献者First-time contributor——你合并了一个 PR欢迎加入可信贡献者Trusted contributor——几个扎实的合并后你的 PR 会走快速通道并在相关工作里 你审阅者Reviewer——帮助分流与审阅他人 PR由项目方邀请维护者Maintainer——参与掌舵项目方向。想多做一点直接在 issue 里说出来即可。五、接管被放弃的 PRpublic、可预测的三级阶梯生活会发生一个 PR 收到 review作者转行了有用的工作停在 80% 完成。career-ops 的做法不是让 bot 埋掉它也不是任它腐烂而是走一条公开且可预测的阶梯Review 一轮后静默两周维护者将该 PR 选入接管流程adoption/track并友好提醒原作者还是你的不急。再过两周进行第二次确认并写明后续计划若再静默两周工作将开放认领。只有到这一步维护者绝不通过 bot才会感谢并关闭原 PR同时开一个标记为adoptable的伴生 issue指向原分支并逐条列出剩余工作。接管一个被放弃的 PR 是最有价值的首次贡献之一diff 基本完成、review 已经写好、剩余工作范围明确。做法是开一个新 PR并携带原始 commitsgit 会保留作者署名或用Co-authored-by:尾部追加原文作者。两位贡献者都得到署名原作者署名工作你署名落地。如果你是回来的原作者只要还没被别人完成工作随时可收回——在 issue 上说一声即可阶梯任何一步上你的一次评论或 push 都会完整重置计时。六、别人的开放 PR 仍然是别人的边界与自动化规则上述接管阶梯只针对已被放弃的工作。一个作者仍在活跃的开放 PR 是另一回事这条线非常明确不要开一个重新解决别人冲突的 PR。在评论区指出某 PR 已冲突确实有用但把它 rebase 到自己的分支再开替代 PR 不行——因为替代 PR 合并会关闭原 PR原作者得到的将是closed而不是本该属于他的merged。那个徽章是贡献者从这个项目带走的大部分东西不归我们重新分配。如果冲突源自项目方自己的合并修复责任在项目方维护者会在作者自己的分支上解决冲突这正是 Allow edits by maintainers 的意义、跑全套测试、保留原 PR 与作者身份原封不动。冲突来自其他任何地方则由作者在自己方便时 rebase——没人被催着赶这个时间表。自动化同样受约束bot 在别人分支上开替代 PR 等于以更高音量做同一件事在别人线程里贴自动化分流意见别两个都合并把 #X 当作主 PR会读起来像项目决策。合并决定只能由维护者做出。自动化 Agent 只能在自己 operator 开的 PR 上评论在他人 PR 上的自动化评论会被当作离题内容最小化。你以自己名义手写的 Review在任何 PR 上都欢迎。超出解决冲突的改进欢迎但不要钉在别人 PR 上在讨论串里提出、让作者决定或等它合并后开自己的 PR。七、架构边界core 与共享层plugin-first怎么分career-ops core 的定位是local-first本地优先与 human-in-the-loop人在回路它跑在你的机器上起草的申请材料由你审查并提交。而集中式基础设施——托管职位聚合、共享匹配服务、代理或 Workers——不属于 core那是更重的、未来作为独立、opt-in 服务的方向。动手之前的经验法则provider 模块、语言、CLI 支持、core 主路径上的 modes、dashboard、文档与修复 → 属于 core。更大的集中化/自动化想法托管层、auto-apply、爬取基础设施→ 先在方向讨论里发起而不是交一个无法合并的大型 PR。平行功能四问the parallel-feature testcareer-ops 对很多事说是provider、语言、CLI 支持、修复。它刻意挑剔的是平行功能——那些与求职主路径相邻、单独看也各自有用的东西。因为每个合并的 feature 都是永远维护它的承诺文档、测试、agent 上下文、升级路径所以它写得好不好根本不是门槛。提这类功能前先自问四个项目自己也在用的问题它在核心主路径上吗核心路径是发现职位discover→ 评估evaluate→ 定制tailor→ 申请apply→ 跟踪track→ 闭环close the loop。服务于这条路径的基础设施去重、原子写入、状态转换台账即使不可见也属于核心。而在路径旁边的功能联系人管理、日历、笔记从 plugin 起步。谁来付维护成本一个把某个工作流做到极致、却给所有人增加表面积新数据文件、新脚本、新模式的 feature需要被证明有真实需求多个人的 issue而不是一个人否则就应该住进 plugin。Plugin-first凭证据毕业。相邻功能先做成 plugin契约见 docs/PLUGINS.md你自己掌控发布节奏项目把它登记在 registry 里。若 plugin 获得真实采用项目会考虑把它毕业进 core——基于证据的晋升而非关卡这是 WordPress 运营 feature-projects 的方式。它符合项目的形状吗一个破坏既有模式的 mode 或 API会给每个未来的用户和贡献者制造认知负担即使它工作正常。合并前请先接受与代码库一致的拼写/写法这一要求。四条任一不通过是路由问题而非拒绝先开 issue我们会告诉你去哪扇门——core、plugin 还是独立项目。plugin registry 提供真实的分发渠道而今天不适合 core 的想法仍可能成为你交付的最有用的东西。八、Source Indexing Policy所有数据源共用的一把尺career-ops 从公开来源读取职位ATS、招聘板、公司招聘页、人才网络。这套政策是每个来源都必须通过的唯一标准——无论谁提议包括提交自家招聘板的运营者。项目不评判来源的商业模式只评判它的数据这五条规则是 MANIFESTO.mdCareerOps 宣言在数据源上的落地。索引什么任何职位真实、可归属到可识别的雇主、且候选者可免费阅读与申请的来源。宣言权利第 4 条You never pay同样适用于来源对职位或申请设付费墙的来源无论其他方面如何都不会被索引。规范 URLCanonical URL每条职位携带来源所暴露的、通往雇主的最短可验证路径可用时用 ATS 或直投链接。来源自身页面只能作为次级归属。付费置顶到不了候选人推广内容不能购买在 career-ops 中的位置——排序发生在每个用户自己的机器上provider 遍历其来源的完整库存维护者会对来源做响应偏差审计API 总量 vs 站点总量、页面分布。career-ops 自身不带任何赞助位。这是宣言权利第 8 条Your agent works for you. Not for a platform, not for an employer.在数据层的强制执行。索引不等于背书分发也不是欠谁的进入 registry 会把职位摆到安装用户群面前真实、可衡量、且依赖渠道——但没有任何来源被欠着位置、流量或永久性。来源必须声明其运营者且单一来源不得超过 registry 的 40%。聚合层属于项目一个 provider 只读它自己的来源。跨来源的聚合、排序、匹配与 registry 都住在 core 中绝不委托给某个来源。政策如何被逐条执行可以读 docs/SOURCE_INDEXING_LOG.md每个已收录来源一条记录写清楚检查了什么、怎么验证的。文档特别说明该日志不是排名也不是承诺Verified意味着有人跑了命令并报告输出而不是声明被接受涉及活端点检查会注明采样时间因为线上检查会过期。该文档里两个典型判例值得参考remotli.ch第一位在成文政策下过审的运营者自荐来源验证了规则 1无候选者付费墙、规则 2采样 121 行雇主 URL 占比 100%、规则 3运营者自曝不加remoteall只覆盖 392/921 条合并的 provider 遍历全部 19 页。**披露在前规则裁决而不是靠对话**正是政策存在的意义。a16z speedrun 人才网络促成政策成文的案例listing 后由贡献者读线上 feed 发现并修复了两个覆盖缺陷分页容量 50 vs 100、单次上游瞬时故障导致整板中断——这正是规则 3 针对的失效模式看着完整、实则部分覆盖。怎么提出一个新来源想提案一个来源自己的或别人的走source proposalissue 模板逐条对照上面五条规则或直接提交带 provider 的 PR 也欢迎合并前同样走这五条规则。运营者声明在收录前须带外核实out-of-band verification一个可在来源自身域名下联系到的联系人或等效的域名控制证明。运营者提议自己的招聘板完全没问题——规则化门槛正是为此而设。从实现侧印证一个 provider 是一个 providers/ 下的{name}.mjs模块通过 providers/_registry.mjs 被 scan.mjs 与 verify-portals.mjs 自动加载——放入文件即完成注册无手工登记。完整的接入契约、强制护栏与tests/providers/{name}.test.mjs必须覆盖的内容见 providers/ADDING_A_PROVIDER.md。九、开发守则Guidelines尽量让 modes保持语言无关Claude 能同时处理 EN 与 ES脚本应优雅处理缺失文件——先existsSync再readFileSync这也是 tests 中大量用例覆盖的防御模式Dashboard 改动必须构建npm run build:dashboard并用真实数据测试后再提交不要提交个人数据cv.md、profile.yml、applications.md、reports/属于本地用户层不进版本库。十、明确不接受的 PR以下清单是项目红线任何类别都会被主动拒绝了解它能在动手前省下大量时间爬取禁止自动化访问平台的 PR如 LinkedIn 等——为尊重第三方 ToS绕过人工审查、自动提交申请的 PR——career-ops 是决策支持工具不是 spam bot呼应宣言Nothing is ever auto-submitted未经 issue 讨论就引入外部 API 依赖的 PR针对内置 plugin 的 feature PRplugins/apify、plugins/gmail、plugins/notion——内置 plugin 是稳定的reference seeds要扩展就发布你自己的career-ops-plugin-id项目会登记它为安装后即优先的被维护后继内置 plugin 只接收安全/兼容性修复向 core 添加集中化或托管基础设施代理、聚合服务、共享 Workers——那属于独立 opt-in 服务而非 open-core以通用聚合索引作为依赖——把整合众多来源的统一聚合层作为第三方依赖接入单读各招聘板的 provider 永远欢迎统一的聚合层本身必须是一方first-party把数据发给第三方服务的集成——需要第三方账号、或把简历/流水线/笔记推到外部服务的 provider 或同步功能。career-ops 本地优先、零密钥求职数据留在你的机器上。本地读取公开职位 API 完全欢迎内置 provider 就是这么工作的把个人数据路由给别人的服务则不行主要消费者是第三方产品的集成——调用方是别人家产品bot、SaaS、外部编排器的模块/契约/适配器即便代码本身通用也属于 plugin 或独立项目绝不属于 core项目自身一方表面官方 web 体验、可选的共享服务例外向 README 添加第三方托管的入口或服务徽章——README 只保留项目控制的资产基于 career-ops 构建的项目欢迎在社区里分享但不能上首页包含个人数据的 PR真实简历、邮箱、电话——请用 examples/ 下的虚构数据。十一、本地开发与测试规范实测可复制仓库文档给出的一套核心开发命令与 package.json 的 scripts 一一对应# 脚本/自检 npm run doctor # 设置与本地环境校验对应根目录 doctor.mjs node verify-pipeline.mjs # 流水线健康检查 node cv-sync-check.mjs # 配置一致性检查简历相关配置同步 # DashboardGo TUI npm run build:dashboard # 平台正确的 go build调用根目录 build-dashboard.mjs npm run serve:dashboard # 以仓库根目录为 --path 启动 TUI # 测试 node test-all.mjs # 全套测试 —— push / 开 PR 前必跑 node test-all.mjs --quick # 全套但跳过 dashboard 构建 node test-all.mjs --only providers/themuse # 只跑某个 provider 的测试新测试必须独立成文件tests/ 的自动发现机制任何新测试都应放在tests/下自己的文件里而不是作为test-all.mjs里的编号小节。凡是匹配tests/**/*.test.mjs的文件都会被自动发现——无需注册、无需选编号。从源码看这不是洁癖而是真实的协作教训见 test-all.mjs 头注——2026 年 8 月六个贡献者同时往test-all.mjs末尾加编号小节六个人不约而同都选了60a每个合并都迫使其余五个人 rebase——六行测试代码换来约十五次 rebase 和六次串行化的 CI 运行。而一个新文件不与任何人冲突这些 PR 可以全部并行落地。实现上 test-all.mjs 的discoverTests()用readdirSync 字典序确定性遍历还会跳过嵌套 checkoutworktree防止误执行。新增扫描 provider读这份完整契约见 providers/ADDING_A_PROVIDER.md完整契约、强制护栏、以及tests/providers/{name}.test.mjs必须覆盖什么例如禁止process.exit()、必须用测试助手计数、健康探测时的行为等实际仓库的tests/providers/下已沉淀 100 个对应测试文件。Web 端测试布局Web 套件位于 web/tests/镜像被测模块在web/src/下的路径如src/lib/clean-chips.mjs→tests/lib/clean-chips.test.mjs命名为{module}.test.mjs。要点web/自己的npm test通过 glob 发现它们同样无需注册但不要让它们落在web/src/里——Next.js 会扫描该目录树写成.mjs——node --test没有 TypeScript loader布局细节见 web/README.md并由根套件的 tests/web-test-layout.test.mjs 在每个 PR上强制校验。--only只是开发便利不是 PR 门槛test-all.mjs 头部用大写警告写得很直白--only只跑匹配到的tests/文件跳过所有内联核心小节语法、脚本、dashboard、数据契约、个人数据、路径等。因此--only全绿 ≠ 全套通过——push 前永远要跑完整的node test-all.mjs。配套实现中test-all.mjs还会对无匹配文件直接process.exit(1)让路径拼写错误永远不会悄悄把 CI 变绿。十二、品牌、商标与许可代码贡献受MITLICENSE 管辖career-ops 名称本身受 TRADEMARK.md 管辖若你 fork 做商业用途MIT 允许但请给产品起你自己的名字并遵循商标政策中关于商业命名与背书声明endorsement claims的规定。结语从文档到合并的完整闭环最后把整条路径串起来想方向feature 先开 issue→ 认领或自选/assign或直接对未分配 issue 提 PR→ 判断归属core / plugin / 独立项目过平行功能四问→ 涉及新数据源先过 Source Indexing Policy 五条规则 → 遵守开发守则与红线清单 → 本地跑node test-all.mjs全绿新测试独立成.test.mjs文件→ 提交 PR → 通过人类 Review → 合并 → 走上贡献者阶梯。如果遇到困惑最有效的入口都在仓库内开 issue、通读 docs/ARCHITECTURE.md 理解分层、对照 docs/SOURCE_INDEXING_LOG.md 看政策如何落地或用全新的 clone 按 docs/SETUP.md 从头跑一遍再开始改代码——这既是测试你的环境也是测试你即将贡献的项目的真实安装体验。【免费下载链接】career-opsOpen-source AI job search: scan job portals, evaluate listings into a structured A-H report with a global 1-5 score, tailor your CV, track applications — runs locally in your AI coding CLI (Claude Code, Codex, OpenCode, Antigravity…)项目地址: https://gitcode.com/GitHub_Trending/ca/career-ops创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考