javascript-script-developer
Skill1 starsChanged 4 months agoMITView on GitHub
Write production-ready Node.js CLI tools, automation scripts, and batch file processors in modern JavaScript — ESM by default, argument parsing via the built-in node:util parseArgs (no yargs/commander unless complexity demands it), structured logging via console.error or a logger (never console.log for diagnostics), node:fs/promises for filesystem work, specific Error subclasses for distinct failure modes, top-level await, graceful SIGINT/SIGTERM handling, and cross-platform support (Linux, macOS, Windows). Targets Node.js 20 LTS and above; mentions Bun and Deno as alternative runtimes when relevant. Use this skill whenever the user asks to create a JavaScript / Node script, .js or .mjs utility, npm CLI tool, automation, batch processor, or data pipeline — including casual phrasings like 'write a node script that ...', 'automate this in JS', 'make me a small CLI', or 'I need a one-off processor'. Also use when reviewing or hardening an existing JavaScript script.
In this repository24 other files it gives its agents.
- AGENTS.mdAGENTS.md
- CLAUDE.mdCLAUDE.md
- architecture-auditSkill
- autodreamSkill
- deep-discoverySkill
- generic-by-designSkill
- gitops-cd-developerSkill
- gitops-pipeline-developerSkill
- golang-script-developerSkill
- humanizerSkill
- information-architectureSkill
- interactive-deck-builderSkill
- linux-script-developerSkill
- makefile-script-developerSkill
- plan-interviewSkill
- pre-commit-setupSkill
- python-script-developerSkill
- qaSkill
- skill-builderSkill
- teacher-modeSkill
- terraform-module-developerSkill
- typescript-script-developerSkill
- ui-deslopSkill
- xquik-x-dataSkill
The file
Show its rules and text
We split this skill into the rules it gives an agent
18 rules. About 0 are common, 3 are distinctive, and 15 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
15
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 47
Every script you write starts from this skeleton.
- Distinctive: line 107
Confirm the package manager: If the script imports anything outside the standard library, install commands must use the user's preferred …
- Very specific: line 108
Confirm the runtime: Default is Node.js 20+. If the user mentions Bun or Deno, load references/runtimes.md to pick the right one.
- Very specific: line 114
Validate the result: Run node scripts/validate-script.mjs <your-script.js> — it checks shebang, ESM, node: prefix, parseArgs, stderr …
- Very specific: line 138
__dirnameis undefined in ESM: Use dirname(fileURLToPath(import.meta.url)). - Distinctive: line 143
SIGINT exits with 130. SIGTERM exits with 143: Don't pick arbitrary codes.
- Very specific: line 148
Start every script from assets/templates/.
- Very specific: line 149
Use ESM (import, node: prefix).
- Very specific: line 152
Use node:fs/promises for all filesystem work.
- Very specific: line 156
Use cross-spawn (or execFile with explicit paths) when invoking child processes that should work on Windows.
- Very specific: line 158
Run validate-script.mjs against the result.
- Very specific: line 162
Use console.log for log lines.
- Very specific: line 163
Use sync fs APIs (readFileSync, writeFileSync, etc.) outside startup.
- Very specific: line 164
Use require() or module.exports — ESM only.
- Very specific: line 167
Use __dirname / __filename in ESM.
- Very specific: line 168
Run Promise.all over thousands of tasks without bounded concurrency.
- Very specific: line 169
Add axios/got for a single HTTP call — global fetch works (Node 18+).
- Distinctive: line 172
Use deprecated callback-style fs APIs.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
JavaScript Script Developer
Production-ready Node.js. ESM + parseArgs + node:fs/promises + structured stderr logging + Error subclasses with exitCodes + graceful signals.
When to use
- The user asks for any
.js/.mjsscript, Node CLI tool, automation, or batch processor. - The user wants to harden, refactor, or review an existing JavaScript script.
- A task chain ends in "and put it in a node script".
Skip this skill for: TypeScript scripts (use typescript-script-developer), browser-only code, or framework-bound code (Next.js, Express apps).
Required structure
Every script you write starts from this skeleton. Do not omit the entry guard, the process.exit(0) from the catch block, or the structured error subclass.
#!/usr/bin/env node
/**
* <one-line description>.
*
* usage: <name> [options] <input>
* exit: 0 ok, 1 generic, 2 usage, 130 interrupt
*/
import { parseArgs } from "node:util";
import { fileURLToPath } from "node:url";
import process from "node:process";
let verbose = false;
const log = {
debug: (...a) => verbose && process.stderr.write(`[debug] ${a.join(" ")}\n`),
info: (...a) => process.stderr.write(`[info] ${a.join(" ")}\n`),
warn: (...a) => process.stderr.write(`[warn] ${a.join(" ")}\n`),
error: (...a) => process.stderr.write(`[error] ${a.join(" ")}\n`),
};
class UsageError extends Error {
constructor(msg) { super(msg); this.exitCode = 2; }
}
async function main() {
const { values, positionals } = parseArgs({
options: {
output: { type: "string", short: "o" },
verbose: { type: "boolean", short: "v" },
help: { type: "boolean", short: "h" },
},
allowPositionals: true,
strict: true,
});
verbose = values.verbose ?? false;
if (values.help) { /* print help */ return 0; }
process.on("SIGINT", () => process.exit(130));
if (process.platform !== "win32") process.on("SIGTERM", () => process.exit(143));
// ... real work ...
return 0;
}
const isEntry = process.argv[1] === fileURLToPath(import.meta.url);
if (isEntry) {
main()
.then((code) => process.exit(code ?? 0))
.catch((err) => {
if (err.exitCode != null) { log.error(err.message); process.exit(err.exitCode); }
log.error("unexpected:", err.stack ?? err.message);
process.exit(1);
});
}Workflow
- Confirm the package manager. If the script imports anything outside the standard library, install commands must use the user's preferred manager. See
references/package-managers.md— read it on the first run, then save the answer to user memory so future runs skip the question. - Confirm the runtime. Default is Node.js 20+. If the user mentions Bun or Deno, load
references/runtimes.mdto pick the right one. - Pick a starting template from
assets/templates/:script.template.js— single-purpose script.cli-tool.template.js— multi-subcommand CLI.file-processor.template.js— batch processing with bounded concurrency.
- Apply patterns from
references/patterns.mdfor argv parsing, logging, error classes, fs, signals, child_process, streams, concurrency, progress. - Validate the result. Run
node scripts/validate-script.mjs <your-script.js>— it checks shebang, ESM,node:prefix, parseArgs, stderr logging, no sync fs, norequire(), error subclass, main+entry-guard, SIGINT. Aim for ≥ 90%. - Cross-check
references/anti-patterns.md— especiallyconsole.logfor diagnostics, sync fs,execwith user input, hardcoded paths,Promise.allwithout bounded concurrency. - For cross-platform scripts, load
references/cross-platform.mdand apply the rules (path separators, signals,cross-spawnfor Windows, exit codes). - Generate man-page-style docs using
references/documentation.md— either inline or as<script>.mdnext to the file.
Available resources
assets/templates/{script,cli-tool,file-processor}.template.js— starting points.assets/examples/csv-analyzer.js— full-featured reference implementation (CSV streaming, gzip, custom error classes, Welford running stats).scripts/validate-script.mjs— score a script against the checklist (run after writing).references/patterns.md— load when implementing parseArgs, logging, errors, fs, signals, child_process, streams, concurrency, progress, env vars.references/anti-patterns.md— load when reviewing or rewriting an existing script.references/cross-platform.md— load when targeting Windows or macOS alongside Linux.references/runtimes.md— load when the user mentions Bun or Deno, or when picking a runtime.references/package-managers.md— load on the first run to capture the user's preferred installer (npm / pnpm / yarn / bun).references/documentation.md— load when generating man-page-style script reference docs.
Top gotchas (always inline — do not skip)
console.error(or stderr writes), neverconsole.logfor diagnostics. Reserveconsole.logfor the script's structured output. Mixing the two breaks downstream pipes.node:fs/promises, never sync APIs in the main flow.readFileSync/writeFileSync/existsSyncblock the event loop.- ESM, not CommonJS.
import, notrequire(). Set"type": "module"inpackage.json, or use.mjs. execFile, notexecfor child processes —execwith user-controlled args is command injection.path.join, never+or${}for filesystem paths. Windows uses\.__dirnameis undefined in ESM. Usedirname(fileURLToPath(import.meta.url)).- Entry guard required. Wrap
main()inif (process.argv[1] === fileURLToPath(import.meta.url))so the file is safe toimport. - Subclass
ErrorwithexitCodefor each distinct failure mode. Map subclasses to exit codes in the top-level catch. process.on("unhandledRejection")andprocess.on("uncaughtException")as belt-and-suspenders. Don't silently die.Promise.allwith no concurrency limit will fail at scale. Bounded pool /p-limitfor any batch over ~50 items.- SIGINT exits with 130. SIGTERM exits with 143. Don't pick arbitrary codes.
engines.nodeinpackage.jsonsonpm installwarns on the wrong runtime.
What you DO
- Start every script from
assets/templates/. - Use ESM (
import,node:prefix). - Parse args with
parseArgsfromnode:util. Reach for commander/yargs only when the CLI has many subcommands or deep help. - Log to stderr. Reserve stdout for the script's structured output.
- Use
node:fs/promisesfor all filesystem work. Use streams for files that don't fit in memory. - Subclass
Errorfor each failure mode and attachexitCode. - Wrap top-level work in
async function main(), gate execution on the entry-guard check. - Register
SIGINT(andSIGTERMon POSIX) for graceful shutdown. - Use
cross-spawn(orexecFilewith explicit paths) when invoking child processes that should work on Windows. - Pin the runtime floor in
package.jsonenginesfield. - Run
validate-script.mjsagainst the result; iterate until ≥ 90%.
What you do NOT do
- Use
console.logfor log lines. - Use sync fs APIs (
readFileSync,writeFileSync, etc.) outside startup. - Use
require()ormodule.exports— ESM only. - Pass user-controlled strings to
exec. UseexecFilewith array args. - Concatenate paths with
+or${}. Usepath.join. - Use
__dirname/__filenamein ESM. Derive fromimport.meta.url. - Run
Promise.allover thousands of tasks without bounded concurrency. - Add
axios/gotfor a single HTTP call — globalfetchworks (Node 18+). - Hardcode absolute paths. Use script-relative or env-var-configurable.
- Skip the lockfile.
package-lock.json/pnpm-lock.yamletc. must be committed. - Use deprecated callback-style fs APIs. Promise APIs only.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

