feat(batch_execute): opt-in concurrency for parallel command runs#358
feat(batch_execute): opt-in concurrency for parallel command runs#358sebastianbreguel wants to merge 2 commits intomksglu:nextfrom
Conversation
Add concurrency field (default 1, max 8) to ctx_batch_execute. Serial path preserved bit-for-bit at concurrency=1. Parallel path uses inline worker pool (no new deps), preserves output order via index-keyed array, gives each command its own full timeout instead of shared budget. Bench (macOS arm64, 5x 500ms sleeps): - c=1: 3336ms (baseline) - c=2: 2120ms (1.57x) - c=4: 1598ms (2.09x) - c=8: 984ms (3.39x) Includes tests/bench/batch-execute-parallel.ts for repeatable measurement.
Real end-to-end test on Claude Code MCP transportSpawned Schema (from {"type":"integer","minimum":1,"maximum":8,"default":1,"description":"Max commands to run in parallel (1-8, default: 1). >1 switches to per-command timeouts (no shared budget) and individual `(timed out)` blocks instead of cascading skip."}Wall-clock (4 commands with reverse delays: 800ms / 600ms / 400ms / 200ms):
Serial ≈ Σ delays = 2000ms (+ MCP/index overhead). Parallel ≈ max delay = 800ms (+ overhead). Order preservation under reverse delays. Input order, not completion order. Both Validation: Harness script that produced this: https://gist.github.com/sebastianbreguel — happy to inline if you want it added under |
Summary
Adds opt-in
concurrencyfield (default 1, max 8) toctx_batch_execute. Independent shell commands now run in parallel when requested.concurrency=1(default). Existing callers unaffected — same shared timeout budget, same cascading skip-on-timeout.timeoutms (not a shared budget).__CM_FS__markers parsed per command.bytesSandboxedaccumulator stays race-free (JS single-thread).Bench (macOS arm64, Node 22, 5× 500ms sleeps)
Reproduce:
npm run bench:batch-parallel. Tunable viaN,SLEEP_MS,LEVELSenv vars. Bench script importsrunBatchCommandsdirectly — no MCP stdio in the loop.Design notes
concurrency(integer 1–8) chosen overparallel: booleanfor forward flexibility — single knob, clear semantics.nextIdx++) instead ofp-limitdep.Test plan
bytesSandboxedcallback shaperunBatchCommandsserial path: happy path, cascading skip, shared timeoutrunBatchCommandsparallel path: happy path, order preservation under reverse delays, concurrency cap, per-cmd timeout, cap clamped at cmd count, FS bytes callbacknodeOptsPrefixprependingtests/core/server.test.tspassnpx tsc --noEmitcleanFiles
src/server.ts— extractedrunBatchCommands+ types, added schema field, updated tool descriptiontests/core/server.test.ts— 3 new describe blocks (~180 LOC) + updated existing source-scan testtests/bench/batch-execute-parallel.ts— manual bench script (not vitest)package.json—bench:batch-parallelscript