JuliusBrussee/caveman · error · Error

caveman-cloud MCP postflight mismatch

Error message

${agent} caveman-cloud MCP postflight mismatch

What it means

Thrown by verifyAgentNativeBundle when the caveman-cloud MCP server marker read back from the agent's config either does not exist or does not exactly match the expected command and args that were supposed to be registered during setup. This is a postflight consistency check on the agent's MCP configuration.

Solutions

  1. Re-run `caveman setup --agent-native <agent>` to rewrite the caveman-cloud MCP entry.
  2. Inspect the agent's MCP config for the caveman-cloud entry and remove stale/conflicting registrations manually, then re-run setup.
  3. Confirm no other tool (or an older caveman version) is managing the caveman-cloud server name in that agent's config.
  4. Compare the marker's command/args with the expected values to spot path drift (e.g. node version path changed) and update.

Example fix

// before: stale marker from an old install
"caveman-cloud": { "command": "/old/path/node", "args": ["old-cli.mjs"] }
// after: re-run setup or correct the entry
"caveman-cloud": { "command": "/current/path/node", "args": ["/current/caveman.mjs", "serve-cloud"] }
Defensive patterns

Strategy: validation

Validate before calling

const marker = readMcpServerMarker(agent, "caveman-cloud");
if (!marker || marker.command !== expected.command || JSON.stringify(marker.args) !== JSON.stringify(expected.args)) {
  console.error("caveman-cloud MCP entry missing or stale; re-run caveman setup --agent-native " + agent);
}

Type guard

function hasCloudMarker(m: unknown): m is { command: string; args: string[] } {
  return !!m && typeof m === "object" && typeof (m as any).command === "string" && Array.isArray((m as any).args);
}

Try / catch

try {
  verifyAgentNativeBundle(agent, journal, cloudMcp);
} catch (err) {
  if (/(postflight mismatch)/.test((err as Error).message)) {
    console.error("MCP entry drifted; re-running setup to rewrite it");
  }
}

Prevention

When it happens

Trigger: After setup, readMcpServerMarker(agent, "caveman-cloud") returns null, or the marker's command/args differ from the cloudMcp {command,args} the setup intended to write — e.g. the agent rewrote its config, or a stale entry points at an old command path.

Common situations: The agent CLI normalized or rewrote its MCP config on startup; a different tool also manages the same MCP server name and overwrote it; switching between dev/staging cloud commands left a stale marker; manual edits to the agent config.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/374a422673bc0b08. Report an issue: GitHub.

Appendix: source

Thrown at packages/cli/src/index.ts:2909

function installAgentNativeBundleSkills(agent: "claude" | "codex", journal: AgentNativeBundleJournal): void {
  const originals = new Map(journal.skills.map((skill) => [skill.file, skill.before_base64]));
  journal.skills = agentNativeSkillFiles(agent).map(({ file, body }) => {
    mkdirSync(dirname(file), { recursive: true });
    atomicWriteFile(file, Buffer.from(body));
    return {
      file,
      before_base64: originals.get(file) ?? null,
      after_sha256: bytesHash(Buffer.from(body)),
    };
  });
}

function verifyAgentNativeBundle(agent: "claude" | "codex", journal: AgentNativeBundleJournal, cloudMcp: { command: string; args: string[] }): void {
  const status = nativeIntegrationStatus(agent);
  if (status.state !== "installed") throw new Error(`${agent} native integration postflight is ${status.state}`);
  const marker = readMcpServerMarker(agent, "caveman-cloud");
  if (!marker || marker.command !== cloudMcp.command || JSON.stringify(marker.args) !== JSON.stringify(cloudMcp.args)) {
    throw new Error(`${agent} caveman-cloud MCP postflight mismatch`);
  }
  if (!agentNativeCloudMcpMatches(agent, cloudMcp)) {
    throw new Error(`${agent} caveman-cloud MCP registration failed exact postflight`);
  }
  for (const skill of journal.skills) {
    const current = fileBytes(skill.file);
    if (!current || bytesHash(current) !== skill.after_sha256) throw new Error(`${skill.file} failed skill postflight`);
  }
}

function removeAgentNativeBundle(agent: "claude" | "codex"): void {
  recoverPendingAgentNativeRemoval(agent);
  recoverPendingAgentNativeBundle(agent);
  const journal = readAgentNativeBundleJournal(agent);
  if (!journal) {
    process.stderr.write(`${mark("warn")} ${agent}: no agent-native bundle journal found\n`);
    return;
  }

View on GitHub (pinned to 3ee70a1026)