{"record":{"id":"601ee2859e87ec1a","repo":"EveryInc/compound-engineering-plugin","slug":"local-skill-mode-cannot-represent-default-codex-ho","errorCode":null,"errorMessage":"Local skill mode cannot represent default Codex hooks at hooks/hooks.json. Update the developer workflow before using it.","messagePattern":"Local skill mode cannot represent default Codex hooks at hooks/hooks\\.json\\. Update the developer workflow before using it\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/dev/codex-dev.ts","lineNumber":148,"sourceCode":"    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 })\n  const names: string[] = []\n  for (const entry of entries) {\n    if (!entry.isDirectory() && !entry.isSymbolicLink()) continue\n    try {\n      const stat = await fs.stat(path.join(skillsRoot, entry.name, \"SKILL.md\"))\n      if (stat.isFile()) names.push(entry.name)\n    } catch (error) {\n      if ((error as NodeJS.ErrnoException).code !== \"ENOENT\") throw error","sourceCodeStart":130,"sourceCodeEnd":166,"githubUrl":"https://github.com/EveryInc/compound-engineering-plugin/blob/c9c10f8c75412c7232cb2bd663e5fd1cea98d84e/src/dev/codex-dev.ts#L130-L166","documentation":"Even if the manifest declares no hooks, the library additionally checks whether a default hooks file exists at <repoRoot>/hooks/hooks.json. If that file exists, local skill mode could not represent it once installed, so it throws this error. ENOENT (no such file) is treated as the happy path and swallowed.","triggerScenarios":"fs.stat(<repoRoot>/hooks/hooks.json) succeeds and isFile() is true during assertCompoundEngineeringRepo (src/dev/codex-dev.ts:148); the repo contains a hooks/hooks.json file while running codex:dev -- local.","commonSituations":"A developer prototyped Codex hooks in the checkout and left hooks/hooks.json in place; an upstream branch introduced default hooks while a local-mode workflow is in use; hooks directory restored from an old branch during a rebase.","solutions":["Check the file: ls hooks/hooks.json — if it is experimental leftovers, remove it or move it out of the checkout.","git restore/rebase away the branch that added hooks/hooks.json if it is not intended on this branch.","Use bun run codex:dev -- remote while the repo carries default hooks."],"exampleFix":"// before: repo layout\nhooks/hooks.json   // present\nskills/\n// after\nhooks/             // no hooks.json (or directory removed)\nskills/","handlingStrategy":"validation","validationCode":"import { stat } from \"node:fs/promises\"\ntry {\n  const s = await stat(\"hooks/hooks.json\")\n  if (s.isFile()) throw new Error(\"hooks/hooks.json present; local mode unavailable\")\n} catch (e) {\n  if ((e as NodeJS.ErrnoException).code !== \"ENOENT\") throw e\n}","typeGuard":null,"tryCatchPattern":"try {\n  await switchToLocal()\n} catch (error) {\n  if ((error as Error).message.includes(\"default Codex hooks at hooks/hooks.json\")) {\n    console.error(\"Remove or move hooks/hooks.json, or use codex:dev -- remote\")\n  } else throw error\n}","preventionTips":["Keep hook prototypes outside the repo (or in an untracked scratch dir) while using local mode.","After rebasing onto branches that add hooks/, re-check hooks/hooks.json existence.","Add hooks/hooks.json to a pre-flight check in scripts that automate local mode."],"tags":["validation","hooks","unsupported-feature"],"backgroundTag":"unsupported-manifest-feature","analyzedSha":"c9c10f8c75412c7232cb2bd663e5fd1cea98d84e","analyzedAt":"2026-08-31T15:18:07.959Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}