{"record":{"id":"374a422673bc0b08","repo":"JuliusBrussee/caveman","slug":"agent-caveman-cloud-mcp-postflight-mismatch","errorCode":null,"errorMessage":"${agent} caveman-cloud MCP postflight mismatch","messagePattern":"(.+?) caveman-cloud MCP postflight mismatch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":2589,"sourceCode":"function installAgentNativeBundleSkills(agent: \"claude\" | \"codex\", journal: AgentNativeBundleJournal): void {\n  const originals = new Map(journal.skills.map((skill) => [skill.file, skill.before_base64]));\n  journal.skills = agentNativeSkillFiles(agent).map(({ file, body }) => {\n    mkdirSync(dirname(file), { recursive: true });\n    atomicWriteFile(file, Buffer.from(body));\n    return {\n      file,\n      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  }","sourceCodeStart":2571,"sourceCodeEnd":2607,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/cli/src/index.ts#L2571-L2607","documentation":"Postflight check in verifyAgentNativeBundle: after setup, the agent's config must contain an MCP server marker named \"caveman-cloud\" whose command and args exactly equal the ones the installer applied (compared via string equality and JSON.stringify of args). A missing marker or any command/args difference throws.","triggerScenarios":"Running `caveman setup --agent-native <agent>` where the caveman-cloud MCP entry was not persisted, was rewritten by the agent itself, or arg ordering/JSON key order differs after stringification. Also triggered if another tool overwrote the agent config between write and verification.","commonSituations":"The agent (claude/codex) rewrites its config file on exit and drops or reorders MCP entries; arg arrays serialized with different key order; concurrent agent session flushed config mid-setup; manual edits to the MCP block.","solutions":["Close all running instances of the agent, then re-run `caveman setup --agent-native <agent>`","Manually inspect the agent config's mcpServers.\"caveman-cloud\" entry and correct command/args to match what setup printed","Remove the bundle (`--remove`) and reinstall so the marker is written fresh","Ensure no wrapper script rewrites the agent config on launch"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// pre-flight: confirm agent config can hold the marker and none exists yet\nimport { readFileSync } from \"node:fs\";\nconst cfg = JSON.parse(readFileSync(\"~/.claude.json\".replace(\"~\", process.env.HOME!), \"utf8\"));\nif (cfg.mcpServers?.[\"caveman-cloud\"]) {\n  console.error(\"caveman-cloud already registered; remove the bundle first to avoid marker mismatch\");\n}","typeGuard":"function isMcpMarker(v: unknown): v is { command: string; args: string[] } {\n  return !!v && typeof (v as any).command === \"string\" && Array.isArray((v as any).args)\n    && (v as any).args.every((a: unknown) => typeof a === \"string\");\n}","tryCatchPattern":"try {\n  await setup([\"--agent-native\", agent]);\n} catch (error) {\n  if (/caveman-cloud MCP postflight mismatch/.test((error as Error).message)) {\n    // close agent processes, then retry once; a running agent rewrites config\n    await closeAgentSessions(agent);\n    await setup([\"--agent-native\", agent]);\n  } else throw error;\n}","preventionTips":["Quit the agent before setup so it cannot rewrite mcpServers between write and verify","Do not hand-edit the caveman-cloud MCP entry while a bundle is installed","Treat marker mismatch as config drift: reconcile, don't force"],"tags":["postflight","mcp","agent-native","config-drift"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}