基于 career-ops 插件模板开发并发布社区插件:从脚手架的 `{{NAME}}` 占位符到 registry 审核上架

基于 career-ops 插件模板开发并发布社区插件:从脚手架的 `{{NAME}}` 占位符到 registry 审核上架 基于 career-ops 插件模板开发并发布社区插件从脚手架的{{NAME}}占位符到 registry 审核上架【免费下载链接】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 是一套零密钥、本地优先local-first、可在 AI 编码 CLIClaude Code、Codex、OpenCode 等中运行的开源求职流水线。本文围绕 plugins/_template 这一官方插件脚手架目录展开它既是新插件仓库的起点也是一份声明式最小可发布单元的活样板。读完本文你将掌握manifest.jsonindex.mjs的插件契约、plugins.mjs add/enable的双门禁安装与授权流程、密钥与非敏感配置的存放规范以及把插件送入plugins-registry/获得approved审核的全过程最终写出一个可被node plugins.mjs add name一键安装的合规社区插件。模板目录是什么一次看清脚手架的六个文件plugins/_template/是一个不直接运行的模板目录与已上架的apify、gmail、notion、h1b-sponsor等真实插件平级。它的结构即一个插件仓库的最小文件集plugins/_template/ README.md # 用户侧 README——即本文围绕的主体文档含模板化的安装/配置/上架说明 manifest.json # 插件声明解析而非执行先于任何代码导入被校验 index.mjs # 默认导出按 hook 类型组织的对象引擎调用的入口 skill.md # 教 AI Agent 如何驱动本插件的领域说明 LICENSE # MIT License版权行同样带 {{NAME}} 占位符 test/smoke.mjs # 零网络 smoke test由 plugins.mjs add 与 registry CI 执行从 plugins/README.md 的说明可以确认插件的通用形态即manifest.json先校验后执行index.mjs默认导出 hooks_xxx.mjs私有助手_前缀表示永不被当作插件发现。若你是本地私人插件则应放在plugins.local/gitignored、不会被自动更新覆盖模板目录则是将要发布为独立 GitHub 仓库的社区插件的种子。全文除特别说明外{{NAME}}均指你将要替换的插件名manifest.json注释要求 id 只能由小写字母、数字与连字符组成即[a-z0-9-]且必须等于目录名。manifest.json先声明、后被校验的插件身份文件模板自带的 plugins/_template/manifest.json 是理解插件的钥匙{ id: {{NAME}}, name: {{NAME}}, version: 0.1.0, apiVersion: 1, description: TODO: one mission-framed line describing what this plugin does., hooks: [ingest], requiredEnv: [], allowedHosts: [], skill: skill.md, humanInTheLoop: true, homepage: https://github.com/your-user/career-ops-plugin-{{NAME}} }字段语义在 plugins/README.md 的 manifest.json 一节有完整注释与模板一一对应字段含义约束/取值id插件唯一标识必须等于目录名字符集[a-z0-9-]同 id 的 bundled 插件在 id 冲突时永远优先apiVersion契约版本模板为1description一句话使命描述待你替换 TODOhooks声明的 hook 类型可选provider / ingest / search / notify / export之一或多个不存在 auto-submit hookrequiredEnv需要的环境变量名值一律放在用户自己的.env引擎在加载时按此清单做作用域冻结见下文ctx.envallowedHosts允许访问的主机白名单requiredEnv非空时必填引擎据此做 SSRF 防护skillAgent 指南文件名模板指向同目录skill.mdhumanInTheLoop是否强制人工介入模板为true且必须为truehomepage插件仓库主页发布后改为你的真实仓库需要说明的是plugins.mjs 的实现还承认两个模板里未出现的可选扩展字段allowsLocalhost允许插件额外访问 localhost见plugins.mjs对网络声明的输出逻辑与supersedesBundled声明自己是某 bundled 插件受维护的继任者。此外 smoke test 支持manifest.entry自定义入口文件名缺省回落到index.mjs。你可以在模板基础上按需声明但不要删除上面这份身份最小集。index.mjshook 出口与 ctx 运行时契约模板入口 plugins/_template/index.mjs 顶部注释直接给出了引擎会为社区插件强制执行的三条铁律写插件前务必逐条对照出站流量只能走ctx.fetch/ctx.fetchJson/ctx.fetchText引擎会应用你allowedHosts白名单并做 SSRF 防护。禁止import node:http/net或调用全局fetch——社区插件一旦出现会被拒绝。Producerprovider/ingest/search返回Job[]形如{ title, url, company, location }由引擎而非插件经由规范的 writer 写入data/pipeline.md插件因此不可能破坏 Web 端读取的数据格式。Consumerexport/notify只向用户自己的外部存储推送。没有任何自动提交auto-submithook。密钥来自ctx.env在manifest.requiredEnv中声明非敏感配置来自ctx.settings用户config/plugins.yml中plugins.{{NAME}}块。模板只给出了一个空的ingest示例export default { // Replace/add hooks to match manifest.hooks. Example ingest: async ingest(ctx) { // const data await ctx.fetchJson(https://api.example.com/jobs); // return data.results.map(j ({ title: j.title, url: j.url, company: j.company, location: j.location || })); return []; }, };五种 hook 的完整签名与用途见 plugins/README.md 的表格provider是带密钥/鉴权门禁的职位源通过scan在portals.yml的provider: id条目上触发ingest从服务邮件、看板拉取职位search按查询串返回职位export把只读的 tracker 快照推送到你自己的外部存储notify发送外发通知。运行时命令为node plugins.mjs list node plugins.mjs run gmail # ingest node plugins.mjs run notion search platform # search node plugins.mjs run notion export [--dry-run] # exportctx对象还提供env冻结、只包含你声明的密钥、settings你在config/plugins.yml中写的非敏感配置块、log会对你声明的密钥做脱敏、dryRun四个成员。其中ctx.fetch是 HTTPS-only、锚定到allowedHosts、redirect:manual且每一跳都重新校验、跨主机名跳转会剥离凭据的受守卫原语——把 HTTP 都走它出口守卫才真正生效仓库内apify插件是唯一刻意例外其客户端自行硬编码到单一主机并在其代码中明确注释说明。skill.md给 Agent 的插件驾驶手册plugins/_template/skill.md 以 YAML front-matter 开头name: career-ops-plugin-{{NAME}}、description、license: MIT正文刻意保持范围收敛只教 Agent 如何运行本插件node plugins.mjs run {{NAME}}、产出什么数据结构producer 的Job[]四字段或 export 推到哪、推到什么格式、以及有哪些config/plugins.yml下的plugins.{{NAME}}设置项。文件头注释给出关键边界——它不得指示 Agent 修改核心文件、改动评分逻辑或越过插件已声明的 hooks 行事。插件可选用node plugins.mjs skill id打印这份指南。test/smoke.mjs零网络的可安装性自检plugins/_template/test/smoke.mjs 是一个不发起任何网络请求的冒烟测试读取manifest.json以默认导出对象为入口断言默认导出必须是 hooks 对象、至少声明一个 hook、每个 hook 名都属于五种合法类型、且 manifest 声明的每个 hook 都确实被index.mjs导出。它在plugins.mjs add时与 registry CI 中都会被运行——也就是说只要你保持manifest.hooks与index.mjs导出一致就能通过这道最基础的文件级体检。从docs/PLUGINS.md可知可被上架列表收录的插件最少需包含manifest.json、index.mjs、README.md、LICENSE若要进入 listable 状态还需附上skill.md与test/smoke.mjs。安装与启用模板 README 的用户侧操作全继承模板 plugins/_template/README.md 的 Install 一节给出了两种安装路径与授权流程这是文章读者最该直接复用的部分# Once its in the career-ops registry: node plugins.mjs add {{NAME}} # Before listing (install directly from your repo at a pinned commit): node plugins.mjs add your-github-user/career-ops-plugin-{{NAME}} --sha 40-hex-commitThen enable consent:node plugins.mjs enable {{NAME}} # shows the capability card node plugins.mjs enable {{NAME}} --confirm # grants it结合 plugins.mjs 的命令分派list / available / run / skill / new / add / enable与 docs/PLUGINS.md上述流程的底层行为可以展开为以下几点写插件时应在 README 里向用户讲清两扇门都打开插件才会运行插件默认全关Default: off一是要在config/plugins.yml中启用把 config/plugins.example.yml 复制为config/plugins.yml并设enabled: true二是把密钥放进用户自己的.env。node doctor.mjs或node plugins.mjs list会列出每个插件及其密钥是否齐备——模板 README 的 Configure 一节正是让插件作者把缺什么、放哪里写明白。enable是一个显式同意动作第一次enable只展示能力卡片声明网络访问主机与所需密钥见plugins.mjs中对requiredEnv、allowedHosts的输出加上--confirm才真正写入同意记录并启用。社区插件从 git 仓库安装时还有信任徽标 bundled / ✓ approved / ❓ community-unverified / ⚠️ off-registry与篡改检测文件在未升版本号的情况下变更会被阻断需node plugins.mjs trust id重新钉住。本地脚手架node plugins.mjs new my-plugin会直接在plugins.local/my-plugin/生成一套同样式样的模板plugins.mjs中cmdNew的实现即此行为供你在本地迭代后再发布。密钥与配置分离.env放 Secretplugins.yml放选项模板 README 的 Configure 一节只有两条但背后是整个插件的配置哲学务必原样遵守并在你自己的 README 里展开Secrets go in your.env(the names are inmanifest.json→requiredEnv).Non-secret options go inconfig/plugins.ymlunderplugins.{{NAME}}.即requiredEnv只写变量名具体值属于用户侧.env非敏感开关写进config/plugins.yml的plugins.{{NAME}}块运行时经ctx.settings抵达插件。config/plugins.example.yml 里的gmail段是可参照的范本——enabled: false表示默认关闭注释里的label、days_back正是非敏感选项放 settings的示例而APIFY_TOKEN、NOTION_ACCESS_TOKEN、GMAIL_CLIENT_ID等一律指向.env。config/plugins.yml属于用户gitignored、永不被自动更新改写引擎只在两扇门都打开时才会读它未启用插件的核心运行与无插件时代完全一致。上架 registry模板 README Get it listed as approved 的完整流水线模板 README 把上架指引收敛为一句话——Open a registry PR against career-ops (see docs/PLUGINS.md)而完整步骤在 docs/PLUGINS.md 的 Publishing getting approved 一节作为插件作者必须把这条链路写进你发布后的 README独立发布把模板填充后发布为独立的公共 GitHub 仓库命名必须精确为career-ops-plugin-name模板仓库即给出正确形状与 release 工作流。登记提交一个 Plugin registration issue作为插件的 home/changelog。registry PR使用?templateplugin-registry.md模板模板仓库的 release 工作流可在打 tag 时替你从自己的 fork 发起新增plugins-registry/id.json钉住一个精确 commit。CIplugin-registry-validate会先做命名、manifest、最小文件集、license、出口网络与静态审计再由维护者人工复核。合并后用户即可node plugins.mjs add name安装插件随正常更新机制分发。更新就是再一次 registry PR把条目的sha与version一起抬升——用户只会拿到你被批准的那个 commit。仓库内plugins-registry/下现存的google-calendar.json、linkedin-alerts.json、tavily.json等条目即此格式的真实样例。如果你想把某个 bundled 插件如gmail、notion、apify——它们是参考种子刻意保持精简稳定不做日常功能开发扩展成自己的维护版官方路径是发布同 id的career-ops-plugin-id在 registry 条目里设supersedesBundled: true批准后引擎会让你的维护继任者优先于 bundled 参考实现node plugins.mjs available会显示 maintained version 提示。优先级只授予registry 批准且钉住精确 commit的继任者未审核的社区插件永远无法顶掉 bundled 插件——这保护的是供应链而不是阻止你在本机运行自己的修改。信任边界与安全前提必须写进 README 的诚实说明career-ops 是纯 ESM、无构建步骤引擎无法真正沙箱化插件的 import。allowedHosts、作用域化的ctx.env以及无 auto-submit 的 hook 分类学约束的是诚实的插件并让每个被加载的插件都可见doctor/plugins.mjs list但它们不是对抗恶意代码的硬边界——恶意代码仍可直接触达process.env或网络。这是社区插件 README 中应如实交代的部分Bundled 插件plugins/下与providers/一样经过代码评审CI 会检查它们未声明核心拥有的密钥、不引入浏览器自动化或进程派生模块、永不自动提交。plugins.local/运行在你自己的信任之下——是你亲手安装的把第三方插件当作任何在你机器上运行的代码一样对待。因此当你把模板 README 中的占位内容替换为真实说明时What it does / Install / Configure / Get it listed / License 五节骨架不应删减建议把上面的密钥来源、hook 行为、信任边界分别映射进 Configure 与上架两节让用户在不看主仓库文档的情况下也能安全地安装与判断你的插件。License随仓库走 MIT模板 plugins/_template/LICENSE 是标准 MIT License版权行模板为 Copyright (c) the career-ops-plugin-{{NAME}} authors。发布前记得把作者名占位替换为真实的插件作者集合模板 README 的 License 一节只写MIT若你的插件引用了某个 bundled 插件的代码起步官方鼓励如此且它本就是 MIT 并注明出处保持 MIT 即可与主仓库的许可证相容。总而言之plugins/_template/的价值在于把career-ops 社区插件到底长什么样压缩到了一个目录、六个文件、一套占位符里。对照 plugins/README.md 的完整契约与 plugins.mjs 的命令实现逐文件替换{{NAME}}、补全 TODO、跑通test/smoke.mjs你就已经站在了提交 registry PR、进入 approved 列表的门槛上。【免费下载链接】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),仅供参考