# runCommand vs runCommandChecked in OpenAI Codex Plugin: Key Differences Explained

> Understand the crucial differences between runCommand and runCommandChecked in the OpenAI Codex plugin. Learn how each handles shell command execution and error management for efficient development.

- Repository: [OpenAI/codex-plugin-cc](https://github.com/openai/codex-plugin-cc)
- Tags: deep-dive
- Published: 2026-07-11

---

**runCommand returns a result object regardless of exit status, while runCommandChecked throws an exception on failure, providing automatic error handling for shell commands in the Codex plugin.**

The OpenAI Codex plugin (`openai/codex-plugin-cc`) provides two distinct Node.js utilities for executing shell commands synchronously. Understanding the difference between **runCommand** and **runCommandChecked** is essential for writing robust plugin scripts, as one returns raw results for manual inspection while the other enforces success through exceptions.

## Source Location and Implementation

Both functions are defined in `plugins/codex/scripts/lib/process.mjs` and serve as thin wrappers around Node.js's `spawnSync`. The `runCommand` function acts as the low-level primitive, while `runCommandChecked` builds upon it to add automatic error validation.

### runCommand Implementation

The `runCommand` function (lines 4-25) always returns a plain result object containing the command output and exit status:

```js
export function runCommand(command, args = [], options = {}) {
  // ... spawns the process synchronously
  return { command, args, status, signal, stdout, stderr, error };
}

```

### runCommandChecked Implementation

The `runCommandChecked` function (lines 27-36) delegates to `runCommand` then validates the result:

```js
export function runCommandChecked(command, args = [], options = {}) {
  const result = runCommand(command, args, options);
  if (result.error) throw result.error;
  if (result.status !== 0) throw new Error(formatCommandFailure(result));
  return result;
}

```

## Core Differences Between runCommand and runCommandChecked

| Feature | `runCommand` | `runCommandChecked` |
|---------|--------------|---------------------|
| **Return behavior** | Always returns result object `{ command, args, status, signal, stdout, stderr, error }` | Returns result object only on success |
| **Error handling** | Caller must manually check `result.error` or `result.status !== 0` | Automatically throws on spawn errors or non-zero exit codes |
| **Typical use case** | Commands where non-zero exits are expected or custom diagnostics are needed | Commands that must succeed for the script to continue |

## Real-World Usage in git.mjs

The `plugins/codex/scripts/lib/git.mjs` file demonstrates practical application of both approaches. At line 13, `runCommand` handles `git rev-parse` where the caller needs to inspect raw output regardless of success:

```js
const result = runCommand("git", args, { cwd, ... });

```

At line 17, `runCommandChecked` wraps `git fetch` to ensure the operation succeeds or throws immediately:

```js
runCommandChecked("git", args, { cwd, ... });

```

## Practical Code Examples

### Manual Error Handling with runCommand

Use `runCommand` when you need to parse output or handle specific exit codes gracefully:

```js
import { runCommand } from "./process.mjs";

const result = runCommand("git", ["rev-parse", "HEAD"], { cwd: repoRoot });

if (result.error) {
  console.error("Git failed to start:", result.error);
} else if (result.status !== 0) {
  console.warn("Git exited with non-zero code:", result.stderr);
} else {
  console.log("Current commit hash:", result.stdout.trim());
}

```

### Automatic Error Propagation with runCommandChecked

Use `runCommandChecked` for "fire-and-forget" operations that should abort execution on failure:

```js
import { runCommandChecked } from "./process.mjs";

try {
  const { stdout } = runCommandChecked("git", ["fetch"], { cwd: repoRoot });
  console.log("Fetch succeeded:", stdout);
} catch (e) {
  console.error("Failed to fetch:", e.message);
}

```

### Combining Both Approaches

Higher-level helpers can mix both functions to handle optional and mandatory operations:

```js
import { runCommand, runCommandChecked } from "./process.mjs";

export function ensureRemoteExists(name, url, cwd) {
  // Check if remote exists - non-fatal
  const list = runCommand("git", ["remote", "-v"], { cwd });
  if (list.stdout.includes(name)) return;

  // Add remote - must succeed
  runCommandChecked("git", ["remote", "add", name, url], { cwd });
}

```

## Summary

- **runCommand** in `plugins/codex/scripts/lib/process.mjs` returns a complete result object for every invocation, placing error-handling responsibility on the caller to inspect `result.status` or `result.error`.
- **runCommandChecked** wraps `runCommand` to provide automatic exception throwing when commands fail to spawn or exit with non-zero status codes, using `formatCommandFailure` for descriptive messages.
- Choose **runCommand** when you need to inspect exit codes, parse error output, or handle expected failures gracefully according to the OpenAI Codex plugin source code.
- Choose **runCommandChecked** when a command must succeed for the script to continue, keeping calling code clean through exception handling rather than manual status checks.

## Frequently Asked Questions

### What does runCommand return when a command fails?

When a command fails, `runCommand` still returns a result object containing the `error` property (if spawn failed) or a non-zero `status` code. The function never throws, allowing callers to inspect `result.status !== 0` or `result.error` to determine failure type and handle it appropriately.

### How does runCommandChecked format error messages?

`runCommandChecked` uses the internal `formatCommandFailure` helper function to build descriptive error messages when commands exit with non-zero status. For spawn failures, it throws the original `result.error` directly rather than wrapping it in a new Error instance.

### Can I disable the automatic throwing in runCommandChecked?

No, `runCommandChecked` is designed specifically to always throw on failure. If you need conditional error handling or need to inspect non-zero exit codes, use `runCommand` instead and implement custom logic based on the returned `status` and `stderr` properties according to the implementation in `process.mjs`.

### Are these functions used elsewhere in the OpenAI Codex plugin?

Yes, beyond `plugins/codex/scripts/lib/git.mjs`, these utilities appear throughout the plugin codebase wherever shell command execution is required, including test suites like `tests/process.test.mjs` which verify both the raw result handling and error propagation behaviors.