{"record":{"id":"528246b888948013","repo":"JuliusBrussee/caveman","slug":"claude-caveman-cloud-mcp-exists-but-is-not-caveman","errorCode":null,"errorMessage":"Claude caveman-cloud MCP exists but is not Caveman-journaled; refusing overwrite","messagePattern":"Claude caveman-cloud MCP exists but is not Caveman-journaled; refusing overwrite","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":2557,"sourceCode":"  const previousSkills = new Map(existingBundle?.skills.map((skill) => [skill.file, skill]) ?? []);\n  for (const { file, body } of agentNativeSkillFiles(agent)) {\n    const current = fileBytes(file);\n    if (!existingBundle) {\n      if (current && !current.equals(Buffer.from(body))) {\n        throw new Error(`${file} already exists with non-canonical content; refusing to overwrite an unjournaled skill`);\n      }\n      continue;\n    }\n    const previous = previousSkills.get(file);\n    if (current && !current.equals(Buffer.from(body)) && (!previous || bytesHash(current) !== previous.after_sha256)) {\n      throw new Error(`${file} changed after setup; refusing to overwrite user skill edits`);\n    }\n  }\n  if (agent === \"claude\") {\n    const actual = claudeMcpRegistration(\"caveman-cloud\");\n    const marker = readMcpServerMarker(\"claude\", \"caveman-cloud\");\n    if (actual.present && !marker) {\n      throw new Error(\"Claude caveman-cloud MCP exists but is not Caveman-journaled; refusing overwrite\");\n    }\n    if (actual.present && marker && !agentNativeCloudMcpMatches(\"claude\", marker)) {\n      throw new Error(\"Claude caveman-cloud MCP changed after setup; refusing to overwrite user fields\");\n    }\n    return;\n  }\n  const config = fileBytes(join(homedir(), \".codex\", \"config.toml\"))?.toString(\"utf8\") ?? \"\";\n  if (!config.includes(\"[mcp_servers.caveman-cloud]\")) return;\n  if (!readMcpServerMarker(\"codex\", \"caveman-cloud\")) {\n    throw new Error(\"[mcp_servers.caveman-cloud] exists but is not Caveman-journaled; refusing overwrite\");\n  }\n}\n\nfunction 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));","sourceCodeStart":2539,"sourceCodeEnd":2575,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/cli/src/index.ts#L2539-L2575","documentation":"Claude-specific preflight: claudeMcpRegistration('caveman-cloud') finds a caveman-cloud entry in ~/.claude.json, but no Caveman marker file exists under ~/.caveman-cloud/integrations proving Caveman installed it. Without the marker, Caveman cannot know the entry's provenance or safely overwrite it, so setup refuses rather than clobber a possibly user-owned registration.","triggerScenarios":"User (or an old Caveman version that did not write markers) manually added a caveman-cloud server to Claude's mcpServers; marker files were deleted from ~/.caveman-cloud/integrations; home dir restored from backup without the marker.","commonSituations":"Hand-written MCP config copied from docs or a teammate; leftover from a pre-marker CLI version; cleaning ~/.caveman-cloud while keeping ~/.claude.json.","solutions":["If you do not need the manual entry, remove caveman-cloud from ~/.claude.json's mcpServers and re-run setup so Caveman installs and journals it","If you want to keep your custom entry, rename it to something other than caveman-cloud so Caveman can own the canonical name","Never delete ~/.caveman-cloud/integrations markers while keeping host registrations"],"exampleFix":null,"handlingStrategy":"validation","validationCode":"import { existsSync, readFileSync } from \"node:fs\";\nfunction claudeCavemanCloudJournaled(): boolean {\n  const cfg = JSON.parse(readFileSync(join(homedir(), \".claude.json\"), \"utf8\"));\n  const present = !!cfg.mcpServers?.[\"caveman-cloud\"];\n  const marker = existsSync(join(cavemanHome(), \"mcp\", \"claude.caveman-cloud.json\"));\n  return !present || marker;\n}","typeGuard":"function isUnjournaledClaudeMcpError(e: unknown): boolean {\n  return e instanceof Error && e.message === \"Claude caveman-cloud MCP exists but is not Caveman-journaled; refusing overwrite\";\n}","tryCatchPattern":"try {\n  runCavemanSetup();\n} catch (e) {\n  if (isUnjournaledClaudeMcpError(e)) {\n    // remove the manual caveman-cloud entry from ~/.claude.json (or rename it), re-run\n  } else throw e;\n}","preventionTips":["Never hand-add a caveman-cloud server to Claude's config — let caveman install it","Do not delete ~/.caveman-cloud/integrations markers while keeping host registrations"],"tags":["mcp","claude","preflight","safety"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}