{"record":{"id":"75f190639ed9fd92","repo":"JuliusBrussee/caveman","slug":"skill-file-failed-skill-postflight","errorCode":null,"errorMessage":"${skill.file} failed skill postflight","messagePattern":"(.+?) failed skill postflight","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":2596,"sourceCode":"      before_base64: originals.get(file) ?? null,\n      after_sha256: bytesHash(Buffer.from(body)),\n    };\n  });\n}\n\nfunction verifyAgentNativeBundle(agent: \"claude\" | \"codex\", journal: AgentNativeBundleJournal, cloudMcp: { command: string; args: string[] }): void {\n  const status = nativeIntegrationStatus(agent);\n  if (status.state !== \"installed\") throw new Error(`${agent} native integration postflight is ${status.state}`);\n  const marker = readMcpServerMarker(agent, \"caveman-cloud\");\n  if (!marker || marker.command !== cloudMcp.command || JSON.stringify(marker.args) !== JSON.stringify(cloudMcp.args)) {\n    throw new Error(`${agent} caveman-cloud MCP postflight mismatch`);\n  }\n  if (!agentNativeCloudMcpMatches(agent, cloudMcp)) {\n    throw new Error(`${agent} caveman-cloud MCP registration failed exact postflight`);\n  }\n  for (const skill of journal.skills) {\n    const current = fileBytes(skill.file);\n    if (!current || bytesHash(current) !== skill.after_sha256) throw new Error(`${skill.file} failed skill postflight`);\n  }\n}\n\nfunction removeAgentNativeBundle(agent: \"claude\" | \"codex\"): void {\n  recoverPendingAgentNativeRemoval(agent);\n  recoverPendingAgentNativeBundle(agent);\n  const journal = readAgentNativeBundleJournal(agent);\n  if (!journal) {\n    process.stderr.write(`${mark(\"warn\")} ${agent}: no agent-native bundle journal found\\n`);\n    return;\n  }\n  for (const skill of journal.skills) {\n    const current = fileBytes(skill.file);\n    if (!current || bytesHash(current) !== skill.after_sha256) throw new Error(`${skill.file} changed after setup; refusing destructive bundle removal`);\n  }\n  const marker = readMcpServerMarker(agent, \"caveman-cloud\");\n  if (!sameMcpCommand(marker, journal.cloud_mcp) || !agentNativeCloudMcpMatches(agent, journal.cloud_mcp)) {\n    throw new Error(`${agent} caveman-cloud MCP changed after setup; refusing destructive bundle removal`);","sourceCodeStart":2578,"sourceCodeEnd":2614,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/cli/src/index.ts#L2578-L2614","documentation":"Postflight loop in verifyAgentNativeBundle: every skill file recorded in the AgentNativeBundleJournal must still exist on disk (fileBytes returns bytes) and hash to the after_sha256 captured at write time. A missing file or content change means the skill bundle did not survive setup or was modified immediately after.","triggerScenarios":"Running agent-native setup when a skill file is deleted between write and verification, or when antivirus/editor/another process rewrites the file; also when after_sha256 was journaled from a different body than what was written (partial write, disk full).","commonSituations":"Disk-full during setup leaving truncated skill files; file watchers (formatters, sync clients) touching freshly written SKILL.md files; two concurrent setups writing overlapping skill paths.","solutions":["Free disk space and re-run `caveman setup --agent-native <agent> --remove` followed by setup","Temporarily disable editors/formatters/cloud-sync watching the agent skills directory during setup","Verify permissions on the agent skills directory and repair with a clean reinstall of the bundle"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-flight: writable skills dir + disk headroom avoids truncated writes\nimport { accessSync, constants } from \"node:fs\";\naccessSync(skillsDir, constants.W_OK);\nconst stat = await import(\"node:fs/promises\").then((f) => f.statfs(skillsDir));\nif (Number(stat.bavail) * Number(stat.bsize) < 50 * 1024 * 1024) throw new Error(\"<50MB free; skill writes may truncate\");","typeGuard":null,"tryCatchPattern":"try {\n  await setup([\"--agent-native\", agent]);\n} catch (error) {\n  if (/failed skill postflight/.test((error as Error).message)) {\n    // file named in the message drifted; clean reinstall is the reliable repair\n    await setup([\"--agent-native\", agent, \"--remove\"]).catch(() => {});\n    await setup([\"--agent-native\", agent]);\n  } else throw error;\n}","preventionTips":["Pause formatters/sync clients watching the agent skills directory during setup","Ensure adequate free disk space before install","Never edit installed skill files in place; layer changes outside the bundle"],"tags":["postflight","skills","integrity","sha256"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}