Issue: inference() passes the system prompt via argv → E2BIG on large system prompts
Repo: danielmiessler/LifeOS · File: LifeOS/install/LIFEOS/TOOLS/Inference.ts (~l.216–225) — confirm line refs against the live file
Version seen: current main (last touched in 7.0.0, 2026-07-12)
Thanks again — offered as contributor support. This is a small companion to a fix you already made (verified by reproduction on Linux, claude 2.1.214).
Summary
inference() builds the claude argv with '--system-prompt', options.systemPrompt. A single argv element cannot exceed MAX_ARG_STRLEN = 32 × PAGE_SIZE = 131072 bytes (128 KiB) on Linux — this is a per-argument kernel limit, distinct from and much smaller than the ~2 MB total ARG_MAX, and it is not tunable via ulimit. So a system prompt larger than ~128 KiB overflows and the spawn fails with E2BIG: argument list too long (fatal for that call).
Verified on this box: a single arg of 100 KB succeeds; 128 KB, 200 KB, 512 KB, 2 MB all fail with E2BIG.
Notably the code already solved this for the user prompt — the l.247 comment "Write prompt via stdin to avoid ARG_MAX limits on large inputs" moved the user prompt to stdin. The system prompt was left on argv, so a large one still overflows.
Reproduction
Call inference() with a systemPrompt > ~128 KiB (e.g. a large formation/memory context). Result:
E2BIG: argument list too long, posix_spawn '.../claude'
Current code (~l.216–225)
const args = [ '--print', '--model', model, '--effort', config.effort, ...,
'--system-prompt', options.systemPrompt ]; // <-- fails at ~128 KiB (MAX_ARG_STRLEN)
Proposed fix (tested)
claude supports --system-prompt-file (verified present in 2.1.214; it's the replace-family counterpart of --system-prompt). Route large prompts through a temp file, gating on bytes well under 128 KiB, with a collision-safe name and idempotent cleanup on all exit paths:
import { writeFileSync, unlinkSync } from 'fs';
import { tmpdir } from 'os';
import { randomUUID } from 'crypto';
const SYS_ARGV_LIMIT = 100_000; // bytes; MAX_ARG_STRLEN=131072 — stay under, and count BYTES not chars
let sysTmpFile: string | null = null;
let systemPromptArgs: string[];
if (Buffer.byteLength(options.systemPrompt, 'utf8') > SYS_ARGV_LIMIT) {
sysTmpFile = join(tmpdir(), `lifeos-sysprompt-${process.pid}-${randomUUID()}.txt`); // randomUUID: parallel inference() calls in one PID collide otherwise
writeFileSync(sysTmpFile, options.systemPrompt, { encoding: 'utf8', mode: 0o600 }); // 0600: system prompt can carry sensitive context
systemPromptArgs = ['--system-prompt-file', sysTmpFile];
} else {
systemPromptArgs = ['--system-prompt', options.systemPrompt];
}
let tmpCleaned = false;
const cleanupTmp = () => { if (tmpCleaned || !sysTmpFile) return; tmpCleaned = true; try { unlinkSync(sysTmpFile); } catch {} };
// args: replace the '--system-prompt' line with ...systemPromptArgs
// call cleanupTmp() in proc 'close', the timeout handler, AND proc 'error' (spawn failure leaks otherwise)
Why these details matter (all reproduced): a naive > 500_000 char threshold leaves 128 KB–500 KB prompts still crashing; .length counts UTF-16 units so multibyte content underestimates bytes; a pid+Date.now() filename collides across parallel inference() calls (the cross-model runner does exactly this); and close+timeout alone double-unlinks and leaks on spawn-error. Verified: a 200 KB system prompt (previously in the crash band) now succeeds, no temp-file leak.
Happy to open a PR (mirrors the fix already applied to the user prompt).
Issue:
inference()passes the system prompt via argv →E2BIGon large system promptsRepo: danielmiessler/LifeOS · File:
LifeOS/install/LIFEOS/TOOLS/Inference.ts(~l.216–225) — confirm line refs against the live fileVersion seen: current
main(last touched in 7.0.0, 2026-07-12)Thanks again — offered as contributor support. This is a small companion to a fix you already made (verified by reproduction on Linux,
claude2.1.214).Summary
inference()builds theclaudeargv with'--system-prompt', options.systemPrompt. A single argv element cannot exceedMAX_ARG_STRLEN= 32 × PAGE_SIZE = 131072 bytes (128 KiB) on Linux — this is a per-argument kernel limit, distinct from and much smaller than the ~2 MB totalARG_MAX, and it is not tunable viaulimit. So a system prompt larger than ~128 KiB overflows and the spawn fails withE2BIG: argument list too long(fatal for that call).Verified on this box: a single arg of 100 KB succeeds; 128 KB, 200 KB, 512 KB, 2 MB all fail with E2BIG.
Notably the code already solved this for the user prompt — the l.247 comment "Write prompt via stdin to avoid ARG_MAX limits on large inputs" moved the user prompt to stdin. The system prompt was left on argv, so a large one still overflows.
Reproduction
Call
inference()with asystemPrompt> ~128 KiB (e.g. a large formation/memory context). Result:Current code (~l.216–225)
Proposed fix (tested)
claudesupports--system-prompt-file(verified present in 2.1.214; it's the replace-family counterpart of--system-prompt). Route large prompts through a temp file, gating on bytes well under 128 KiB, with a collision-safe name and idempotent cleanup on all exit paths:Why these details matter (all reproduced): a naive
> 500_000char threshold leaves 128 KB–500 KB prompts still crashing;.lengthcounts UTF-16 units so multibyte content underestimates bytes; apid+Date.now()filename collides across parallelinference()calls (the cross-model runner does exactly this); andclose+timeoutalone double-unlinks and leaks on spawn-error. Verified: a 200 KB system prompt (previously in the crash band) now succeeds, no temp-file leak.Happy to open a PR (mirrors the fix already applied to the user prompt).