{"record":{"id":"6a4d9e1b24d4e813","repo":"JuliusBrussee/caveman","slug":"cave-claude-tool-contract-unsupported","errorCode":"cave_claude_tool_contract_unsupported","errorMessage":"cave_claude_tool_contract_unsupported:${unsupportedTool.name}","messagePattern":"cave_claude_tool_contract_unsupported:(.+?)","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"packages/agent/src/claude-runtime.ts","lineNumber":103,"sourceCode":"  if (options.lockedBuild !== undefined && options.candidatePlan !== undefined) {\n    throw new Error(\"cave_execution_authorization_ambiguous\");\n  }\n  if (options.candidatePlan !== undefined) {\n    throw new Error(\"cave_claude_candidate_execution_unavailable\");\n  }\n  if (options.lockedBuild !== undefined) {\n    throw new Error(\"cave_claude_locked_execution_unavailable\");\n  }\n  if (definition.memory !== undefined) {\n    throw new Error(\"cave_claude_memory_bridge_unavailable\");\n  }\n  if (definition.tools.some((item) => item.runtime?.kind === \"subagent\")) {\n    throw new Error(\"cave_claude_subagent_bridge_unavailable\");\n  }\n  const unsupportedTool = definition.tools.find((item) =>\n    item.effect !== \"read\" || item.result !== \"inline\");\n  if (unsupportedTool !== undefined) {\n    throw new Error(`cave_claude_tool_contract_unsupported:${unsupportedTool.name}`);\n  }\n  if (options.maxTurns !== undefined &&\n      (!Number.isSafeInteger(options.maxTurns) || options.maxTurns <= 0 || options.maxTurns > 1_000)) {\n    throw new Error(\"cave_claude_max_turns_invalid\");\n  }\n  if (options.maxBudgetUsd !== undefined &&\n      (!Number.isFinite(options.maxBudgetUsd) || options.maxBudgetUsd <= 0)) {\n    throw new Error(\"cave_claude_max_budget_invalid\");\n  }\n  const rootDir = resolve(options.rootDir ?? process.cwd());\n  const lowered = await lowerAgentContext(definition, { rootDir, input });\n  const bill = contextBill(lowered.ir);\n  const selected = resolveClaudeModel(definition, rootDir);\n  const reasoningOptions = claudeReasoningOptions(\n    selected,\n    definition.reasoning,\n    definition.output?.maxTokens,\n  );","sourceCodeStart":85,"sourceCodeEnd":121,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/claude-runtime.ts#L85-L121","documentation":"runClaudeAgentWithOptions only supports tools declared with effect \"read\" and inline results. Any tool in the AgentDefinition violating that contract is rejected before the Claude run starts, and the offending tool's name is appended to the message. This guarantees the Claude runtime bridge never has to model side-effecting or non-inline tool results.","triggerScenarios":"Passing an AgentDefinition whose tools array contains a tool with effect !== \"read\" or result !== \"inline\" — e.g. a write-effect filesystem tool or a tool returning a resource/file reference.","commonSituations":"Reusing a general-purpose agent definition (with write/bash tools) against the Claude runtime; adding a new tool with the default effect without realizing the Claude bridge only accepts read/inline tools.","solutions":["Change the offending tool's definition to effect: \"read\" and result: \"inline\"","Remove the unsupported tool from definition.tools when targeting the Claude runtime","If the tool must write, run it in a different runtime that supports the full tool contract"],"exampleFix":"// before\ntools: [{ name: \"save_note\", effect: \"write\", result: \"inline\", ... }]\n// after\ntools: [{ name: \"read_note\", effect: \"read\", result: \"inline\", ... }]","handlingStrategy":"validation","validationCode":"const bad = definition.tools.find(t => t.effect !== \"read\" || t.result !== \"inline\");\nif (bad) throw new Error(`tool ${bad.name} must be read/inline for the Claude runtime`);","typeGuard":"const isClaudeCompatible = (t) => t.effect === \"read\" && t.result === \"inline\";","tryCatchPattern":"try { await runClaudeAgent(opts); } catch (e) { if (String(e.message).startsWith(\"cave_claude_tool_contract_unsupported:\")) { /* drop or re-scope tool */ } else throw e; }","preventionTips":["Keep a separate read-only tool set for the Claude runtime","Assert tool contracts in tests before running agents","Default new tools to effect:\"read\" unless they truly need write"],"tags":["tools","validation","claude-runtime"],"backgroundTag":"unsupported-operation","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}