Scaffold a new sub-worker inside packages_worker (npm, deps.dev, osv, scorecard, etc.) following the single-service multi-entry-point structure. Use when: "add a new packages worker", "scaffold a sub-worker in packages_worker", "new worker for packages-db", "add npm worker", "add OSV worker", "add deps.dev worker".
67
82%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
You are adding a new data-ingestion worker to services/apps/packages_worker/.
The structure follows the same pattern as backend/ (where api.ts and
job-generator.ts share one Dockerfile): one npm package, one Docker image,
each worker in its own src/{worker}/ directory with its own entry point.
services/apps/packages_worker/
src/
bin/
github-repos-enricher.ts ← existing worker
<name>.ts ← entry point you will create
github/ ← existing worker logic
<worker>/ ← directory you will create
index.ts ← main logic for this worker
types.ts
config.ts ← shared — add your config getter here
db.ts ← shared — do not modifyAsk the engineer for:
npm-sync, osv-sync, scorecard-runner. Used as the entry point filename (src/bin/<name>.ts) and docker-compose service name.npm, osv, scorecard. Becomes src/<worker>/.NPM_API_URL, OSV_API_KEY.Do not proceed until you have answers to 1–3.
cat services/apps/packages_worker/src/bin/github-repos-enricher.ts
cat services/apps/packages_worker/src/config.ts
cat services/apps/packages_worker/package.json
cat scripts/services/github-repos-enricher.yamlThese are the canonical references. Do not deviate from the patterns you see there.
services/apps/packages_worker/src/<worker>/Create the directory with at minimum:
types.ts — types specific to this worker (input/output shapes, error kinds if calling an external API).
index.ts — the main logic function(s) this worker runs. What goes here depends entirely on what the worker does — do not force a loop shape if it does not fit. Discuss with the engineer what the execution model should be (continuous loop, one-shot batch, event-driven, etc.) and implement accordingly.
Add any additional files the worker needs (e.g. an API client, a DB query helper). All DB access uses inline pg-promise SQL via qx.select / qx.result / qx.none — do not add files to services/libs/data-access-layer.
services/apps/packages_worker/src/bin/<name>.tsFollow the structure of github-repos-enricher.ts:
getServiceLogger from @crowd/logging../config and getPackagesDb from ../db../<worker>/indexliveFilePath / readyFilePath to ../tmp/<name>-live.tmp / ../tmp/<name>-ready.tmpshuttingDown flagmain(): call config getter → validate any required tokens/keys → await getPackagesDb() → await qx.selectOne('SELECT 1') → fs.mkdirSync for the tmp dir → setInterval writing probe files every 5000ms → call your worker's main function → clearInterval → process.exit(0)main().catch(err => { log.error({ err }, '<name> fatal error'); process.exit(1) })services/apps/packages_worker/src/config.tsRead the file first, then add a get<Worker>Config() function:
requireEnv(name) for string vars, requireEnvInt(name) for integers?? undefined — the process must refuse to start on missing configscripts/services/<name>.yamlCopy scripts/services/github-repos-enricher.yaml and adapt:
<name> (prod) and <name>-dev (dev)command (prod): pnpm run start:<name>command (dev): pnpm run dev:<name>env_file: keep the same four files (backend/.env.dist.local, backend/.env.dist.composed, backend/.env.override.local, backend/.env.override.composed)environment: set any tuning var defaults inline (avoids requiring them in .env.override.local for local dev)volumes (dev only): bind-mount ./services/apps/packages_worker/src plus every services/libs/*/src directory (copy the full list from the enricher yaml for hot reload)services/apps/packages_worker/package.jsonRead the file first, then add:
"start:<name>": "tsx src/bin/<name>.ts",
"dev:<name>": "tsx watch src/bin/<name>.ts"backend/.env.dist.local and backend/.env.dist.composedAppend new required vars with empty-string defaults (or sensible local values for non-secrets):
NEW_WORKER_API_KEY=cd services/apps/packages_worker && pnpm tsc --noEmitFix any errors before proceeding.
src/<worker>/ directory created with types.ts and index.tssrc/bin/<name>.ts — probe files, SIGINT/SIGTERM handler, fail-fast config check, SELECT 1 on startupconfig.ts — new get<Worker>Config() using requireEnv/requireEnvInt, no defaultsscripts/services/<name>.yaml — prod + dev services with bind mountspackage.json — start:<name> and dev:<name> scripts addedbackend/.env.dist.local and .env.dist.composed — new vars documentedservices/libs/data-access-layer (packages-db uses inline SQL)pnpm tsc --noEmit passesUse /preflight before opening a PR and /commit to sign off.
7038855
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.