{"record":{"id":"e77b9682c5c001c9","repo":"JuliusBrussee/caveman","slug":"cave-reserved-tool-name","errorCode":"cave_reserved_tool_name","errorMessage":"cave_reserved_tool_name:${declared.name}","messagePattern":"cave_reserved_tool_name:(.+?)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/definition-graph.ts","lineNumber":43,"sourceCode":"    // it to run closures outside an ancestor's required containment.\n    if (sandboxRequired && definition.sandbox === \"host\") {\n      throw new Error(\"cave_host_sandbox_nested_under_required\");\n    }\n    const memo = visited[sandboxRequired ? 1 : 0]!;\n    if (memo.has(definition)) return;\n    active.add(definition);\n    const childSandboxRequired = sandboxRequired ||\n      definition.sandbox === \"required\";\n    const names = new Set<string>();\n    for (const declared of definition.tools) {\n      if (!declared || declared.kind !== \"tool\" ||\n          typeof declared.name !== \"string\") {\n        throw new Error(\"cave_tool_definition_invalid\");\n      }\n      if (names.has(declared.name)) throw new Error(\"cave_duplicate_tool_name\");\n      names.add(declared.name);\n      if (declared.name.startsWith(\"cave_\")) {\n        throw new Error(`cave_reserved_tool_name:${declared.name}`);\n      }\n      if (typeof Reflect.get(declared, TOOL_IMPLEMENTATION_SOURCE) !== \"string\") {\n        throw new Error(`cave_untrusted_tool_definition:${declared.name}`);\n      }\n      if (declared.runtime?.kind !== \"subagent\") continue;\n      const child = declared.runtime.definition as AgentDefinition;\n      visit(child, depth + 1, childSandboxRequired);\n    }\n    active.delete(definition);\n    memo.add(definition);\n  };\n\n  visit(root, 0, false);\n}\n\n/**\n * True when any agent in the graph opts into host mode.\n *","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/766dce6b1394ebb56a3090748d5a0240a5aefb36/packages/agent/src/definition-graph.ts#L25-L61","documentation":"The `cave_` prefix is reserved for framework built-ins (such as `cave_retrieve`) so user tools can never shadow or impersonate them. `validateAgentGraph` rejects any user-declared tool whose name starts with `cave_`, including the offending name in the message.","triggerScenarios":"Declaring a tool named `cave_search`, `cave_compress`, or anything starting with `cave_` in an agent definition's `tools` array.","commonSituations":"Naming tools after the framework's built-ins by convention (\"cave_* means caveman-related tools\"); wrapping a built-in and keeping its name; tutorial code that mimics internal tool names.","solutions":["Rename the tool to drop the prefix (e.g. `cave_search` → `search` or `vault_search`).","If you intended built-in behavior like recovery retrieval, enable the built-in (`cave_retrieve` comes with the plan) rather than redeclaring it."],"exampleFix":"// before\nconst search = tool({ name: \"cave_search\", ... });\n// after\nconst search = tool({ name: \"search\", ... });","handlingStrategy":"validation","validationCode":"for (const name of definition.tools.map((declared) => declared.name)) {\n  if (name.startsWith(\"cave_\")) {\n    throw new Error(`tool name \"${name}\" uses the reserved cave_ prefix`);\n  }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat cave_ as read-only framework namespace in naming conventions.","Get built-in behavior by enabling framework options, never by redeclaring built-in names."],"tags":["validation","tools","naming","reserved"],"backgroundTag":"reserved-name-prefix","analyzedSha":"766dce6b1394ebb56a3090748d5a0240a5aefb36","analyzedAt":"2026-08-18T03:14:35.516Z","contentChangedAt":"2026-08-18T03:14:35.516Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}