EveryInc/compound-engineering-plugin · error · Error

Cannot switch to remote mode while the local collection is $

Error message

Cannot switch to remote mode while the local collection is ${collection.kind}

What it means

`switchToRemote()` inspects the local collection (the `$CODEX_HOME/skills/compound-engineering-local` symlink) before switching. If the collection is in a state the tool cannot safely clean up — `collision` (a real file/dir occupies the symlink path), `unrelated` (symlink points somewhere foreign), or `broken` (dangling target) — it refuses and throws, to avoid deleting data it did not create.

Source

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

      `Marketplace ${OFFICIAL_MARKETPLACE} exists with an unexpected source; refusing to replace it`,
    )
  }
  await runCodex(context, runner, [
    "plugin",
    "marketplace",
    "upgrade",
    OFFICIAL_MARKETPLACE,
    "--json",
  ])
}

export async function switchToRemote(
  context: CodexDevContext,
  runner: CommandRunner = new BunCommandRunner(),
): Promise<CodexDevStatus> {
  const collection = await inspectLocalCollection(context)
  if (collection.kind === "collision" || collection.kind === "unrelated" || collection.kind === "broken") {
    throw new Error(`Cannot switch to remote mode while the local collection is ${collection.kind}`)
  }

  await ensureOfficialMarketplace(context, runner)
  const plugins = await listCompoundEngineeringPlugins(context, runner)
  await removePlugins(
    context,
    runner,
    collection.kind === "valid"
      ? plugins
      : plugins.filter((entry) => entry.pluginId !== OFFICIAL_PLUGIN_ID),
  )
  await runCodex(context, runner, ["plugin", "add", OFFICIAL_PLUGIN_ID, "--json"])

  const installed = await listCompoundEngineeringPlugins(context, runner)
  if (installed.length !== 1 || !isOfficialMarketplacePlugin(installed[0]!)) {
    throw new Error("Could not verify the official marketplace-backed Compound Engineering plugin")
  }

View on GitHub (pinned to c9c10f8c75)

Solutions

  1. Inspect the path `$CODEX_HOME/skills/compound-engineering-local` yourself
  2. If it is safe to delete, remove the offending file/symlink manually, then retry `codex:dev -- remote`
  3. Run `codex:dev -- status` to confirm the collection state is now `absent` before switching
  4. Preserve anything valuable from a `collision` directory before deleting

Example fix

// before: dangling symlink blocks switch
rm ~/.codex/skills/compound-engineering-local
bun run codex:dev -- remote
Defensive patterns

Strategy: validation

Validate before calling

const collection = await inspectLocalCollection(context)
if (collection.kind === "collision" || collection.kind === "unrelated" || collection.kind === "broken") {
  throw new Error(`Resolve the ${collection.kind} local collection at $CODEX_HOME/skills/compound-engineering-local first`)
}
await switchToRemote(context, runner)

Type guard

function isCleanCollection(c: LocalCollectionState): boolean {
  return c.kind === "absent" || c.kind === "valid"
}

Try / catch

try {
  await switchToRemote(context, runner)
} catch (error) {
  if (String(error).includes("local collection is")) {
    console.error("Inspect and clean $CODEX_HOME/skills/compound-engineering-local manually, then retry")
  } else throw error
}

Prevention

When it happens

Trigger: Calling `switchToRemote(context, runner)` when `inspectLocalCollection` returns `kind` of `"collision"`, `"unrelated"`, or `"broken"` — e.g. the user replaced the skill symlink with a real directory, pointed it at their own skills, or deleted the target checkout.

Common situations: User created `$CODEX_HOME/skills/compound-engineering-local` manually as a folder; target worktree was deleted without running `codex:dev -- remove`; a different tool wrote to the same skills path.

Related errors


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