{"record":{"id":"ea00b26b93f2010c","repo":"pbakaus/impeccable","slug":"no-live-copy-edit-ai-runner-is-available-ea00b2","errorCode":null,"errorMessage":"No live copy-edit AI runner is available.","messagePattern":"No live copy-edit AI runner is available\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"skill/scripts/live-copy-edit-agent.mjs","lineNumber":114,"sourceCode":"\nexport async function runCopyEditBatchAgent(batch, opts = {}) {\n  const cwd = opts.cwd || process.cwd();\n  const env = opts.env || process.env;\n  const provider = opts.provider || chooseCopyEditAgent({ env, chatAvailable: opts.chatAvailable });\n  if (provider === 'mock') {\n    const delayMs = Number(env.IMPECCABLE_LIVE_COPY_AGENT_MOCK_DELAY_MS || 0);\n    if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));\n    return mockBatchResult(batch, env, cwd);\n  }\n  if (provider === 'chat') {\n    if (typeof opts.applyBatchToSource !== 'function') {\n      throw new Error('chat provider requires applyBatchToSource callback');\n    }\n    const raw = await opts.applyBatchToSource(batch, { repair: batch?.repair || null });\n    return normalizeBatchResult(raw || {});\n  }\n  if (!provider) {\n    throw new Error(describeNoProviderError({ env }));\n  }\n\n  const prompt = buildCopyEditBatchPrompt(batch, { cwd });\n  const outDir = opts.outDir || fs.mkdtempSync(path.join(os.tmpdir(), 'impeccable-copy-batch-'));\n  fs.mkdirSync(outDir, { recursive: true });\n  const resultPath = path.join(outDir, 'result.json');\n  const logPath = path.join(outDir, 'agent.log');\n\n  if (provider === 'codex') {\n    await runCodex(prompt, { cwd, env, resultPath, logPath, timeoutMs: opts.timeoutMs });\n  } else if (provider === 'claude') {\n    await runClaude(prompt, { cwd, env, resultPath, logPath, timeoutMs: opts.timeoutMs });\n  } else {\n    throw new Error(`Unsupported live copy-edit AI runner: ${provider}`);\n  }\n\n  const output = fs.existsSync(resultPath) ? fs.readFileSync(resultPath, 'utf-8') : '';\n  const parsed = parseCopyEditBatchResult(output);","sourceCodeStart":96,"sourceCodeEnd":132,"githubUrl":"https://github.com/pbakaus/impeccable/blob/d14711ae3d1a1dd62dee61a358d27f107c51ccd0/skill/scripts/live-copy-edit-agent.mjs#L96-L132","documentation":"Thrown by runCopyEditBatchAgent() when chooseCopyEditAgent() returns a falsy provider, meaning no live copy-edit runner could be selected. The full message comes from describeNoProviderError() and itemizes the state of the Claude CLI, Codex CLI, and the chat session, plus the IMPECCABLE_LIVE_COPY_AGENT setting. Provider is null when mode is off/none, when a named mode's tool is missing (claude/codex not installed or not authed), or auto-mode found nothing authed.","triggerScenarios":"Running Apply in a live copy-edit flow with IMPECCABLE_LIVE_COPY_AGENT unset (auto) while neither `claude` nor `codex` is installed/authed and no Impeccable chat session is polling; or setting IMPECCABLE_LIVE_COPY_AGENT=claude without the claude CLI; or =off/none explicitly.","commonSituations":"First run on a machine without the CLIs installed; macOS where `claude /login` Keychain creds are unreachable from a no-TTY subprocess; Codex not logged in; running tests without setting IMPECCABLE_LIVE_COPY_AGENT=mock.","solutions":["Set IMPECCABLE_LIVE_COPY_AGENT=mock for local/tests to use the deterministic mock runner.","Install and authenticate a real runner: `claude setup-token` then export CLAUDE_CODE_OAUTH_TOKEN, or export ANTHROPIC_API_KEY, or `codex login`.","Start an Impeccable live chat session so the chat provider becomes available, or set IMPECCABLE_LIVE_COPY_AGENT=chat explicitly.","Read the bullet list in the error text — it names exactly which runner is missing/unauthed for your environment."],"exampleFix":"// before\nIMPECCABLE_LIVE_COPY_AGENT=auto  # nothing authed\n// after (tests/dev)\nexport IMPECCABLE_LIVE_COPY_AGENT=mock","handlingStrategy":"validation","validationCode":"import { chooseCopyEditAgent } from './live-copy-edit-agent.mjs';\nconst provider = chooseCopyEditAgent({ env, chatAvailable });\nif (!provider) {\n  throw new Error('No copy-edit runner; set IMPECCABLE_LIVE_COPY_AGENT=mock or install/auth claude|codex');\n}","typeGuard":"function copyEditProviderAvailable(env, chatAvailable) {\n  return Boolean(chooseCopyEditAgent({ env, chatAvailable }));\n}","tryCatchPattern":null,"preventionTips":["Set IMPECCABLE_LIVE_COPY_AGENT=mock in dev/CI.","Run `claude setup-token` / `codex login` before relying on a real runner.","Start an Impeccable live chat session to enable the chat provider."],"tags":["live-copy-edit","provider","environment","agent-runner"],"backgroundTag":null,"analyzedSha":"d14711ae3d1a1dd62dee61a358d27f107c51ccd0","analyzedAt":"2026-08-13T00:52:25.771Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}