EveryInc/compound-engineering-plugin · error · Error

Could not verify local Codex development mode (reported ${st

Error message

Could not verify local Codex development mode (reported ${status.mode})

What it means

`switchToLocal()` links your skills directory into Codex and then re-runs `inspectCodexDevStatus` to prove the switch actually took. If the post-switch status reports any mode other than `"local"` (e.g. `"mixed"`, `"drifted"`, `"remote"`, `"absent"`), the switch failed and this error is thrown; the previously active collection is restored before rethrowing.

Source

Thrown at src/dev/codex-dev.ts:569

  )
}

export async function switchToLocal(
  context: CodexDevContext,
  runner: CommandRunner = new BunCommandRunner(),
): Promise<CodexDevStatus> {
  const previous = await inspectLocalCollection(context)
  if (previous.kind !== "absent" && previous.kind !== "valid") {
    throw new Error(`Cannot switch to local mode while the local collection is ${previous.kind}`)
  }
  const activatedTarget = await fs.realpath(context.skillsRoot)
  await activateLocalCollection(context)
  try {
    const plugins = await listCompoundEngineeringPlugins(context, runner)
    await removeLocalPluginConflicts(context, runner, plugins)
    const status = await inspectCodexDevStatus(context, runner)
    if (status.mode !== "local") {
      throw new Error(`Could not verify local Codex development mode (reported ${status.mode})`)
    }
    return status
  } catch (error) {
    await restoreLocalCollection(context, previous, activatedTarget)
    throw error
  }
}

async function listMarketplaces(context: CodexDevContext, runner: CommandRunner): Promise<Marketplace[]> {
  const result = await runCodex(context, runner, ["plugin", "marketplace", "list", "--json"])
  return parseJson<{ marketplaces?: Marketplace[] }>(result, "codex plugin marketplace list").marketplaces ?? []
}

async function ensureOfficialMarketplace(context: CodexDevContext, runner: CommandRunner): Promise<void> {
  const marketplaces = await listMarketplaces(context, runner)
  const existing = marketplaces.find((marketplace) => marketplace.name === OFFICIAL_MARKETPLACE)
  if (!existing) {
    await runCodex(context, runner, [

View on GitHub (pinned to c9c10f8c75)

Solutions

  1. Inspect `codex:dev -- status` to see the reported mode and installed plugins
  2. Run `bun run codex:dev -- remove` to wipe stale plugin state, then retry `codex:dev -- local`
  3. Manually check `$CODEX_HOME/config.toml` for leftover `compound-engineering` plugin entries and remove them
  4. Start a new Codex session after switching modes (per the repo docs) so the state is re-read

Example fix

// before: switching with stale state
await runCodexDev(["local"])
// after: clean state first
await runCodexDev(["remove"])
await runCodexDev(["local"])
Defensive patterns

Strategy: validation

Validate before calling

const status = await inspectCodexDevStatus(context)
if (status.mode !== "absent" && status.mode !== "remote") {
  await removeCodexDevInstallation(context)
}
await switchToLocal(context)

Type guard

function isLocalMode(status: CodexDevStatus): boolean { return status.mode === "local" }

Try / catch

try {
  await switchToLocal(context)
} catch (error) {
  console.error("Switch to local failed; prior state was restored:", error)
  const status = await inspectCodexDevStatus(context)
  console.log("Current mode:", status.mode)
}

Prevention

When it happens

Trigger: Calling `switchToLocal(context, runner)` when the activated local symlink leaves residual plugin state that keeps `inspectCodexDevStatus` from reporting `"local"` — e.g. an official marketplace-backed plugin was not fully removed by `removeLocalPluginConflicts`, or `activateLocalCollection` produced a link that `inspectLocalCollection` later classifies as `broken`/`unrelated`.

Common situations: Running `bun run codex:dev -- local` in a checkout whose `$CODEX_HOME` already contains a partially-installed official plugin; a stale `~/.codex` state from an older codex-dev run; switching to local while a previous run's cleanup was interrupted.

Related errors


AI-assisted analysis of EveryInc/compound-engineering-plugin@c9c10f8c75 (2026-08-31). Data as JSON: /api/errors/660cc78833caa9a3. Report an issue: GitHub.