@arcqdev/deadpool-runner
v0.2.0
Published
Self-healing command runner for CLI and SDK usage with ACP-powered fixes.
Maintainers
Readme
@arcqdev/deadpool-runner
Install
Use it as a local dependency for SDK or repo-level CLI usage:
vp add @arcqdev/deadpool-runnerOr install the CLI globally:
npm i -g @arcqdev/deadpool-runnerCLI Quick Start
Run a command directly:
dpr -- vp testPass context and a retry budget:
dpr --retries 3 --prompt "Vite+ monorepo, fix root causes" -- vp checkOr define a config file:
import { defineDeadpoolRunnerConfig } from "@arcqdev/deadpool-runner";
export default defineDeadpoolRunnerConfig({
command: ["vp", "test"],
retries: 5,
initialPrompt: "Fix the actual regression, not the assertion.",
acpClient: {
name: "codex",
model: "gpt-5.4",
fullAuto: true,
},
critique: {
enabled: true,
repeatFailureLimit: 1,
failureConditions: {
instructions: "Exit early for blockers the repo cannot repair on its own.",
conditions: [
{
id: "third-party-api-down",
description: "A required external API is unavailable or returning a sustained outage.",
stop: true,
output: {
code: "third_party_api_down",
retryable: false,
},
},
],
},
acpClient: {
sandbox: "read-only",
fullAuto: false,
},
},
});Then run:
dprSDK Quick Start
The package now exposes a first-class SDK entrypoint for running repairs programmatically:
import { runDeadpoolRunner } from "@arcqdev/deadpool-runner";
const result = await runDeadpoolRunner({
cwd: process.cwd(),
command: ["vp", "test"],
retries: 2,
initialPrompt: "TypeScript package. Keep fixes minimal and rerunnable.",
acpClient: {
name: "codex",
model: "gpt-5.4",
sandbox: "workspace-write",
},
critique: {
failureConditions: {
instructions: "Classify external dependency outages before spending more repair attempts.",
conditions: [
{
id: "third-party-api-down",
description: "A required external API is unavailable.",
stop: true,
output: {
code: "third_party_api_down",
retryable: false,
},
},
],
},
},
});
if (result.failureCondition) {
console.error("Terminal failure condition:", result.failureCondition.output);
}
if (result.code !== 0) {
throw new Error(`Repair loop failed with exit code ${result.code}`);
}For advanced integrations, the lower-level runner is still available:
import { createRunner } from "@arcqdev/deadpool-runner";
const runner = createRunner({
runCommand: async (command, options) => {
return {
code: 0,
signal: null,
stdout: `stubbed ${String(command)}`,
stderr: "",
combinedOutput: `stubbed ${String(command)}`,
};
},
});
await runner.run({
command: ["vp", "test"],
});Register a Custom ACP Client
Deadpool Runner is SDK-friendly because the ACP client registry is public:
import {
registerACPClient,
runDeadpoolRunner,
type ACPClient,
type ACPClientConfig,
} from "@arcqdev/deadpool-runner";
registerACPClient(
"internal-agent",
(config?: ACPClientConfig): ACPClient => ({
name: "internal-agent",
async fixFailure(context) {
console.log("Repairing", context.command, "with", config?.model ?? "default model");
return { summary: "Applied internal-agent repair." };
},
}),
);
await runDeadpoolRunner({
command: ["vp", "test"],
acpClient: {
name: "internal-agent",
model: "my-internal-model",
},
});Failure Conditions
By default, Deadpool Runner does not ask critique to classify named terminal conditions. If you set critique.failureConditions, the critique step gets a list of allowed condition IDs, descriptions, and optional structured outputs.
idis the stable identifier the critique model can return.descriptiontells critique when that condition applies.stop: trueexits the loop immediately when that condition matches.outputis copied intoresult.failureCondition.outputfor SDK consumers and printed by the CLI when a match stops the run.
Example SDK config:
import { runDeadpoolRunner } from "@arcqdev/deadpool-runner";
const result = await runDeadpoolRunner({
command: ["vp", "test"],
critique: {
failureConditions: {
instructions: "Only match a condition when the command output clearly supports it.",
conditions: [
{
id: "third-party-api-down",
description: "A required hosted API is down or returning a sustained outage.",
stop: true,
output: {
code: "third_party_api_down",
retryable: false,
notify: "platform-team",
},
},
{
id: "missing-secret",
description: "The command is blocked by a missing runtime secret or token.",
stop: true,
output: {
code: "missing_secret",
retryable: false,
},
},
],
},
},
});
if (result.failureCondition) {
console.error(result.failureCondition.id, result.failureCondition.output);
}Example CLI usage:
dpr \
--failure-conditions-json '{"conditions":[{"id":"third-party-api-down","description":"A required hosted API is down.","stop":true,"output":{"code":"third_party_api_down","retryable":false}}]}' \
-- vp testOr load them from a separate file:
dpr --failure-conditions-file ./failure-conditions.json -- vp testThe failure conditions file can export either the failureConditions object directly or a larger config object with critique.failureConditions.
CLI Flags
| Flag | What it does |
| ---------------------------------- | ------------------------------------------------------- |
| --retries <n> | Max fix attempts after the initial failure |
| --prompt <text> | Extra repo context for the fixer |
| --cwd, --repo <path> | Target a different repo or working directory |
| --client <name> | ACP client name, currently codex by default |
| --model <name> | Model override for the ACP client |
| --sandbox <mode> | read-only, workspace-write, or danger-full-access |
| --max-output-chars <n> | Limit the trailing error text sent to the fixer |
| --verbose, -v | Stream ACP client logs during fix attempts |
| --config <path> | Explicit config file path |
| --failure-conditions-json <json> | Inline JSON for critique.failureConditions |
| --failure-conditions-file <path> | Load critique.failureConditions from a file |
Repeat-Failure Critique
Deadpool Runner keeps the normal retry budget and adds an optional loop guard for repeated failures.
retriescaps the total number of fixer attempts.critique.repeatFailureLimitstops early when the same failure repeats consecutively.critique.failureConditionsoptionally lets critique classify named terminal failures.- The default repeat-failure limit is
1. - Critique defaults to the main ACP client unless you override it.
- Critique runs read-only by default.
Environment overrides:
DEADPOOL_RUNNER_REPEAT_FAILURE_LIMITDEADPOOL_RUNNER_DISABLE_CRITIQUE=1DEADPOOL_RUNNER_CRITIQUE_CLIENTDEADPOOL_RUNNER_CRITIQUE_MODELDEADPOOL_RUNNER_CRITIQUE_COLORDEADPOOL_RUNNER_CRITIQUE_SANDBOXDEADPOOL_RUNNER_CRITIQUE_BYPASS_SANDBOXDEADPOOL_RUNNER_CRITIQUE_FULL_AUTODEADPOOL_RUNNER_CRITIQUE_EXECUTABLE
Package Exports
The published package includes typed ESM exports for both direct use and tooling compatibility:
@arcqdev/deadpool-runner@arcqdev/deadpool-runner/cli@arcqdev/deadpool-runner/bin
How It Works
- Run the wrapped command.
- If it fails, the ACP client gets the repo context and captured error output.
- Deadpool Runner writes per-run artifacts under
~/.deadpool-runner/runs/. - The command reruns until it passes, repeats the same failure too many times, or exhausts the retry budget.
Development
This repo uses Vite+.
./node_modules/.bin/vp check
./node_modules/.bin/vp test
./node_modules/.bin/vp run buildGitHub Pages is deployed from the committed docs/ directory through the workflow in .github/workflows/ci-pages.yml.
License
MIT
