pbakaus/impeccable · error · Error

No live copy-edit AI runner is available.

Error message

No live copy-edit AI runner is available.

What it means

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.

Source

Thrown at skill/scripts/live-copy-edit-agent.mjs:114

export async function runCopyEditBatchAgent(batch, opts = {}) {
  const cwd = opts.cwd || process.cwd();
  const env = opts.env || process.env;
  const provider = opts.provider || chooseCopyEditAgent({ env, chatAvailable: opts.chatAvailable });
  if (provider === 'mock') {
    const delayMs = Number(env.IMPECCABLE_LIVE_COPY_AGENT_MOCK_DELAY_MS || 0);
    if (delayMs > 0) await new Promise((resolve) => setTimeout(resolve, delayMs));
    return mockBatchResult(batch, env, cwd);
  }
  if (provider === 'chat') {
    if (typeof opts.applyBatchToSource !== 'function') {
      throw new Error('chat provider requires applyBatchToSource callback');
    }
    const raw = await opts.applyBatchToSource(batch, { repair: batch?.repair || null });
    return normalizeBatchResult(raw || {});
  }
  if (!provider) {
    throw new Error(describeNoProviderError({ env }));
  }

  const prompt = buildCopyEditBatchPrompt(batch, { cwd });
  const outDir = opts.outDir || fs.mkdtempSync(path.join(os.tmpdir(), 'impeccable-copy-batch-'));
  fs.mkdirSync(outDir, { recursive: true });
  const resultPath = path.join(outDir, 'result.json');
  const logPath = path.join(outDir, 'agent.log');

  if (provider === 'codex') {
    await runCodex(prompt, { cwd, env, resultPath, logPath, timeoutMs: opts.timeoutMs });
  } else if (provider === 'claude') {
    await runClaude(prompt, { cwd, env, resultPath, logPath, timeoutMs: opts.timeoutMs });
  } else {
    throw new Error(`Unsupported live copy-edit AI runner: ${provider}`);
  }

  const output = fs.existsSync(resultPath) ? fs.readFileSync(resultPath, 'utf-8') : '';
  const parsed = parseCopyEditBatchResult(output);

View on GitHub (pinned to d14711ae3d)

Solutions

  1. Set IMPECCABLE_LIVE_COPY_AGENT=mock for local/tests to use the deterministic mock runner.
  2. Install and authenticate a real runner: `claude setup-token` then export CLAUDE_CODE_OAUTH_TOKEN, or export ANTHROPIC_API_KEY, or `codex login`.
  3. Start an Impeccable live chat session so the chat provider becomes available, or set IMPECCABLE_LIVE_COPY_AGENT=chat explicitly.
  4. Read the bullet list in the error text — it names exactly which runner is missing/unauthed for your environment.

Example fix

// before
IMPECCABLE_LIVE_COPY_AGENT=auto  # nothing authed
// after (tests/dev)
export IMPECCABLE_LIVE_COPY_AGENT=mock
Defensive patterns

Strategy: validation

Validate before calling

import { chooseCopyEditAgent } from './live-copy-edit-agent.mjs';
const provider = chooseCopyEditAgent({ env, chatAvailable });
if (!provider) {
  throw new Error('No copy-edit runner; set IMPECCABLE_LIVE_COPY_AGENT=mock or install/auth claude|codex');
}

Type guard

function copyEditProviderAvailable(env, chatAvailable) {
  return Boolean(chooseCopyEditAgent({ env, chatAvailable }));
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of pbakaus/impeccable@d14711ae3d (2026-08-13). Data as JSON: /api/errors/ea00b26b93f2010c. Report an issue: GitHub.