Write Script
Scope: CLI one-shots under .scripts/<scriptName>/index.mjs. Not app services, Route Handlers, or Server Actions. Standalone — do not copy a prior project’s collection names, DB default, or lib/ helpers.
Secrets → secrets-hygiene. Folders/files → naming-conventions (index.mjs is the required entry). App MongoClient pools → mongodb-connection from mongodb/agent-skills if installed (this skill overrides: one-shots must close() in finally). Omit output/ from staging (git-commit).
Prefer .scripts/lib/ already in this repo. Do not invent a second flag parser or output tree.
Details → REFERENCE.md. Env + flag combos → references/runEnv.md. Row / snapshot contract → references/undoAndSnapshots.md. Skeleton → EXAMPLES.md.
Layout
One camelCase folder per job. Script id = folder name. Output lives in that folder.
.scripts/
lib/ ← shared harness; only once a second script needs it
exampleHeal/
index.mjs ← only entry
helpers.mjs ← optional, this job only
data/ ← optional CSV
output/latest/ ← this run; previous latest/ archived beside it
Env (before any run command)
Look at repo root for .infisical.json, infisical.json, or .Infisical.json.
- Found → Infisical only:
infisical run --env=<env> -- node .scripts/<name>/index.mjs …(never--env-file=.env.local). - Missing → ask once: Infisical (user will add config) vs
--env-file=.env.local. Do not assume.env.local.
Flag combos → runEnv.md.
Safety
Dry-run is default. --apply is the only write switch. --undo still needs --apply.
- Never
--applyon first run;--apply/--undo --applyonly after the user asks. deleteMany/ drop / bulk$unsetof real fields → confirm first.- Every mutation row reversible.
actions.jsonlalways, appended as each action happens (crash-safe). End-only JSON is not enough for undo. - Never log
MONGODB_URI. Gitignore.scripts/*/output/.
Env vars: MONGODB_URI required. MONGODB_DB_NAME from env — this repo’s default if one exists, else require the var. Collections: this repo’s names; --test only if the repo already has that pattern.
Logging
Silent loop = bug. Banner before connect. Phase start/finish. Progress: every batch always; every 100 rows default; --verbose / -v → every row. Summary last.
Agent workflow
- Reuse
.scripts/lib/or an existing job folder - Create
.scripts/<scriptName>/index.mjs; output viaimport.meta.url→./output - Resolve Infisical vs
.env.local(ask once if no config). Dry-run first.--applyonly if asked MongoClient.close()infinally;main().catch→process.exitCode = 1
Finish checklist
- Infisical run cmd, or one confirmation if no config file
-
.scripts/<camelCase>/index.mjs+ colocatedoutput/ - Dry-run default;
--applyonly write switch;--undofrom jsonl before archive - Activity-named files (not a fixed set);
actions.jsonlflushed per action - Pretty JSON indent 4, rewritten each batch; row
before/undo; multi-step snapshots - Progress default 100;
-vevery row; client closed;output/not staged