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
- Add --force to skip confirmation in non-interactive contexts
- Allocate a TTY (ssh -t, docker run -it) when interactive confirmation is desired
- 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
- Always pass --force in CI/scripts/docker
- Gate interactive prompts on isTTY checks in your own tooling
- Use ssh -t or docker -it when you genuinely need the prompt
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
- agent name must not be empty
- invalid agent name: ${name}
- \"${trimmed}\" is reserved by Codex built-in agents
- Expected --scope user|project
- agent already exists: ${path}
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/499f76b5b8c318ac.
Report an issue: GitHub.