{"record":{"id":"48cdf1209998fb3d","repo":"EveryInc/compound-engineering-plugin","slug":"local-skill-mode-cannot-represent-codex-runtime-co","errorCode":null,"errorMessage":"Local skill mode cannot represent Codex runtime components: ${unsupported.join(\", \")}. Update the developer workflow before using it.","messagePattern":"Local skill mode cannot represent Codex runtime components: (.+?)\\. Update the developer workflow before using it\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/dev/codex-dev.ts","lineNumber":140,"sourceCode":"\nasync function assertCompoundEngineeringRepo(repoRoot: string): Promise<void> {\n  const packageJson = await readJson(path.join(repoRoot, \"package.json\"))\n  if (packageJson.name !== \"compound-engineering\") {\n    throw new Error(`${repoRoot} is not the compound-engineering repository`)\n  }\n  const pluginJson = await readJson(path.join(repoRoot, \".codex-plugin\", \"plugin.json\"))\n  if (pluginJson.name !== \"compound-engineering\") {\n    throw new Error(`${repoRoot} is not the compound-engineering repository`)\n  }\n\n  const skills = pluginJson.skills\n  if (typeof skills !== \"string\" || path.resolve(repoRoot, skills) !== path.join(repoRoot, \"skills\")) {\n    throw new Error(\"The Codex plugin manifest does not point at this repository's skills directory\")\n  }\n\n  const unsupported = [\"apps\", \"hooks\", \"mcpServers\"].filter((key) => pluginJson[key] !== undefined)\n  if (unsupported.length > 0) {\n    throw new Error(\n      `Local skill mode cannot represent Codex runtime components: ${unsupported.join(\", \")}. Update the developer workflow before using it.`,\n    )\n  }\n\n  try {\n    const defaultHooks = await fs.stat(path.join(repoRoot, \"hooks\", \"hooks.json\"))\n    if (defaultHooks.isFile()) {\n      throw new Error(\n        \"Local skill mode cannot represent default Codex hooks at hooks/hooks.json. Update the developer workflow before using it.\",\n      )\n    }\n  } catch (error) {\n    if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error\n  }\n}\n\nasync function listSkills(skillsRoot: string): Promise<string[]> {\n  const entries = await fs.readdir(skillsRoot, { withFileTypes: true })","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/EveryInc/compound-engineering-plugin/blob/c9c10f8c75412c7232cb2bd663e5fd1cea98d84e/src/dev/codex-dev.ts#L122-L158","documentation":"Local skill mode can only link the skills directory; it cannot represent Codex runtime components. If .codex-plugin/plugin.json defines any of apps, hooks, or mcpServers, the library refuses with this error listing the offending keys, so the developer updates the workflow before linking, avoiding a half-installed local mode.","triggerScenarios":"resolveCodexDevContext -> assertCompoundEngineeringRepo finds pluginJson[\"apps\"], pluginJson[\"hooks\"], or pluginJson[\"mcpServers\"] defined (non-undefined) in .codex-plugin/plugin.json (src/dev/codex-dev.ts:140).","commonSituations":"A developer added MCP servers or hooks to the Codex manifest for a new feature and then ran codex:dev -- local; merging an upstream change that introduced runtime components; a stale/hand-edited manifest carrying legacy keys.","solutions":["Check which keys are listed: jq '{apps, hooks, mcpServers}' .codex-plugin/plugin.json.","Remove the listed keys from the manifest (or git restore it) if they are not needed.","If the components are genuinely required, do not use local skill mode — use bun run codex:dev -- remote (marketplace install) until the dev workflow supports them."],"exampleFix":"// before: .codex-plugin/plugin.json\n{ \"name\": \"compound-engineering\", \"skills\": \"skills\", \"mcpServers\": { \"docs\": {} } }\n// after\n{ \"name\": \"compound-engineering\", \"skills\": \"skills\" }","handlingStrategy":"validation","validationCode":"const m = JSON.parse(await (await import(\"node:fs/promises\")).readFile(\".codex-plugin/plugin.json\", \"utf8\"))\nconst bad = [\"apps\", \"hooks\", \"mcpServers\"].filter((k) => m[k] !== undefined)\nif (bad.length > 0) throw new Error(`Remove ${bad.join(\", \")} before codex:dev -- local`)","typeGuard":"function isSkillsOnlyManifest(m: Record<string, unknown>): boolean {\n  return [\"apps\", \"hooks\", \"mcpServers\"].every((k) => m[k] === undefined)\n}","tryCatchPattern":"try {\n  await switchToLocal()\n} catch (error) {\n  if ((error as Error).message.startsWith(\"Local skill mode cannot represent Codex runtime components\")) {\n    console.error(\"Use bun run codex:dev -- remote, or remove the runtime keys from the manifest\")\n  } else throw error\n}","preventionTips":["Check jq '{apps,hooks,mcpServers}' .codex-plugin/plugin.json before local mode.","Branch work that adds runtime components should use codex:dev -- remote, not local mode.","Re-run release:validate after merging upstream manifest changes."],"tags":["validation","manifest","unsupported-feature"],"backgroundTag":"unsupported-manifest-feature","analyzedSha":"c9c10f8c75412c7232cb2bd663e5fd1cea98d84e","analyzedAt":"2026-08-31T15:18:07.959Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}