From harness-claude
Spawn and manage Node.js child processes using exec, execFile, spawn, fork, and IPC for running shell commands, external tools like ffmpeg/git/curl, or parallel worker scripts.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Spawn and manage child processes with exec, spawn, fork, and IPC communication
Offloads CPU-intensive tasks to Node.js worker threads using MessageChannel, shared buffers, pools, and SharedArrayBuffer for parallel computation without blocking the event loop.
Turns any CLI tool into a fully typed JavaScript/TypeScript API by parsing --help output. Enables calling subcommands and flags from Node.js with autocomplete and type safety.
Provides bash patterns for parallel and concurrent processing using GNU Parallel, xargs, job pools, worker control, and async techniques to accelerate batch tasks.
Share bugs, ideas, or general feedback.
Spawn and manage child processes with exec, spawn, fork, and IPC communication
exec for simple commands with buffered output:import { exec } from 'node:child_process';
import { promisify } from 'node:util';
const execAsync = promisify(exec);
const { stdout, stderr } = await execAsync('git log --oneline -5');
console.log(stdout);
execFile for running executables (no shell, safer):import { execFile } from 'node:child_process';
import { promisify } from 'node:util';
const execFileAsync = promisify(execFile);
const { stdout } = await execFileAsync('node', ['--version']);
spawn for streaming output from long-running processes:import { spawn } from 'node:child_process';
const child = spawn('ffmpeg', ['-i', 'input.mp4', '-c:v', 'libx264', 'output.mp4']);
child.stdout.on('data', (data) => console.log(`stdout: ${data}`));
child.stderr.on('data', (data) => console.error(`stderr: ${data}`));
child.on('close', (code) => {
console.log(`Process exited with code ${code}`);
});
fork for Node.js worker scripts with IPC:// parent.ts
import { fork } from 'node:child_process';
const child = fork('./worker.ts');
child.send({ task: 'process', data: [1, 2, 3] });
child.on('message', (result) => {
console.log('Result from child:', result);
});
// worker.ts
process.on('message', (msg: any) => {
const result = msg.data.map((n: number) => n * 2);
process.send!(result);
});
import { spawn } from 'node:child_process';
function run(command: string, args: string[]): Promise<string> {
return new Promise((resolve, reject) => {
const child = spawn(command, args);
let stdout = '';
let stderr = '';
child.stdout.on('data', (data) => {
stdout += data;
});
child.stderr.on('data', (data) => {
stderr += data;
});
child.on('error', reject); // Spawn error (command not found)
child.on('close', (code) => {
if (code === 0) resolve(stdout);
else reject(new Error(`Exit code ${code}: ${stderr}`));
});
});
}
const child = spawn('npm', ['run', 'build'], {
cwd: '/path/to/project',
env: { ...process.env, NODE_ENV: 'production' },
timeout: 60_000,
});
const child = spawn('long-running-process');
process.on('SIGTERM', () => {
child.kill('SIGTERM');
});
// Or with AbortController
const ac = new AbortController();
const child = spawn('command', [], { signal: ac.signal });
ac.abort(); // Kills the child process
exec runs a shell command, buffers the entire output, and returns it. spawn streams output as it arrives. fork creates a Node.js child process with a built-in IPC channel.
exec vs spawn vs fork:
exec — shell, buffered output, 1MB default limit. Best for short commandsspawn — no shell (by default), streaming output, no buffer limit. Best for long-running or large-output processesfork — specialized spawn for Node.js scripts with IPC. Best for parallel Node.js workSecurity: exec runs through a shell, making it vulnerable to command injection. Never pass user input to exec without sanitization. Use execFile or spawn (no shell) for user-provided arguments.
Trade-offs:
exec is simple — but buffers all output in memory and uses a shellspawn streams output — but requires manual output collectionfork has built-in IPC — but only works with Node.js scriptshttps://nodejs.org/api/child_process.html