Replies: 2 comments
|
This is an interesting and useful proposal, especially the explicit trust model around local-first plugins, registry pinning, and no auto-submit. One hook-contract question: do you envision any of the five hooks ( The OCF case is the example I have in mind. This is a little different from the keyed/external integrations you describe: the OCF connector would be local and zero-key, using the same LLM session Career-Ops is already running. Open Career Format is not a service and has no API; it is an open schema with prompts/skills around it. A Career-Ops integration would not call OCF over the network. Instead, when Career-Ops needs candidate context for a search track, it could run a scoped workflow over declared local files: read the candidate’s local OCF file, apply OCF/Career-Ops connector instructions for that subtask, and refresh Career-Ops user-layer files for that track. This plugin would augment, not replace, the Career-Ops structure: model, files, workflow, and conventions. OCF’s boundaries are clear and focused on candidate-owned career history. The reverse direction would also be scoped. When Career-Ops is about to save candidate-facing context or user-authored search-profile material, it could invoke the connector to ask whether any reusable candidate-context improvement should be proposed back to the candidate’s OCF file. That proposal would be reviewed by the user and would be in addition to whatever Career-Ops was already going to save. Job listings, scores, pipeline state, and reports would remain outside the candidate’s OCF file. If this is in scope, I assume the connector instructions would live in the reviewed/pinned plugin tree, or be version-pinned the same way, rather than being copied ad hoc or silently updated. So the design question is whether |
|
Great question, @dmadeo — and good news: you don't need a new hook for this. The five hooks are deliberately data-shaped (provider/ingest/search/notify/export), but the plugin system has a second layer that does exactly what you describe: a plugin can ship a skill, which teaches the already-running agent session how to drive the plugin — local, zero-key, same LLM session, bounded by the plugin's declared surface. That's how the bundled seeds (gmail/notion) work today. So the OCF adapter maps cleanly: the deterministic OCF file read/write lives in plugin code behind Concretely: publish |
Uh oh!
There was an error while loading. Please reload this page.
Proposing a plugin system for career-ops. The implementation landed in #1333 (merged); this RFC opens the design for community input before the contract stabilizes.
Summary
career-ops core is deliberately local-first and zero-keys — it runs on your
machine against public job-board APIs, no accounts or API keys required. That
design has kept the core simple and trustworthy, but it left ~a dozen
community-requested integrations (Gmail, Notion, Apify, Telegram, Tavily,
Microsoft Graph, Google Workspace, …) with nowhere to live: they all need a key,
an account, or a third-party service.
This RFC proposes an opt-in plugin system that gives those integrations a
home without compromising the core. It generalizes the pattern career-ops
already uses for scanner providers, stays local-first, and is byte-identical
when no plugin is enabled. Implementation: #1333 (838 tests passing).
The problem
plugin-candidateissues) was triaged case-by-case with nocanonical answer to "how do I plug X into career-ops?".
them.
The proposal
The engine generalizes a pattern career-ops already ships
providers/is already an auto-discovered plugin layer (scan.mjsloadsproviders/*.mjs, each exporting{ id, detect, fetch }). The plugin enginegeneralizes that into a sibling
plugins/layer for integrations that need a keyor an external service. The zero-key
providers/dir is untouched.A plugin is a directory
Five hooks —
provider,ingest,search,notify,export. There isno auto-submit hook: career-ops drafts applications for you to review and
submit; that is enforced by the contract, not just policy. Producers
(
provider/ingest/search) returnJob[]; the engine writes the canonicalfiles, so a plugin can't corrupt your tracker/pipeline format.
Opt-in, two gates
Nothing loads unless you (1) enable it in
config/plugins.ymland (2) provide itskeys in your own
.env. With neither, the core behaves exactly as before.Honest trust + safety
career-ops is plain ESM with no build step, so there is no hard sandbox — and
the docs say so plainly. What the engine does give you:
ctx.fetch(HTTPS-only, pinned to the plugin's declaredallowedHosts, rejects private/loopback/cloud-metadata addresses, re-checksevery redirect hop, strips cross-host credentials).
tampering: if a community plugin's files change without a version bump, it's
blocked until you review + re-trust it (the rug-pull defense).
child_process, rawsockets, global
fetch,eval, and third-party npm dependencies — they egressonly through
ctx.fetch.Containment is code review (for bundled + registry plugins) and your own
trust (for anything you install yourself). Stated, not overclaimed.
Distribution + the registry
Community plugins are published as the author's own public repo named
career-ops-plugin-<name>(a template +node plugins.mjs new <name>scaffoldthe minimum file set). Installing pins an exact commit and runs the audit:
A curated
plugins-registry.jsonis the single trust root: a plugin appearsthere only via a reviewed PR pinned to an exact commit, and users only ever
install the commit the shipped registry names — so an author can't reach users
without passing review. The registry ships with the normal update, so approved
updates flow to users automatically; the source repo never reaches them directly.
Getting approved (the path)
career-ops-plugin-<name>(template gives you the shape + CI).commit, validates the manifest + min-files, and runs the static audit before a
maintainer reviews. Updates are one more small registry PR.
in
plugins/).What is NOT a plugin
shared services, proxies) → a separate, opt-in service (Discussion Where career-ops is going #904).
Status
Implemented in #1333: the engine, the 3 reference plugins (Apify, Gmail,
Notion — ported with credit from #693/#1203/#959), the CLI, the registry, the
adoption templates/CI, and docs (
docs/PLUGINS.md,docs/PLUGIN_REVIEW.md). 838tests pass; scan verified byte-identical with no plugins configured.
Questions for the community
provider/ingest/search/notify/export) coverwhat you'd build? Anything missing that isn't auto-submit?
career-ops-plugin-<name>+ registry-PR flow a reasonableon-ramp, or too heavy?
Feedback welcome here before the contract stabilizes.
All reactions