Yeachan-Heo/oh-my-codex · error · Error

remove requires an interactive terminal; rerun with --force

Error message

remove requires an interactive terminal; rerun with --force in non-interactive environments

What it means

agent remove prompts for confirmation, which requires both stdin and stdout to be TTYs. In non-interactive environments (CI, pipes, scripts) without --force, this error is thrown instead of hanging on a prompt nobody can answer.

Source

Thrown at src/cli/agents.ts:208

    if (existsSync(path)) return path;
  }
  throw new Error(`agent not found: ${normalized}`);
}

async function confirmRemove(path: string): Promise<boolean> {
  const rl = createInterface({ input: process.stdin, output: process.stdout });
  try {
    const answer = (await rl.question(`Delete native agent ${path}? [y/N]: `)).trim().toLowerCase();
    return answer === 'y' || answer === 'yes';
  } finally {
    rl.close();
  }
}

function ensureInteractiveRemove(force: boolean): void {
  if (force) return;
  if (process.stdin.isTTY && process.stdout.isTTY) return;
  throw new Error('remove requires an interactive terminal; rerun with --force in non-interactive environments');
}

async function editNativeAgent(
  name: string,
  options: { cwd?: string; scope?: AgentScope; editor?: string } = {},
): Promise<string> {
  const path = resolveExistingAgentPath(name, options);
  const editor = options.editor ?? process.env.EDITOR ?? process.env.VISUAL ?? 'vi';
  const result = spawnSync(editor, [path], {
    stdio: 'inherit',
    shell: true,
    env: process.env,
  });
  if (result.status !== 0) {
    throw new Error(`editor exited with status ${result.status ?? 'unknown'}`);
  }
  return path;
}

View on GitHub (pinned to 3ad79a8a6f)

Solutions

  1. Add --force to skip confirmation in non-interactive contexts
  2. Allocate a TTY (ssh -t, docker run -it) when interactive confirmation is desired
  3. Pipe scripts should always use --force

Example fix

# before (CI script)
omx agent remove reviewer

# after
omx agent remove reviewer --force
Defensive patterns

Strategy: validation

Validate before calling

const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY);
if (!interactive && !force) {
  // either pass force:true or abort with a clear message before calling
  force = true;
}

Type guard

const isInteractive = (): boolean => Boolean(process.stdin.isTTY && process.stdout.isTTY);

Try / catch

try { await removeNativeAgent(name, { force: !isInteractive() }); } catch (e) { if (/interactive terminal/.test(String(e))) throw new Error('rerun with --force in CI'); throw e; }

Prevention

When it happens

Trigger: Running `omx agent remove x` in CI, via ssh -c, inside a pipe (`echo | omx agent remove x`), or from any non-TTY context.

Common situations: CI cleanup steps, docker containers without TTY, automation scripts, cron jobs.

Related errors


AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27). Data as JSON: /api/errors/499f76b5b8c318ac. Report an issue: GitHub.