{"record":{"id":"09bdf9eb1b9138e4","repo":"Yeachan-Heo/oh-my-codex","slug":"sandbox-md-is-required-inside-mission-dir-sandb","errorCode":null,"errorMessage":"sandbox.md is required inside mission-dir: ${sandboxFile}","messagePattern":"sandbox\\.md is required inside mission-dir: (.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/autoresearch/contracts.ts","lineNumber":227,"sourceCode":"  };\n}\n\nexport async function loadAutoresearchMissionContract(missionDirArg: string): Promise<AutoresearchMissionContract> {\n  const missionDir = resolve(missionDirArg);\n  if (!existsSync(missionDir)) {\n    throw contractError(`mission-dir does not exist: ${missionDir}`);\n  }\n\n  const repoRoot = readGit(missionDir, ['rev-parse', '--show-toplevel']);\n  ensurePathInside(repoRoot, missionDir);\n\n  const missionFile = join(missionDir, 'mission.md');\n  const sandboxFile = join(missionDir, 'sandbox.md');\n  if (!existsSync(missionFile)) {\n    throw contractError(`mission.md is required inside mission-dir: ${missionFile}`);\n  }\n  if (!existsSync(sandboxFile)) {\n    throw contractError(`sandbox.md is required inside mission-dir: ${sandboxFile}`);\n  }\n\n  const missionContent = await readFile(missionFile, 'utf-8');\n  const sandboxContent = await readFile(sandboxFile, 'utf-8');\n  const sandbox = parseSandboxContract(sandboxContent);\n  const missionRelativeDir = relative(repoRoot, missionDir) || basename(missionDir);\n  const missionSlug = slugifyMissionName(missionRelativeDir);\n\n  return {\n    missionDir,\n    repoRoot,\n    missionFile,\n    sandboxFile,\n    missionRelativeDir,\n    missionContent,\n    sandboxContent,\n    sandbox,\n    missionSlug,","sourceCodeStart":209,"sourceCodeEnd":245,"githubUrl":"https://github.com/Yeachan-Heo/oh-my-codex/blob/3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2/src/autoresearch/contracts.ts#L209-L245","documentation":"loadAutoresearchMissionContract requires a sandbox.md file directly inside the mission directory; if existsSync(join(missionDir,'sandbox.md')) fails it throws with the expected path. sandbox.md defines the evaluator contract (frontmatter with evaluator.command and evaluator.format=json) plus sandbox body.","triggerScenarios":"Mission directory missing sandbox.md entirely; file named sandbox.txt or with different casing on a case-sensitive filesystem.","commonSituations":"New missions authored with only mission.md; files renamed or excluded by .gitignore so they are missing after clone; casing mistakes across operating systems.","solutions":["Create sandbox.md in the mission directory with valid frontmatter (evaluator.command, evaluator.format: json).","Verify exact filename casing 'sandbox.md'.","Ensure sandbox.md is committed and not ignored by .gitignore."],"exampleFix":"# before\nmissions/m1/\n  mission.md\n\n# after\nmissions/m1/\n  mission.md\n  sandbox.md  # ---\\nevaluator:\\n  command: ./evaluate.sh\\n  format: json\\n---","handlingStrategy":"validation","validationCode":"import { existsSync } from 'node:fs';\nimport { join } from 'node:path';\n\nif (!existsSync(join(missionDir, 'sandbox.md'))) {\n  throw new Error('sandbox.md missing — add evaluator frontmatter (evaluator.command, format: json)');\n}\nconst contract = await loadAutoresearchMissionContract(missionDir);","typeGuard":null,"tryCatchPattern":"try {\n  await loadAutoresearchMissionContract(dir);\n} catch (err) {\n  if ((err as Error).message.includes('sandbox.md is required')) {\n    // create sandbox.md with valid evaluator frontmatter in the mission dir\n  }\n  throw err;\n}","preventionTips":["Scaffold missions from a template containing sandbox.md.","Verify sandbox.md is committed and not gitignored.","Use exact filename 'sandbox.md'; beware casing on case-sensitive filesystems."],"tags":["filesystem","mission-dir","missing-file","sandbox-md"],"backgroundTag":"missing-required-file","analyzedSha":"3ad79a8a6fe6e95fdbb8c00e40716fffe4011ce2","analyzedAt":"2026-08-27T22:18:39.783Z","schemaVersion":2},"datasetVersion":"2026-08-28T00:17:15.603Z"}