{"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":null,"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/3ee70a102609e550bd2e68004bf5990a9341c851/packages/agent/src/index.ts#L93-L129","documentation":"agent() reserves the tool-name prefix 'cave_' for framework-provided tools and throws if any user-supplied tool's name starts with it, reporting the offending tool's name. This prevents collisions with internal tools the kernel injects.","triggerScenarios":"agent({ tools: [{ name: 'cave_search', ... }] }) or any custom tool named like 'cave_*'.","commonSituations":"Mimicking the naming style of built-in tools; wrapping a framework tool under a similar name; generated tool names that concatenate a 'cave_' namespace prefix.","solutions":["Rename the tool to a name not starting with 'cave_' (e.g. 'myapp_search')","Namespace with your own prefix instead of the framework's","Search your tool factory for hardcoded 'cave_' prefixes","If you intended a built-in tool, import and use the framework's tool rather than redefining it"],"exampleFix":"// before\nagent({ id: \"bot\", tools: [{ name: \"cave_lookup\", run: lookup }] });\n// after\nagent({ id: \"bot\", tools: [{ name: \"app_lookup\", run: lookup }] });","handlingStrategy":"validation","validationCode":"if (tools.some(t => t.name.startsWith(\"cave_\"))) throw new Error(\"tool uses reserved cave_ prefix\");","typeGuard":"const usesReservedPrefix = (tools) => tools.some(t => typeof t.name === \"string\" && t.name.startsWith(\"cave_\"));","tryCatchPattern":"try { def = agent(opts); } catch (err) { if (String(err.message).includes(\"prefix cave_ is reserved\")) { opts.tools = opts.tools.map(renameReserved); def = agent(opts); } else throw err; }","preventionTips":["Treat 'cave_' as a framework-only namespace","Use your own product prefix for custom tools","Lint tool names against ^cave_ in CI"],"tags":["validation","agent-definition","reserved-names","tools"],"backgroundTag":"invalid-identifier-format","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"}