Codex background delegation This support skill changes Codex's waiting boundary. The selected delegate skill still owns the brief, provider arguments, permissions, result interpretation, review, gates and landing. Claude's background Bash workflow stays unchanged. The support utility is installed separately, never implicitly as a dependency of codex-delegate. Details: references/configuration.md. First use / setup If the tool is not available, setup is incomplete. Tell the user that bootstrap will update (default , backed up first) and write a registry of the installed skills, then run: is th…

};\nconst COMMON_FLAGS = ['--brief', '--cd', '--out-dir', '--timeout'];\nconst GRACE_MS = 15000;\nconst DELIVERY_MARGIN_MS = 30000;\nconst MAX_TIMER_MS = 2147483647;\n\nfunction onlyKeys(value, keys) {\n if (!value || typeof value !== 'object' || Array.isArray(value) || Object.keys(value).some(key => !keys.includes(key))) throw Error('Unexpected object fields');\n}\nfunction absolute(value) {\n if (typeof value !== 'string' || value.includes('\\0') || !isAbsolute(value)) throw Error('Paths must be absolute');\n return resolve(value);\n}\nfunction futurePath(value) {\n let parent = absolute(value);\n const parts = [];\n while (!existsSync(parent)) { parts.unshift(basename(parent)); parent = dirname(parent); }\n return join(realpathSync(parent), ...parts);\n}\nfunction within(path, roots) {\n return roots.some(root => { const r = relative(root, path); return r === '' || (r !== '..' && !r.startsWith(`..${sep}`) && !isAbsolute(r)); });\n}\nfunction directories(values) {\n if (!Array.isArray(values) || !values.length) throw Error('Configure nonempty root arrays');\n return values.map(value => { const path = realpathSync(absolute(value)); if (!statSync(path).isDirectory()) throw Error('Configured root is not a directory'); return path; });\n}\nfunction readRegistry(file) {\n if (!['win32', 'linux'].includes(process.platform)) throw Error('Safe ownership requires Windows or Linux; other hosts are unsupported');\n if (process.platform === 'linux' && !existsSync('/usr/bin/cc')) throw Error('Linux ownership requires the system C compiler at /usr/bin/cc');\n if (!file) throw Error('Missing CODEX_BACKGROUND_REGISTRY: configure the codex-background MCP server registry first');\n const source = readFileSync(absolute(file), 'utf8');\n const registry = JSON.parse(source);\n onlyKeys(registry, ['schema', 'hostToolTimeoutSeconds', 'stateDirectory', 'workspaceRoots', 'artifactRoots', 'relays']);\n if (registry.schema !== 'codex-background.registry.v1') throw Error('Unsupported registry schema');\n const budgetMs = registry.hostToolTimeoutSeconds * 1000;\n if (!Number.isInteger(registry.hostToolTimeoutSeconds) || budgetMs \u003c= DELIVERY_MARGIN_MS + 1000 || budgetMs > MAX_TIMER_MS) throw Error('Invalid host tool timeout');\n const workspaceRoots = directories(registry.workspaceRoots);\n const artifactRoots = directories(registry.artifactRoots);\n const stateDirectory = futurePath(registry.stateDirectory);\n if (!within(stateDirectory, artifactRoots)) throw Error('State directory is outside artifact roots');\n if (!registry.relays || typeof registry.relays !== 'object' || Array.isArray(registry.relays) || !Object.keys(registry.relays).length) throw Error('Configure an explicit relay registry');\n const relays = new Map();\n for (const [key, value] of Object.entries(registry.relays)) {\n if (!/^[a-z][a-z0-9-]*$/.test(key)) throw Error('Invalid implementer key');\n const path = realpathSync(absolute(value));\n if (!statSync(path).isFile() || basename(path) !== 'relay.mjs' || basename(dirname(path)) !== 'scripts' || basename(dirname(dirname(path))) !== `${key}-delegate`) throw Error(`Invalid registered relay for ${key}`);\n relays.set(key, path);\n }\n return { budgetMs, workspaceRoots, artifactRoots, stateDirectory, relays };\n}\nfunction validId(value) {\n if (typeof value !== 'string' || !/^[A-Za-z0-9_-]{1,80}$/.test(value)) throw Error('Invalid runId');\n}\nfunction persist(path, value) {\n const temporary = `${path}.tmp`;\n writeFileSync(temporary, JSON.stringify(value, null, 2), { mode: 0o600 });\n renameSync(temporary, path);\n}\nfunction opaqueResult(path) {\n const bytes = readFileSync(path);\n const text = bytes.toString('utf8');\n const utf8 = Buffer.from(text).equals(bytes);\n return { resultPath: path, resultEncoding: utf8 ? 'utf8' : 'base64', resultText: utf8 ? text : bytes.toString('base64') };\n}\nfunction toolResult(outcome) {\n return { content: [{ type: 'text', text: JSON.stringify(outcome) }], isError: outcome.adapterStatus !== 'completed' };\n}\n\nexport function startServer({ registryFile = process.env.CODEX_BACKGROUND_REGISTRY, input = process.stdin, output = process.stdout } = {}) {\n const registry = readRegistry(registryFile);\n const jobs = new Map();\n const active = new Set();\n const cancelled = new Set();\n const artifactRoot = registry.artifactRoots[0].replaceAll('\\\\', '/');\n const idSchema = { type: 'object', properties: { runId: ID }, required: ['runId'], additionalProperties: false };\n const runSchema = {\n type: 'object', additionalProperties: false,\n required: ['runId', 'implementer', 'brief', 'workspace', 'outputDirectory', 'relayTimeoutSeconds'],\n properties: {\n runId: ID, implementer: { type: 'string', enum: [...registry.relays.keys()] },\n brief: { type: 'string', description: `Absolute existing brief file in approved roots, e.g. ${artifactRoot}/briefs/\u003crunId>.txt (create the briefs directory if missing).` },\n workspace: { type: 'string', description: 'Absolute approved workspace directory.' },\n outputDirectory: { type: 'string', description: `Absolute fresh relay artifact directory, e.g. ${artifactRoot}/runs/\u003crunId>.` },\n relayTimeoutSeconds: { type: 'integer', minimum: 1, maximum: Math.floor((registry.budgetMs - DELIVERY_MARGIN_MS - 1) / 1000) },\n relayArgs: { type: 'array', items: { type: 'string' }, default: [] },\n },\n };\n const tools = [\n { name: 'delegate_run', description: 'Codex only: invoke a registered existing delegate relay. This request stays pending until relay closure. Do not poll or read progress logs; review the opaque result and rerun gates before landing.', inputSchema: runSchema, annotations: { readOnlyHint: false, destructiveHint: true, idempotentHint: false, openWorldHint: true } },\n { name: 'delegate_wait', description: 'Reattach after an interrupted wait; never redispatch. Wait for a live owned job, recover a persisted terminal outcome, or report recovery_required for unresolved state.', inputSchema: idSchema, annotations: { readOnlyHint: true, openWorldHint: false } },\n { name: 'delegate_abort', description: 'Explicitly terminate only a live job owned by this server. Cancelling a wait alone does not abort delegation. Never kill an old PID after restart.', inputSchema: idSchema, annotations: { readOnlyHint: false, destructiveHint: true, openWorldHint: false } },\n ];\n let transportOpen = true;\n const send = value => { if (transportOpen && !output.destroyed && !output.writableEnded) output.write(`${JSON.stringify(value)}\\n`); };\n\n function prepare(args) {\n onlyKeys(args, Object.keys(runSchema.properties));\n validId(args.runId);\n if (!registry.relays.has(args.implementer)) throw Error('Implementer is not registered');\n const workspace = realpathSync(absolute(args.workspace));\n const brief = realpathSync(absolute(args.brief));\n const outputDirectory = futurePath(args.outputDirectory);\n if (!statSync(workspace).isDirectory() || !within(workspace, registry.workspaceRoots)) throw Error('Workspace is outside configured roots');\n if (!statSync(brief).isFile() || !within(brief, [...registry.workspaceRoots, ...registry.artifactRoots])) throw Error('Brief is outside configured roots');\n if (!within(outputDirectory, registry.artifactRoots) || within(outputDirectory, [registry.stateDirectory])) throw Error('Output must be in artifact roots and outside adapter state');\n if (existsSync(outputDirectory)) throw Error('Use a fresh output directory');\n const timeoutMs = args.relayTimeoutSeconds * 1000;\n if (!Number.isInteger(args.relayTimeoutSeconds) || timeoutMs \u003c= 0 || timeoutMs + DELIVERY_MARGIN_MS >= registry.budgetMs) throw Error('Host timeout must exceed relay timeout by more than thirty seconds');\n const relayArgs = args.relayArgs ?? [];\n if (!Array.isArray(relayArgs) || relayArgs.some(arg => typeof arg !== 'string' || arg.includes('\\0'))) throw Error('relayArgs must be a string array');\n for (const arg of relayArgs) if (COMMON_FLAGS.some(flag => arg === flag || arg.startsWith(`${flag}=`))) throw Error('Common flags must use structured inputs');\n // Extra workspace access is checked without changing the relay-native argument array.\n for (let i = 0; i \u003c relayArgs.length; i++) {\n if (relayArgs[i].startsWith('--add-dir=')) throw Error('Use a separate --add-dir value');\n if (relayArgs[i] === '--add-dir') {\n const value = relayArgs[++i];\n if (!value || !within(realpathSync(resolve(workspace, value)), registry.workspaceRoots)) throw Error('Extra workspace is outside configured roots');\n }\n }\n const runDirectory = join(registry.stateDirectory, args.runId);\n if (existsSync(runDirectory)) throw Error('runId already used; call delegate_wait');\n const relayPath = registry.relays.get(args.implementer);\n if (realpathSync(relayPath) !== relayPath) throw Error('Registered relay identity changed; reload the registry');\n const argv = [...relayArgs, '--brief', brief, '--cd', workspace, '--out-dir', outputDirectory, '--timeout', `${args.relayTimeoutSeconds}s`];\n return { runId: args.runId, implementer: args.implementer, workspace, outputDirectory, runDirectory, relayPath, argv, timeoutMs };\n }\n\n async function terminate(job) {\n if (job.anchorExited) return job.cleanup; // Native parent-death cleanup owns the tree now; never signal an old PID.\n if (job.exited || job.ownerExited || job.child.exitCode !== null) return;\n if (process.platform === 'win32') {\n await new Promise((resolveStop, rejectStop) => {\n const systemRoot = process.env.SystemRoot || process.env.WINDIR;\n if (!systemRoot) { rejectStop(Error('Windows system directory is unavailable')); return; }\n const killer = spawn(join(systemRoot, 'System32', 'taskkill.exe'), ['/PID', String(job.child.pid), '/T', '/F'], { windowsHide: true, stdio: 'ignore' });\n const limit = setTimeout(() => { killer.kill(); rejectStop(Error('Process-tree termination timed out')); }, 5000);\n killer.once('error', error => { clearTimeout(limit); rejectStop(error); });\n killer.once('exit', code => { clearTimeout(limit); if (code === 0 || job.ownerExited) resolveStop(); else rejectStop(Error(`Process-tree termination failed (${code})`)); });\n });\n } else {\n try { process.kill(-job.child.pid, 'SIGTERM'); } catch (error) { if (error.code !== 'ESRCH') throw error; }\n // Sweep the owned process group even if its parent exits before a stubborn descendant.\n await new Promise(resolveGrace => setTimeout(resolveGrace, 3500));\n if (job.anchorExited) { await job.cleanup; return; } // Never signal a recycled group ID.\n try { process.kill(-job.child.pid, 'SIGKILL'); } catch (error) { if (error.code !== 'ESRCH') throw error; }\n }\n }\n function stop(job, reason) {\n if (job.anchorExited) return job.cleanup;\n if (job.exited || job.ownerExited) return job.termination ?? Promise.resolve();\n if (!job.termination) {\n job.stopReason = reason;\n job.termination = terminate(job);\n job.termination.catch(error => { job.errors.push(error.message); });\n }\n return job.termination;\n }\n\n function launch(args) {\n if (closing) throw Error('Server is shutting down; no new delegation is accepted');\n const spec = prepare(args);\n mkdirSync(registry.stateDirectory, { recursive: true });\n mkdirSync(join(registry.stateDirectory, 'output-claims'), { recursive: true });\n mkdirSync(spec.runDirectory); // Exclusive durable run claim, including across server instances.\n const outputKey = createHash('sha256').update(process.platform === 'win32' ? spec.outputDirectory.toLowerCase() : spec.outputDirectory).digest('hex');\n const claim = join(registry.stateDirectory, 'output-claims', outputKey);\n const manifest = { runId: spec.runId, implementer: spec.implementer, outputDirectory: spec.outputDirectory, resultPath: join(spec.outputDirectory, 'result.json'), stdoutPath: join(spec.runDirectory, 'stdout.log'), stderrPath: join(spec.runDirectory, 'stderr.log'), phase: 'claimed' };\n try { writeFileSync(claim, spec.runId, { flag: 'wx', mode: 0o600 }); persist(join(spec.runDirectory, 'run.json'), manifest); }\n catch (error) { persist(join(spec.runDirectory, 'outcome.json'), { ...manifest, adapterStatus: 'failed', error: error.message }); throw error; }\n const stdout = createWriteStream(manifest.stdoutPath, { flags: 'wx', mode: 0o600 });\n const stderr = createWriteStream(manifest.stderrPath, { flags: 'wx', mode: 0o600 });\n const stdoutDone = finished(stdout).catch(error => error);\n const stderrDone = finished(stderr).catch(error => error);\n const ownerSpec = join(spec.runDirectory, 'owner-spec.json');\n persist(ownerSpec, { node: process.execPath, relayPath: spec.relayPath, argv: spec.argv, workspace: spec.workspace, runDirectory: spec.runDirectory });\n const child = spawn(process.execPath, [fileURLToPath(new URL('./supervisor.mjs', import.meta.url)), ownerSpec], { cwd: spec.workspace, windowsHide: true, detached: process.platform !== 'win32', stdio: ['ignore', 'pipe', 'pipe'] });\n const job = { child, errors: [], stopReason: null, termination: null, ownerExited: false, anchorExited: false, cleanup: Promise.resolve(), exited: false };\n jobs.set(spec.runId, job);\n const guard = setTimeout(() => { stop(job, 'adapter_timeout').catch(() => {}); }, spec.timeoutMs + GRACE_MS);\n child.once('error', error => { job.errors.push(error.message); });\n child.once('exit', () => {\n job.anchorExited = true;\n clearTimeout(guard);\n job.cleanup = (async () => {\n if (process.platform === 'linux' && existsSync(join(spec.runDirectory, 'owner-ready.json'))) {\n const deadline = Date.now() + 5000;\n while (!existsSync(join(spec.runDirectory, 'owner-closed.json'))) {\n if (Date.now() >= deadline) throw Error('Linux ownership cleanup was not confirmed after supervisor exit');\n await new Promise(resolveCleanup => setTimeout(resolveCleanup, 20));\n }\n }\n job.ownerExited = true;\n })();\n job.cleanup.catch(error => { job.errors.push(error.message); });\n const drain = setTimeout(() => { if (!job.exited) { child.stdout.destroy(); child.stderr.destroy(); stdout.end(); stderr.end(); } }, 1000);\n drain.unref();\n });\n for (const [source, target] of [[child.stdout, stdout], [child.stderr, stderr]]) {\n target.once('error', () => { source.unpipe(target); source.resume(); });\n source.pipe(target);\n }\n job.done = new Promise(resolveDone => child.once('close', async (exitCode, signal) => {\n clearTimeout(guard);\n if (job.termination) await job.termination.catch(() => {});\n await job.cleanup.catch(() => {});\n job.exited = true;\n stdout.end(); stderr.end();\n for (const error of await Promise.all([stdoutDone, stderrDone])) if (error) job.errors.push(error.message);\n let result = {};\n try { result = opaqueResult(manifest.resultPath); } catch (error) { job.errors.push(error.message); }\n let relayExit = { exitCode, signal };\n try { relayExit = JSON.parse(readFileSync(join(spec.runDirectory, 'relay-exit.json'), 'utf8')); } catch {}\n try {\n const owner = JSON.parse(readFileSync(join(spec.runDirectory, 'owner-outcome.json'), 'utf8'));\n if (owner.error) job.errors.push(owner.error);\n if (process.platform === 'win32' && owner.ownerExitCode !== relayExit.exitCode && !job.stopReason) job.errors.push('Windows job owner did not close normally');\n } catch { if (!job.stopReason) job.errors.push('Ownership supervisor exited without a terminal outcome'); }\n const outcome = { ...manifest, ...result, ...relayExit, phase: 'closed', adapterStatus: job.stopReason || (exitCode === 0 && relayExit.exitCode === 0 && !job.errors.length ? 'completed' : 'failed'), errors: job.errors };\n try { persist(join(spec.runDirectory, 'outcome.json'), outcome); } catch (error) { outcome.adapterStatus = 'failed'; outcome.errors.push(error.message); }\n resolveDone(outcome);\n }));\n return job.done;\n }\n\n async function callTool(name, args) {\n if (name === 'delegate_run') return toolResult(await launch(args));\n onlyKeys(args, ['runId']); validId(args.runId);\n const job = jobs.get(args.runId);\n if (name === 'delegate_wait') {\n if (job) return toolResult(await job.done);\n const runDirectory = join(registry.stateDirectory, args.runId);\n if (existsSync(join(runDirectory, 'outcome.json'))) return toolResult(JSON.parse(readFileSync(join(runDirectory, 'outcome.json'), 'utf8')));\n if (!existsSync(runDirectory)) throw Error('Unknown runId');\n return toolResult({ runId: args.runId, adapterStatus: 'recovery_required', runDirectory, errors: ['No persisted terminal outcome or live owned job; inspect artifacts, never redispatch automatically or adopt an old PID.'] });\n }\n if (name === 'delegate_abort') {\n if (!job) throw Error('Abort only applies to a live job owned by this server');\n await stop(job, 'aborted');\n return toolResult(await job.done);\n }\n throw Error('Unknown tool');\n }\n\n const lines = createInterface({ input, crlfDelay: Infinity });\n lines.on('line', line => {\n let request;\n try { request = JSON.parse(line); } catch { send({ jsonrpc: '2.0', id: null, error: { code: -32700, message: 'Invalid JSON' } }); return; }\n if (!request || typeof request !== 'object' || Array.isArray(request)) { send({ jsonrpc: '2.0', id: null, error: { code: -32600, message: 'Invalid request' } }); return; }\n if (request.method === 'notifications/cancelled') { if (active.has(request.params?.requestId)) cancelled.add(request.params.requestId); return; }\n if (!Object.hasOwn(request, 'id')) return;\n if (active.has(request.id)) { send({ jsonrpc: '2.0', id: request.id, error: { code: -32600, message: 'Duplicate request ID' } }); return; }\n active.add(request.id);\n (async () => {\n if (request.method === 'initialize') return { protocolVersion: request.params?.protocolVersion || '2024-11-05', capabilities: { tools: {} }, serverInfo: { name: 'codex-background', version: '0.5.0' }, instructions: `Codex only. Delegate through a registered relay with one pending delegate_run call. No sleep/status/log polling or intermediate progress. An interrupted wait can reattach by runId; only delegate_abort stops a job. Keep the outer host call pending, review opaque resultText, rerun gates and land through the selected delegate skill. Write the brief to ${artifactRoot}/briefs/\u003crunId>.txt (or anywhere inside an approved workspace or artifact root) and use ${artifactRoot}/runs/\u003crunId> as outputDirectory.` };\n if (request.method === 'ping') return {};\n if (request.method === 'tools/list') return { tools };\n if (request.method === 'tools/call') {\n try { return await callTool(request.params?.name, request.params?.arguments); }\n catch (error) { return { content: [{ type: 'text', text: error.message }], isError: true }; }\n }\n throw Error('Unknown method');\n })().then(result => { if (!cancelled.has(request.id)) send({ jsonrpc: '2.0', id: request.id, result }); }, error => { if (!cancelled.has(request.id)) send({ jsonrpc: '2.0', id: request.id, error: { code: -32601, message: error.message } }); }).finally(() => { active.delete(request.id); cancelled.delete(request.id); });\n });\n let closing;\n function shutdown() {\n closing ??= Promise.allSettled([...jobs.values()].map(async job => { await stop(job, 'aborted'); await job.done; })).then(() => { lines.close(); });\n return closing;\n }\n lines.once('close', () => { transportOpen = false; shutdown().catch(() => {}); });\n output.once('error', () => { transportOpen = false; shutdown().catch(() => {}); });\n for (const signal of ['SIGINT', 'SIGTERM']) process.once(signal, () => { shutdown().finally(() => { process.exitCode = 128; }); });\n return { shutdown };\n}\n\nif (process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {\n try { startServer(); } catch (error) { process.stderr.write(`${error.message}\\nTo configure codex-background, run: node \"${fileURLToPath(new URL('./bootstrap.mjs', import.meta.url))}\"\\n`); process.exitCode = 1; }\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":20931,"content_sha256":"53d7ff8f7d100f71139765d717ca45de5448213aa63cf471d54a41bc3968c2c8"},{"filename":"scripts/server.test.mjs","content":"import assert from 'node:assert/strict';\nimport { test } from 'node:test';\nimport { spawn } from 'node:child_process';\nimport { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';\nimport { tmpdir } from 'node:os';\nimport { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { createInterface } from 'node:readline';\nimport { setTimeout as delay } from 'node:timers/promises';\n\nconst SERVER = fileURLToPath(new URL('./server.mjs', import.meta.url));\nconst fixture = String.raw`import { spawn } from 'node:child_process';\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { setTimeout as delay } from 'node:timers/promises';\nconst argv = process.argv.slice(2);\nconst get = flag => argv[argv.indexOf(flag) + 1];\nconst spec = JSON.parse(readFileSync(get('--brief'), 'utf8'));\nif (spec.delayOutput) await delay(spec.delayOutput);\nconst out = get('--out-dir'); mkdirSync(out, { recursive: true });\nwriteFileSync(join(out, 'received.json'), JSON.stringify(argv));\nfunction result(code = 0) {\n const text = spec.raw ?? JSON.stringify({ finalMessage: 'report\\nexact', threadId: 'Opaque:Thread/9', artifacts: { custom: true }, status: code ? 'timeout' : 'completed' }, null, 2);\n writeFileSync(join(out, 'result.json'), spec.binary ? Buffer.from([255, 0, 254]) : text);\n process.exit(code);\n}\nif (spec.mode === 'usage') process.exit(2);\nif (spec.mode === 'missing') process.exit(0);\nif (spec.earlyResult) writeFileSync(join(out, 'result.json'), 'early opaque report');\nif (spec.mode === 'orphan') {\n const ready = join(out, 'child-ready');\n const program = \"require('node:fs').writeFileSync(process.argv[1],'ready');\" + (spec.childLifetime ? 'setTimeout(()=>{},' + spec.childLifetime + ')' : \"process.on('SIGTERM',()=>{});setInterval(()=>{},1000)\");\n const child = spawn(process.execPath, ['-e', program, ready], { stdio: 'ignore', windowsHide: true, detached: true });\n for (let i = 0; i \u003c 100 && !existsSync(ready); i++) await delay(50);\n if (!existsSync(ready)) throw Error('Orphan fixture failed to start');\n writeFileSync(join(out, 'child.pid'), String(child.pid));\n writeFileSync(join(out, 'result.json'), 'parent finished, owned descendant still alive');\n process.exit(0);\n}\nif (spec.mode === 'stuck') {\n const child = spawn(process.execPath, ['-e', \"process.on('SIGTERM',()=>{});setInterval(()=>{},1000)\"], { stdio: 'ignore', windowsHide: true });\n writeFileSync(join(out, 'child.pid'), String(child.pid));\n process.on('SIGTERM', () => process.exit(143));\n setInterval(()=>{},1000);\n} else {\n const noise = setInterval(()=>{process.stdout.write('progress stdout\\n');process.stderr.write('progress stderr\\n');}, 100);\n await delay(spec.delayMs ?? 100); clearInterval(noise); result(spec.code ?? 0);\n}\n`;\nfunction setup(suffix = '') {\n const root = mkdtempSync(join(tmpdir(), `codex-background-${suffix}`));\n const workspace = join(root, 'work'), artifacts = join(root, 'artifacts'), state = join(artifacts, 'state');\n mkdirSync(workspace); mkdirSync(artifacts);\n const relays = {};\n for (const key of ['agy', 'codex', 'zcode', 'cline', 'opencode']) {\n const scripts = join(root, key + '-delegate', 'scripts'); mkdirSync(scripts, { recursive: true });\n relays[key] = join(scripts, 'relay.mjs'); writeFileSync(relays[key], fixture);\n }\n const registryFile = join(root, 'registry.json');\n const registry = { schema: 'codex-background.registry.v1', hostToolTimeoutSeconds: 180, stateDirectory: state, workspaceRoots: [workspace], artifactRoots: [artifacts], relays };\n writeFileSync(registryFile, JSON.stringify(registry));\n return { root, workspace, artifacts, state, registryFile, registry };\n}\nfunction client(s) {\n const child = spawn(process.execPath, [SERVER], { env: { ...process.env, CODEX_BACKGROUND_REGISTRY: s.registryFile }, windowsHide: true, stdio: ['pipe', 'pipe', 'pipe'] });\n const pending = new Map(), messages = [], calls = []; let id = 0, stderr = '';\n child.stderr.on('data', chunk => { stderr += chunk; });\n const closed = new Promise(resolve => child.once('close', resolve));\n createInterface({ input: child.stdout }).on('line', line => {\n const message = JSON.parse(line); messages.push(message);\n if (pending.has(message.id)) { pending.get(message.id)(message); pending.delete(message.id); }\n });\n function request(method, params) {\n const requestId = ++id;\n if (method === 'tools/call') calls.push(params);\n const promise = new Promise(resolve => pending.set(requestId, resolve));\n child.stdin.write(JSON.stringify({ jsonrpc: '2.0', id: requestId, method, params }) + '\\n');\n return { id: requestId, promise };\n }\n const tool = (name, args) => request('tools/call', { name, arguments: args });\n function args(runId, spec = {}, overrides = {}) {\n const brief = join(s.workspace, runId + '.json'); writeFileSync(brief, JSON.stringify(spec));\n return { runId, implementer: 'agy', brief, workspace: s.workspace, outputDirectory: join(s.artifacts, runId), relayTimeoutSeconds: 90, relayArgs: [], ...overrides };\n }\n return { child, messages, calls, closed, request, tool, args,\n run: (runId, spec, overrides) => tool('delegate_run', args(runId, spec, overrides)),\n async close() { child.stdin.end(); await closed; assert.equal(stderr, '', 'no child stderr reaches MCP transport'); },\n };\n}\nfunction outcome(response) { assert.ok(response.result, JSON.stringify(response)); return JSON.parse(response.result.content[0].text); }\nasync function until(fn) { for (let i = 0; i \u003c 200; i++) { if (fn()) return; await delay(50); } assert.ok(fn(), 'fixture became ready'); }\nfunction alive(pid) {\n try { process.kill(pid, 0); } catch { return false; }\n try { return !/\\)\\s+Z\\s/.test(readFileSync('/proc/' + pid + '/stat', 'utf8')); } catch { return true; }\n}\nasync function clean(s, c) { await c.close(); rmSync(s.root, { recursive: true, force: true }); }\n\ntest('listing tools is read-only and dispatch creates missing state', { skip: !['linux', 'win32'].includes(process.platform), timeout: 15000 }, async () => {\n const s = setup(), c = client(s);\n try {\n const listed = await c.request('tools/list', {}).promise;\n assert.ok(listed.result.tools.some(tool => tool.name === 'delegate_run'));\n assert.equal(existsSync(s.state), false);\n const response = await c.run('first', {}).promise;\n assert.equal(outcome(response).adapterStatus, 'completed');\n assert.equal(existsSync(join(s.state, 'output-claims')), true);\n assert.equal(existsSync(join(s.state, 'first', 'outcome.json')), true);\n } finally { await clean(s, c); }\n});\n\ntest('Windows ownership preserves UTF-8 launch paths and relay arguments', { skip: process.platform !== 'win32', timeout: 15000 }, async () => {\n const s = setup('café مرحبا 漢字-'), c = client(s);\n try {\n const native = ['--label', 'résumé مرحبا 漢字'];\n const response = await c.run('unicode', {}, { relayArgs: native }).promise;\n const value = outcome(response);\n assert.equal(value.adapterStatus, 'completed');\n assert.equal(response.result.isError, false);\n const received = JSON.parse(readFileSync(join(value.outputDirectory, 'received.json'), 'utf8'));\n assert.deepEqual(received.slice(0, native.length), native);\n assert.equal(received[received.indexOf('--cd') + 1], s.workspace);\n assert.equal(received[received.indexOf('--out-dir') + 1], value.outputDirectory);\n } finally { await clean(s, c); }\n});\n\ntest('host tool timeout requires a dispatchable integer budget', { skip: !['linux', 'win32'].includes(process.platform), timeout: 10000 }, async () => {\n const s = setup();\n s.registry.hostToolTimeoutSeconds = 31;\n writeFileSync(s.registryFile, JSON.stringify(s.registry));\n const rejected = spawn(process.execPath, [SERVER], { env: { ...process.env, CODEX_BACKGROUND_REGISTRY: s.registryFile }, stdio: ['ignore', 'pipe', 'pipe'] });\n let stderr = '';\n rejected.stderr.on('data', chunk => { stderr += chunk; });\n const code = await new Promise(resolve => rejected.once('close', resolve));\n assert.equal(code, 1);\n assert.match(stderr, /Invalid host tool timeout/);\n s.registry.hostToolTimeoutSeconds = 32;\n writeFileSync(s.registryFile, JSON.stringify(s.registry));\n const c = client(s);\n try {\n const listed = await c.request('tools/list', {}).promise;\n const timeout = listed.result.tools.find(tool => tool.name === 'delegate_run').inputSchema.properties.relayTimeoutSeconds;\n assert.equal(timeout.minimum, 1);\n assert.equal(timeout.maximum, 1);\n } finally { await clean(s, c); }\n});\n\ntest('one pending MCP invocation stays quiet for more than sixty seconds', { timeout: 85000 }, async t => {\n const s = setup(), c = client(s);\n try {\n await c.request('initialize', { protocolVersion: '2024-11-05' }).promise;\n const listed = await c.request('tools/list', {}).promise;\n assert.deepEqual(listed.result.tools.map(tool => tool.name), ['delegate_run', 'delegate_wait', 'delegate_abort']);\n const started = Date.now();\n const native = ['--session', 'Opaque:Resume/ID', '--effort', 'high', '--fixture-values', '', 'space value', 'quote\"value', 'trailing\\\\', 'slash\\\\\"quote'];\n const call = c.run('long', { delayMs: 65000 }, { relayArgs: native });\n const response = await call.promise, value = outcome(response), elapsedMs = Date.now() - started;\n assert.ok(elapsedMs >= 65000); assert.equal(c.calls.length, 1); assert.equal(c.messages.length, 3);\n assert.equal(c.messages.filter(m => m.id === call.id).length, 1);\n assert.equal(c.messages.filter(m => !Object.hasOwn(m, 'id')).length, 0);\n assert.equal(value.adapterStatus, 'completed'); assert.equal(response.result.isError, false);\n assert.equal(value.resultText, readFileSync(value.resultPath, 'utf8'));\n assert.equal(JSON.parse(value.resultText).threadId, 'Opaque:Thread/9');\n assert.equal(JSON.parse(value.resultText).finalMessage, 'report\\nexact');\n assert.deepEqual(JSON.parse(readFileSync(join(value.outputDirectory, 'received.json'), 'utf8')).slice(0, native.length), native);\n assert.match(readFileSync(value.stdoutPath, 'utf8'), /progress stdout/);\n assert.match(readFileSync(value.stderrPath, 'utf8'), /progress stderr/);\n t.diagnostic(JSON.stringify({ elapsedMs, mcpToolInvocations: 1, intermediateMessages: 0, completionResponses: 1 }));\n } finally { await clean(s, c); }\n});\ntest('opaque result bytes and nonzero relay failures are preserved', async () => {\n const s = setup(), c = client(s);\n try {\n for (const [id, spec] of [['opaque', { raw: 'not JSON\\n unchanged' }], ['binary', { binary: true }], ['failed', { code: 1 }], ['timeout', { code: 124 }], ['usage', { mode: 'usage' }], ['missing', { mode: 'missing' }]]) {\n const response = await c.run(id, spec).promise, value = outcome(response);\n assert.equal(response.result.isError, ['failed', 'timeout', 'usage', 'missing'].includes(id), JSON.stringify(response) + readFileSync(value.stderrPath, 'utf8'));\n if (id === 'usage' || id === 'missing') { assert.equal(existsSync(value.resultPath), false); assert.equal(value.resultText, undefined); }\n else assert.deepEqual(Buffer.from(value.resultText, value.resultEncoding === 'base64' ? 'base64' : 'utf8'), readFileSync(value.resultPath));\n }\n } finally { await clean(s, c); }\n});\ntest('cancelling a wait preserves the job; reattach does not redispatch', async () => {\n const s = setup(), c = client(s);\n try {\n const call = c.run('cancel', { delayMs: 1000 });\n c.child.stdin.write(JSON.stringify({ jsonrpc: '2.0', method: 'notifications/cancelled', params: { requestId: call.id } }) + '\\n');\n assert.equal((await c.tool('delegate_run', { runId: 'cancel', implementer: 'agy', brief: join(s.workspace, 'cancel.json'), workspace: s.workspace, outputDirectory: join(s.artifacts, 'another'), relayTimeoutSeconds: 90 }).promise).result.isError, true);\n const value = outcome(await c.tool('delegate_wait', { runId: 'cancel' }).promise);\n assert.equal(value.adapterStatus, 'completed'); assert.equal(c.messages.filter(m => m.id === call.id).length, 0);\n assert.equal(JSON.parse(readFileSync(join(value.outputDirectory, 'received.json'), 'utf8')).filter(arg => arg === '--brief').length, 1);\n } finally { await clean(s, c); }\n});\ntest('explicit abort terminates the owned tree and preserves artifacts', async () => {\n const s = setup(), c = client(s);\n try {\n const call = c.run('abort', { mode: 'stuck' }); const pidFile = join(s.artifacts, 'abort', 'child.pid');\n await until(() => existsSync(pidFile)); const pid = Number(readFileSync(pidFile));\n const value = outcome(await c.tool('delegate_abort', { runId: 'abort' }).promise);\n assert.equal(value.adapterStatus, 'aborted'); assert.equal(outcome(await call.promise).adapterStatus, 'aborted');\n await until(() => !alive(pid)); assert.equal(existsSync(pidFile), true); assert.equal(value.resultText, undefined);\n } finally { await clean(s, c); }\n});\ntest('adapter guard bounds a relay that ignores its own timeout', { timeout: 23000 }, async () => {\n const s = setup(), c = client(s);\n try {\n const started = Date.now(); const value = outcome(await c.run('guard', { mode: 'stuck' }, { relayTimeoutSeconds: 1 }).promise);\n assert.equal(value.adapterStatus, 'adapter_timeout'); assert.ok(Date.now() - started >= 16000);\n await until(() => !alive(Number(readFileSync(join(value.outputDirectory, 'child.pid')))));\n } finally { await clean(s, c); }\n});\ntest('server shutdown aborts owned jobs and terminal outcomes survive restart', async () => {\n const s = setup(), c = client(s);\n try {\n c.run('shutdown', { mode: 'stuck' }); const pidFile = join(s.artifacts, 'shutdown', 'child.pid');\n await until(() => existsSync(pidFile)); const pid = Number(readFileSync(pidFile));\n c.child.stdout.destroy(); // A disconnected host must not crash cleanup with EPIPE.\n await c.close(); await until(() => !alive(pid));\n const next = client(s);\n try { assert.equal(outcome(await next.tool('delegate_wait', { runId: 'shutdown' }).promise).adapterStatus, 'aborted'); }\n finally { await next.close(); }\n } finally { await c.close(); rmSync(s.root, { recursive: true, force: true }); }\n});\ntest('restart recovers terminal reports and unresolved state never adopts a PID', async () => {\n const s = setup(), c = client(s);\n try {\n const original = outcome(await c.run('done', {}).promise); await c.close();\n mkdirSync(join(s.state, 'unresolved')); writeFileSync(join(s.state, 'unresolved', 'run.json'), JSON.stringify({ pid: process.pid }));\n const next = client(s);\n try {\n assert.deepEqual(outcome(await next.tool('delegate_wait', { runId: 'done' }).promise), original);\n assert.equal(outcome(await next.tool('delegate_wait', { runId: 'unresolved' }).promise).adapterStatus, 'recovery_required');\n assert.equal((await next.tool('delegate_abort', { runId: 'unresolved' }).promise).result.isError, true);\n assert.equal((await next.run('done', {}).promise).result.isError, true);\n assert.equal(alive(process.pid), true);\n } finally { await next.close(); }\n } finally { rmSync(s.root, { recursive: true, force: true }); }\n});\ntest('configured roots, host budget, executable injection and common overrides fail before dispatch', async () => {\n const s = setup(), c = client(s);\n try {\n const cases = [{ implementer: 'missing' }, { relayPath: SERVER }, { workspace: s.root }, { brief: SERVER }, { outputDirectory: join(s.state, 'wrong') }, { outputDirectory: join(s.root, 'outside') }, { relayTimeoutSeconds: 150 }, { relayTimeoutSeconds: 0 }, { relayArgs: ['--timeout=1s'] }, { relayArgs: ['--brief', SERVER] }, { relayArgs: ['--add-dir', s.root] }];\n for (let i = 0; i \u003c cases.length; i++) {\n assert.equal((await c.run('bad-' + i, {}, cases[i]).promise).result.isError, true);\n assert.equal(existsSync(join(s.state, 'bad-' + i)), false);\n }\n } finally { await clean(s, c); }\n});\ntest('exclusive output claims prevent concurrent delegation across server instances', async () => {\n const s = setup(), c = client(s), other = client(s);\n try {\n const call = c.run('first', { delayOutput: 1000 }); await until(() => existsSync(join(s.state, 'first', 'run.json')));\n assert.equal((await other.run('second', {}, { outputDirectory: join(s.artifacts, 'first') }).promise).result.isError, true);\n assert.equal(outcome(await call.promise).adapterStatus, 'completed');\n } finally { await other.close(); await clean(s, c); }\n});\ntest('registry rejects executables and mismatched implementer paths at startup', async () => {\n const s = setup();\n try {\n for (const relay of [process.execPath, s.registry.relays.codex]) {\n writeFileSync(s.registryFile, JSON.stringify({ ...s.registry, relays: { agy: relay } }));\n const child = spawn(process.execPath, [SERVER], { env: { ...process.env, CODEX_BACKGROUND_REGISTRY: s.registryFile }, stdio: ['ignore', 'ignore', 'pipe'], windowsHide: true });\n const code = await new Promise(resolve => child.once('close', resolve)); assert.equal(code, 1);\n }\n } finally { rmSync(s.root, { recursive: true, force: true }); }\n});\n\nfor (const action of ['abort', 'timeout', 'shutdown']) test(action + ' cleans descendants after the relay parent exits', { timeout: 26000 }, async () => {\n const s = setup(), c = client(s);\n const unrelated = spawn(process.execPath, ['-e', 'setInterval(()=>{},1000)'], { windowsHide: true, stdio: 'ignore' });\n try {\n const call = c.run('orphan', { mode: 'orphan' }, { relayTimeoutSeconds: action === 'timeout' ? 1 : 90 });\n const rootExit = join(s.state, 'orphan', 'relay-exit.json'), pidFile = join(s.artifacts, 'orphan', 'child.pid');\n await until(() => existsSync(rootExit));\n assert.equal(JSON.parse(readFileSync(rootExit)).exitCode, 0);\n const pid = Number(readFileSync(pidFile)); assert.equal(alive(pid), true);\n assert.equal(c.messages.filter(message => message.id === call.id).length, 0, 'parent exit and result file do not complete the owned tree');\n if (action === 'shutdown') await c.close();\n else {\n const response = action === 'abort' ? await c.tool('delegate_abort', { runId: 'orphan' }).promise : await call.promise;\n const value = outcome(response); assert.equal(value.adapterStatus, action === 'abort' ? 'aborted' : 'adapter_timeout');\n assert.equal(value.resultText, 'parent finished, owned descendant still alive');\n }\n await until(() => !alive(pid)); assert.equal(alive(unrelated.pid), true, 'unrelated process survives');\n if (action === 'shutdown') assert.equal(JSON.parse(readFileSync(join(s.state, 'orphan', 'outcome.json'))).adapterStatus, 'aborted');\n } finally { unrelated.kill(); await clean(s, c); }\n});\ntest('an early result never completes a live relay; cancellation at completion stays recoverable', async () => {\n const s = setup(), c = client(s);\n try {\n const call = c.run('early', { earlyResult: true, delayMs: 1000 });\n await until(() => existsSync(join(s.artifacts, 'early', 'result.json')));\n assert.equal(c.messages.length, 0);\n await until(() => existsSync(join(s.state, 'early', 'relay-exit.json')));\n c.child.stdin.write(JSON.stringify({ jsonrpc: '2.0', method: 'notifications/cancelled', params: { requestId: call.id } }) + '\\n');\n const value = outcome(await c.tool('delegate_wait', { runId: 'early' }).promise);\n assert.equal(value.adapterStatus, 'completed'); assert.equal(value.resultText, readFileSync(value.resultPath, 'utf8'));\n assert.ok(c.messages.filter(message => message.id === call.id).length \u003c= 1);\n } finally { await clean(s, c); }\n});\ntest('timeout near final descendant exit cannot report completion with a surviving process', { timeout: 26000 }, async () => {\n const s = setup(), c = client(s);\n try {\n const call = c.run('boundary', { mode: 'orphan', childLifetime: 13000 }, { relayTimeoutSeconds: 1 });\n const value = outcome(await call.promise);\n assert.ok(['completed', 'adapter_timeout'].includes(value.adapterStatus));\n const pid = Number(readFileSync(join(s.artifacts, 'boundary', 'child.pid'))); await until(() => !alive(pid));\n assert.equal(value.resultText, 'parent finished, owned descendant still alive');\n } finally { await clean(s, c); }\n});\ntest('shutdown racing relay completion persists exactly one valid terminal outcome', async () => {\n const s = setup(), c = client(s);\n try {\n c.run('closing', { delayMs: 100 }); await until(() => existsSync(join(s.artifacts, 'closing', 'received.json')));\n await c.close(); const value = JSON.parse(readFileSync(join(s.state, 'closing', 'outcome.json')));\n assert.ok(['completed', 'aborted'].includes(value.adapterStatus));\n const next = client(s);\n try { assert.deepEqual(outcome(await next.tool('delegate_wait', { runId: 'closing' }).promise), value); }\n finally { await next.close(); }\n } finally { await clean(s, c); }\n});\n\ntest('missing registry fails startup with actionable setup guidance', async () => {\n const child = spawn(process.execPath, [SERVER], { env: { ...process.env, CODEX_BACKGROUND_REGISTRY: '' }, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'] });\n let stdout = '', stderr = '';\n child.stdout.on('data', data => { stdout += data; }); child.stderr.on('data', data => { stderr += data; });\n const code = await new Promise(resolve => child.once('close', resolve));\n assert.equal(code, 1); assert.equal(stdout, ''); assert.match(stderr, /Missing CODEX_BACKGROUND_REGISTRY/);\n});\n\ntest('abort racing ownership startup stays terminal and cannot leave a live implementer', async () => {\n const s = setup(), c = client(s);\n try {\n const call = c.run('startup', { mode: 'stuck' });\n const value = outcome(await c.tool('delegate_abort', { runId: 'startup' }).promise);\n assert.equal(value.adapterStatus, 'aborted'); assert.equal(outcome(await call.promise).adapterStatus, 'aborted');\n const pidFile = join(s.artifacts, 'startup', 'child.pid');\n if (existsSync(pidFile)) await until(() => !alive(Number(readFileSync(pidFile))));\n assert.deepEqual(outcome(await c.tool('delegate_wait', { runId: 'startup' }).promise), value);\n } finally { await clean(s, c); }\n});\n\ntest('unexpected supervisor exit cleans detached descendants after relay exit', { timeout: 20000 }, async () => {\n const s = setup(), c = client(s);\n const unrelated = spawn(process.execPath, ['-e', 'setInterval(()=>{},1000)'], { windowsHide: true, stdio: 'ignore' });\n try {\n const call = c.run('lost-anchor', { mode: 'orphan' });\n await until(() => existsSync(join(s.state, 'lost-anchor', 'relay-exit.json')));\n const pid = Number(readFileSync(join(s.artifacts, 'lost-anchor', 'child.pid')));\n assert.equal(alive(pid), true);\n const anchor = JSON.parse(readFileSync(join(s.state, 'lost-anchor', 'supervisor.json'))).pid;\n process.kill(anchor, 'SIGKILL');\n const value = outcome(await call.promise);\n assert.equal(value.adapterStatus, 'failed');\n if (process.platform === 'linux') assert.equal(alive(pid), false, 'completion waits for native ownership closure');\n await until(() => !alive(pid));\n assert.equal(alive(unrelated.pid), true);\n assert.equal(value.resultText, 'parent finished, owned descendant still alive');\n assert.deepEqual(outcome(await c.tool('delegate_abort', { runId: 'lost-anchor' }).promise), value);\n } finally { unrelated.kill(); await clean(s, c); }\n});\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":23507,"content_sha256":"7a5fe59ff5d3281db4fe0f3564407e6a6e23b152c3f4807057fb8bde58c4e368"},{"filename":"scripts/supervisor.mjs","content":"#!/usr/bin/env node\n// Keep an ownership anchor alive until the registered relay and its descendants exit.\nimport { spawn, spawnSync } from 'node:child_process';\nimport { existsSync, readFileSync, renameSync, writeFileSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nconst spec = JSON.parse(readFileSync(process.argv[2], 'utf8'));\nconst exitPath = join(spec.runDirectory, 'relay-exit.json');\nconst outcomePath = join(spec.runDirectory, 'owner-outcome.json');\nfunction record(path, value) { writeFileSync(path + '.tmp', JSON.stringify(value), { mode: 0o600 }); renameSync(path + '.tmp', path); }\nrecord(join(spec.runDirectory, 'supervisor.json'), { pid: process.pid });\nif (process.platform === 'win32') {\n const systemRoot = process.env.SystemRoot || process.env.WINDIR;\n if (!systemRoot) throw Error('Windows system directory unavailable');\n const owner = spawn(join(systemRoot, 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe'), ['-NoLogo', '-NoProfile', '-NonInteractive', '-EncodedCommand', Buffer.from(readFileSync(new URL('./windows-job.ps1', import.meta.url), 'utf8'), 'utf16le').toString('base64')], { env: { ...process.env, CODEX_BACKGROUND_OWNER_SPEC: process.argv[2], CODEX_BACKGROUND_OWNER_HELPER: fileURLToPath(new URL('./windows-job.cs', import.meta.url)) }, windowsHide: true, stdio: 'inherit' });\n owner.once('error', error => { record(outcomePath, { error: error.message }); process.exitCode = 1; });\n owner.once('exit', (code, signal) => {\n record(outcomePath, { ownerExitCode: code, ownerSignal: signal, ...(!existsSync(exitPath) ? { error: 'Windows job owner could not initialize or finish; inspect stderr.log' } : {}) });\n process.exitCode = code === 0 || existsSync(exitPath) ? 0 : 1;\n });\n} else if (process.platform === 'linux') {\n let owner, stopping = false;\n // Reserve the group identity and forward a stop that races compilation/owner startup.\n process.on('SIGTERM', () => { stopping = true; owner?.kill('SIGTERM'); });\n const executable = join(spec.runDirectory, 'linux-owner');\n const compiled = spawnSync('/usr/bin/cc', ['-O2', '-Wall', '-Wextra', '-Werror', fileURLToPath(new URL('./linux-owner.c', import.meta.url)), '-o', executable], { encoding: 'utf8', timeout: 10000 });\n if (compiled.error || compiled.status !== 0) {\n record(outcomePath, { error: 'Linux ownership helper requires /usr/bin/cc: ' + (compiled.error?.message || compiled.stderr) });\n process.exitCode = 1;\n } else {\n owner = spawn(executable, [spec.runDirectory, String(process.pid), spec.node, spec.relayPath, ...spec.argv], { cwd: spec.workspace, stdio: 'inherit' });\n if (stopping) owner.kill('SIGTERM');\n owner.once('error', error => { record(outcomePath, { error: error.message }); process.exitCode = 1; });\n owner.once('exit', (code, signal) => {\n record(outcomePath, { ownerExitCode: code, ownerSignal: signal, ...(code !== 0 ? { error: 'Linux ownership helper failed; inspect stderr.log' } : {}) });\n process.exitCode = code === 0 ? 0 : 1;\n });\n }\n} else {\n record(outcomePath, { error: 'Safe process-tree ownership is supported on Windows and Linux only' });\n process.exitCode = 1;\n}\n","content_type":"text/javascript; charset=utf-8","language":"javascript","size":3208,"content_sha256":"fb2c7f0a69524e7815d050ea4bdf53bdd895ca7adb5fa176ef2f4579b7c422fc"},{"filename":"scripts/windows-job.cs","content":"// Kernel job ownership survives relay-parent exit. No PID discovery or adoption.\nusing System;\nusing System.ComponentModel;\nusing System.IO;\nusing System.Runtime.InteropServices;\nusing System.Text;\nusing System.Threading;\npublic static class DelegateJobOwner {\n [StructLayout(LayoutKind.Sequential)] struct IO_COUNTERS { public ulong ReadOperationCount, WriteOperationCount, OtherOperationCount, ReadTransferCount, WriteTransferCount, OtherTransferCount; }\n [StructLayout(LayoutKind.Sequential)] struct BASIC_LIMIT { public long PerProcessUserTimeLimit, PerJobUserTimeLimit; public uint LimitFlags; public UIntPtr MinimumWorkingSetSize, MaximumWorkingSetSize; public uint ActiveProcessLimit; public UIntPtr Affinity; public uint PriorityClass, SchedulingClass; }\n [StructLayout(LayoutKind.Sequential)] struct EXTENDED_LIMIT { public BASIC_LIMIT BasicLimitInformation; public IO_COUNTERS IoInfo; public UIntPtr ProcessMemoryLimit, JobMemoryLimit, PeakProcessMemoryUsed, PeakJobMemoryUsed; }\n [StructLayout(LayoutKind.Sequential)] struct ACCOUNTING { public long TotalUserTime, TotalKernelTime, ThisPeriodTotalUserTime, ThisPeriodTotalKernelTime; public uint TotalPageFaultCount, TotalProcesses, ActiveProcesses, TotalTerminatedProcesses; }\n [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] struct STARTUPINFO { public uint cb; public string reserved, desktop, title; public uint x, y, xSize, ySize, xCount, yCount, fill, flags; public ushort show, reservedSize; public IntPtr reservedBytes, stdin, stdout, stderr; }\n [StructLayout(LayoutKind.Sequential)] struct PROCESS_INFORMATION { public IntPtr process, thread; public uint processId, threadId; }\n [DllImport(\"kernel32.dll\", CharSet = CharSet.Unicode, SetLastError = true)] static extern IntPtr CreateJobObject(IntPtr attributes, string name);\n [DllImport(\"kernel32.dll\", SetLastError = true)] static extern bool SetInformationJobObject(IntPtr job, int info, ref EXTENDED_LIMIT limits, uint size);\n [DllImport(\"kernel32.dll\", SetLastError = true)] static extern bool QueryInformationJobObject(IntPtr job, int info, out ACCOUNTING counts, uint size, IntPtr length);\n [DllImport(\"kernel32.dll\", SetLastError = true)] static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);\n [DllImport(\"kernel32.dll\", CharSet = CharSet.Unicode, SetLastError = true)] static extern bool CreateProcess(string app, StringBuilder command, IntPtr processAttributes, IntPtr threadAttributes, bool inherit, uint flags, IntPtr environment, string cwd, ref STARTUPINFO startup, out PROCESS_INFORMATION process);\n [DllImport(\"kernel32.dll\", SetLastError = true)] static extern uint ResumeThread(IntPtr thread);\n [DllImport(\"kernel32.dll\", SetLastError = true)] static extern bool GetExitCodeProcess(IntPtr process, out uint code);\n [DllImport(\"kernel32.dll\")] static extern uint WaitForSingleObject(IntPtr handle, uint milliseconds);\n [DllImport(\"kernel32.dll\")] static extern IntPtr GetStdHandle(int id);\n [DllImport(\"kernel32.dll\")] static extern bool CloseHandle(IntPtr handle);\n [DllImport(\"kernel32.dll\")] static extern bool TerminateProcess(IntPtr process, uint code);\n static void Require(bool okay) { if (!okay) throw new Win32Exception(Marshal.GetLastWin32Error()); }\n static string Quote(string value) {\n var text = new StringBuilder(\"\\\"\"); int slashes = 0;\n foreach (char c in value) {\n if (c == '\\\\') { slashes++; continue; }\n text.Append('\\\\', c == '\"' ? slashes * 2 + 1 : slashes); text.Append(c); slashes = 0;\n }\n text.Append('\\\\', slashes * 2); return text.Append('\"').ToString();\n }\n public static int Run(string node, string[] args, string cwd, string exitPath) {\n IntPtr job = CreateJobObject(IntPtr.Zero, null); Require(job != IntPtr.Zero);\n PROCESS_INFORMATION process = new PROCESS_INFORMATION(); bool assigned = false;\n try {\n var limits = new EXTENDED_LIMIT(); limits.BasicLimitInformation.LimitFlags = 0x2000; // KILL_ON_JOB_CLOSE, no breakaway.\n Require(SetInformationJobObject(job, 9, ref limits, (uint)Marshal.SizeOf(typeof(EXTENDED_LIMIT))));\n var startup = new STARTUPINFO(); startup.cb = (uint)Marshal.SizeOf(typeof(STARTUPINFO)); startup.flags = 0x100;\n startup.stdin = GetStdHandle(-10); startup.stdout = GetStdHandle(-11); startup.stderr = GetStdHandle(-12);\n var command = new StringBuilder(Quote(node)); foreach (string arg in args) command.Append(\" \").Append(Quote(arg));\n Require(CreateProcess(node, command, IntPtr.Zero, IntPtr.Zero, true, 4 | 0x08000000, IntPtr.Zero, cwd, ref startup, out process));\n Require(AssignProcessToJobObject(job, process.process)); assigned = true;\n Require(ResumeThread(process.thread) != UInt32.MaxValue);\n uint code = 1; bool rootExited = false;\n for (;;) {\n uint waited = WaitForSingleObject(process.process, 100);\n if (waited == UInt32.MaxValue) throw new Win32Exception(Marshal.GetLastWin32Error());\n if (!rootExited && waited == 0) {\n Require(GetExitCodeProcess(process.process, out code)); rootExited = true;\n File.WriteAllText(exitPath + \".tmp\", \"{\\\"exitCode\\\":\" + code + \",\\\"signal\\\":null}\");\n File.Move(exitPath + \".tmp\", exitPath);\n }\n ACCOUNTING counts; Require(QueryInformationJobObject(job, 1, out counts, (uint)Marshal.SizeOf(typeof(ACCOUNTING)), IntPtr.Zero));\n if (rootExited && counts.ActiveProcesses == 0) return unchecked((int)code);\n if (rootExited) Thread.Sleep(100);\n }\n } finally {\n if (!assigned && process.process != IntPtr.Zero) TerminateProcess(process.process, 1);\n if (process.thread != IntPtr.Zero) CloseHandle(process.thread);\n if (process.process != IntPtr.Zero) CloseHandle(process.process);\n CloseHandle(job); // Kills members even if their original parent has already exited.\n }\n }\n}\n","content_type":"text/plain; charset=utf-8","language":"csharp","size":5855,"content_sha256":"fb141e79b68b8f90837b73480d574b9794efa5a5c5c29fa027050031b200edc7"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Codex background delegation","type":"text"}]},{"type":"paragraph","content":[{"text":"This support skill changes Codex's waiting boundary. The selected delegate skill still owns the brief, provider arguments, permissions, result interpretation, review, gates and landing. Claude's background Bash workflow stays unchanged. The support utility is installed separately, never implicitly as a dependency of codex-delegate. Details: ","type":"text"},{"text":"references/configuration.md","type":"text","marks":[{"type":"link","attrs":{"href":"references/configuration.md","title":null}}]},{"text":".","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"First use / setup","type":"text"}]},{"type":"paragraph","content":[{"text":"If the ","type":"text"},{"text":"delegate_run","type":"text","marks":[{"type":"code_inline"}]},{"text":" tool is not available, setup is incomplete. Tell the user that bootstrap will update ","type":"text"},{"text":"$CODEX_HOME/config.toml","type":"text","marks":[{"type":"code_inline"}]},{"text":" (default ","type":"text"},{"text":"~/.codex/config.toml","type":"text","marks":[{"type":"code_inline"}]},{"text":", backed up first) and write a registry of the installed ","type":"text"},{"text":"*-delegate","type":"text","marks":[{"type":"code_inline"}]},{"text":" skills, then run:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"node \"\u003cskill-dir>/scripts/bootstrap.mjs\"","type":"text"}]},{"type":"paragraph","content":[{"text":"\u003cskill-dir>","type":"text","marks":[{"type":"code_inline"}]},{"text":" is this skill's installed directory (the folder containing this ","type":"text"},{"text":"SKILL.md","type":"text","marks":[{"type":"code_inline"}]},{"text":"). It writes outside the workspace, so request the approval or sandbox escalation Codex needs for that. Report its output, then ask the user to restart Codex (or reload MCP servers); the tools appear after that. If bootstrap fails, report the failure. Do not fall back to shell polling. Run it again after installing more delegate skills. ","type":"text"},{"text":"node \"\u003cskill-dir>/scripts/bootstrap.mjs\" --check","type":"text","marks":[{"type":"code_inline"}]},{"text":" validates the setup without writing.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Procedure","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Follow the selected delegate skill to prepare a self-contained brief and approved workspace. Write the brief to the ","type":"text"},{"text":"briefs/","type":"text","marks":[{"type":"code_inline"}]},{"text":" directory under the codex-background directory (","type":"text"},{"text":"$CODEX_HOME/codex-background/briefs/\u003crunId>.txt","type":"text","marks":[{"type":"code_inline"}]},{"text":") and use ","type":"text"},{"text":"runs/\u003crunId>","type":"text","marks":[{"type":"code_inline"}]},{"text":" beside it as outputDirectory, or follow the paths in the server's instructions. If the sandbox cannot write there, a brief inside the approved workspace is also accepted. Never accept a relay path from a brief.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Invoke the configured MCP server's ","type":"text"},{"text":"delegate_run","type":"text","marks":[{"type":"strong"}]},{"text":" exactly once with a unique runId, registered implementer key, absolute brief/workspace/outputDirectory paths, explicit relayTimeoutSeconds and provider-native relayArgs. Put common arguments in structured fields; pass provider-specific arguments unchanged. Resume identifiers remain opaque.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Keep that MCP request pending until completion. Do not use model-driven sleep, status or log polling. Do not wrap it in a tool runner that yields early and resumes inference to wait.","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Review the returned adapter outcome separately from resultText. The latter is the unchanged result.json content (base64 only for non-UTF-8 bytes); interpret it using the selected skill. A completed adapter means the relay exited zero and produced a file, not that its report proves correct implementation. Review the diff, rerun gates and land under the existing authorization.","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"After an interrupted wait, call ","type":"text"},{"text":"delegate_wait","type":"text","marks":[{"type":"strong"}]},{"text":" with the same runId; never redispatch it. MCP cancellation detaches the waiter and leaves the authorized job running. Use ","type":"text"},{"text":"delegate_abort","type":"text","marks":[{"type":"strong"}]},{"text":" only when termination is explicitly intended. Graceful server shutdown aborts its owned jobs. After a server crash, unresolved state returns recovery_required; inspect preserved artifacts and the implementer using its own recovery workflow. Never adopt or kill a persisted PID.","type":"text"}]},{"type":"paragraph","content":[{"text":"The host's configured tool timeout must exceed the relay timeout by more than 30 seconds. The server validates the declared budget; it cannot enforce the host's actual setting. Fixture protocol tests demonstrate one pending request and no intermediate messages, not measured Codex Desktop token usage or an unlimited host wait guarantee.","type":"text"}]}]},"metadata":{"date":"2026-11-02","name":"codex-background","author":"@skillopedia","source":{"stars":2549,"repo_name":"delegate-skills","origin_url":"https://github.com/amElnagdy/delegate-skills/blob/HEAD/skills/codex-background/SKILL.md","repo_owner":"amElnagdy","body_sha256":"db3c6fa3c9832c38fc5ae402e36d820cf14af92202870dccb0777748c7946455","cluster_key":"ceec87cd215158db298b94980817a5541ff778c9c7a0f93bcc1f92e188690f9d","clean_bundle":{"format":"clean-skill-bundle-v1","source":"amElnagdy/delegate-skills/skills/codex-background/SKILL.md","text_bytes":136623,"source_commit":"3aa72d681a79e2a9d09bd9a316353003ae1cb4a7","skills_sh_rank":17069,"attachment_count":8,"text_attachments":8,"attachment_storage":"skill_attachments","binary_attachments":0},"cluster_size":1,"skill_md_path":"skills/codex-background/SKILL.md","import_metadata":{"date":"2026-11-02","author":"@skillopedia","version":"v1","category":"ai-agent-development","category_label":"AI"},"exact_dupes_collapsed_into_this":0},"version":"v1","category":"ai-agent-development","metadata":{"version":"0.5.0"},"import_tag":"skills-sh-top20k-2026-11","description":"Keep a Codex orchestrator's delegation to an installed delegate skill pending until its registered relay completes, without model-driven progress polling. Use with a selected implementer delegate skill when Codex is the orchestrator and the delegation should wait in the background; sets up its MCP server on first use.","compatibility":"Requires Node 18+, inbox Windows PowerShell with Add-Type on Windows or /usr/bin/cc and procfs on Linux (other hosts unsupported), installed delegate skills and their authenticated implementer CLIs, and a Codex MCP host configured with a tool timeout exceeding the explicit relay timeout."}},"renderedAt":1793665941982}

Codex background delegation This support skill changes Codex's waiting boundary. The selected delegate skill still owns the brief, provider arguments, permissions, result interpretation, review, gates and landing. Claude's background Bash workflow stays unchanged. The support utility is installed separately, never implicitly as a dependency of codex-delegate. Details: references/configuration.md. First use / setup If the tool is not available, setup is incomplete. Tell the user that bootstrap will update (default , backed up first) and write a registry of the installed skills, then run: is th…