{"record":{"id":"7e05cc093d70ffe6","repo":"EveryInc/compound-engineering-plugin","slug":"no-codex-skills-were-found-under-skillsroot","errorCode":null,"errorMessage":"No Codex skills were found under ${skillsRoot}","messagePattern":"No Codex skills were found under (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/dev/codex-dev.ts","lineNumber":214,"sourceCode":"  )\n  const branchValue = trim(\n    await checkedRun(runner, \"git\", [\"branch\", \"--show-current\"], { cwd: repoRoot, env }),\n  )\n  const head = trim(await checkedRun(runner, \"git\", [\"rev-parse\", \"HEAD\"], { cwd: repoRoot, env }))\n  const status = trim(\n    await checkedRun(runner, \"git\", [\"status\", \"--porcelain=v1\", \"--untracked-files=all\"], {\n      cwd: repoRoot,\n      env,\n    }),\n  )\n  const lines = status ? status.split(\"\\n\") : []\n  const untrackedCount = lines.filter((line) => line.startsWith(\"?? \")).length\n  const modifiedCount = lines.length - untrackedCount\n\n  const codexHome = resolveHomePath(env.CODEX_HOME || path.join(home, \".codex\"), home)\n  const skillsRoot = path.join(repoRoot, \"skills\")\n  const skillNames = await listSkills(skillsRoot)\n  if (skillNames.length === 0) throw new Error(`No Codex skills were found under ${skillsRoot}`)\n\n  return {\n    repoRoot,\n    skillsRoot,\n    codexHome,\n    collectionPath: path.join(codexHome, \"skills\", \"compound-engineering-local\"),\n    gitDir: path.resolve(gitDir),\n    gitCommonDir: path.resolve(gitCommonDir),\n    linkedWorktree: path.resolve(gitDir) !== path.resolve(gitCommonDir),\n    branch: branchValue || null,\n    head,\n    modifiedCount,\n    untrackedCount,\n    skillNames,\n    env: { ...env, CODEX_HOME: codexHome },\n  }\n}\n","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/EveryInc/compound-engineering-plugin/blob/c9c10f8c75412c7232cb2bd663e5fd1cea98d84e/src/dev/codex-dev.ts#L196-L232","documentation":"After resolving the repo root, resolveCodexDevContext enumerates skills under <repoRoot>/skills via listSkills and requires at least one. If none are found it throws with the skills root in the message. The workflow has nothing to link otherwise, so an empty collection is treated as a broken checkout rather than a no-op.","triggerScenarios":"The skills/ directory at the repo root is empty, contains no subdirectories that listSkills counts (e.g. none with SKILL.md if that is its criterion), or listSkills fails to see entries — thrown at src/dev/codex-dev.ts:214.","commonSituations":"A fresh or partially cloned checkout where skills/ is an empty submodule or was cleaned by git clean -fd; a worktree where untracked skill directories were never checked out; an experiment that moved all skills elsewhere.","solutions":["List what is actually there: ls skills/ — confirm it is empty or missing SKILL.md entries.","Restore the skills directory: git restore skills/ or git submodule update --init if skills is a submodule.","Re-clone the repository if the checkout is incomplete.","git clean -xdn first to see if git clean removed them, then recover accordingly."],"exampleFix":"// before\nskills/          // empty\n// after\ngit checkout main -- skills/ && ls skills/\nce-brainstorm/ ce-plan/ ...   // skill dirs restored","handlingStrategy":"validation","validationCode":"import { readdir } from \"node:fs/promises\"\nconst entries = await readdir(\"skills\", { withFileTypes: true })\nif (!entries.some((e) => e.isDirectory())) {\n  throw new Error(\"skills/ is empty — restore it: git restore skills/ or git submodule update --init\")\n}","typeGuard":null,"tryCatchPattern":"try {\n  await resolveCodexDevContext(cwd)\n} catch (error) {\n  if ((error as Error).message.startsWith(\"No Codex skills were found under\")) {\n    console.error(\"Checkout is incomplete; restore the skills/ directory from git\")\n  } else throw error\n}","preventionTips":["Avoid git clean -fdx in checkouts used for codex:dev local mode.","Initialize submodules after clone if skills/ is one.","Verify ls skills/ is populated before switching install modes."],"tags":["filesystem","validation","skills"],"backgroundTag":"empty-directory-unexpected","analyzedSha":"c9c10f8c75412c7232cb2bd663e5fd1cea98d84e","analyzedAt":"2026-08-31T15:18:07.959Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}