{"record":{"id":"918f50e5c43a14f6","repo":"JuliusBrussee/caveman","slug":"caveman-agent-tool-prefix-cave-is-reserved-by-fr","errorCode":null,"errorMessage":"caveman agent: tool prefix cave_ is reserved by framework (${reserved.name})","messagePattern":"caveman agent: tool prefix cave_ is reserved by framework \\((.+?)\\)","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/index.ts","lineNumber":111,"sourceCode":"  contexts?: ContextDefinition[];\n  memory?: MemoryDefinition;\n  output?: OutputDefinition;\n  sandbox?: AgentDefinition[\"sandbox\"];\n}): AgentDefinition {\n  if (!/^[a-z0-9][a-z0-9_-]{0,95}$/.test(options.id)) {\n    throw new Error(`caveman agent: invalid agent id ${JSON.stringify(options.id)}`);\n  }\n  const tools = Object.freeze([...(options.tools ?? [])]);\n  if (new Set(tools.map((item) => item.name)).size !== tools.length) {\n    throw new Error(\"caveman agent: duplicate tool name\");\n  }\n  const sandbox = options.sandbox ?? \"required\";\n  if (!SANDBOX_MODES.includes(sandbox)) {\n    throw new Error(`caveman agent: unknown sandbox mode ${JSON.stringify(sandbox)}`);\n  }\n  const reserved = tools.find((item) => item.name.startsWith(\"cave_\"));\n  if (reserved) {\n    throw new Error(\n      `caveman agent: tool prefix cave_ is reserved by framework (${reserved.name})`,\n    );\n  }\n  const definition: AgentDefinition = {\n    kind: \"agent\",\n    id: options.id,\n    instructions: options.instructions,\n    model: options.model,\n    reasoning: options.reasoning ?? \"low\",\n    tools,\n    contexts: Object.freeze([...(options.contexts ?? [])]),\n    sandbox,\n    ...(options.memory === undefined ? {} : { memory: options.memory }),\n    ...(options.output === undefined ? {} : { output: options.output }),\n  };\n  return Object.freeze(definition);\n}\n","sourceCodeStart":93,"sourceCodeEnd":129,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/27d5a3981a347890211bb1bf2439e5c821a63bc9/packages/agent/src/index.ts#L93-L129","documentation":"Thrown by the agent() builder (packages/agent/src/index.ts:111): a tool in the agent's tools array has a name starting with 'cave_', which is reserved for framework-provided tools. This is the construction-time equivalent of the graph validation check, firing earlier with a clearer message.","triggerScenarios":"Calling agent({ tools: [tool({ name: 'cave_...', ... })] }) — any tool whose name begins with the reserved prefix 'cave_'.","commonSituations":"Naming a wrapper around a framework tool with the same 'cave_' prefix; teams adopting a 'cave_' naming convention for their project; wrapping framework tools and forwarding the original name.","solutions":["Rename the tool to drop or change the prefix (e.g. 'my_search' instead of 'cave_search').","If wrapping a framework tool, give the wrapper its own non-reserved name.","Add a lint/assert step in shared tool factories rejecting 'cave_'-prefixed names."],"exampleFix":"// before\ntool({ name: \"cave_retrieve_v2\", /* ... */ });\n\n// after\ntool({ name: \"project_retrieve_v2\", /* ... */ });","handlingStrategy":"validation","validationCode":"const reserved = tools.find((t) => t.name.startsWith(\"cave_\"));\nif (reserved) throw new Error(`rename '${reserved.name}': cave_ prefix is framework-reserved`);","typeGuard":"function hasReservedPrefix(name: string): boolean {\n  return name.startsWith(\"cave_\");\n}","tryCatchPattern":null,"preventionTips":["Adopt a project tool-name convention that never uses the cave_ prefix.","When wrapping framework tools, give wrappers their own names.","Enforce with a lint rule or factory helper that rejects reserved prefixes."],"tags":["validation","naming","reserved-prefix","tools"],"backgroundTag":null,"analyzedSha":"27d5a3981a347890211bb1bf2439e5c821a63bc9","analyzedAt":"2026-08-15T09:26:11.751Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}