{"record":{"id":"076887bc6edd9d4a","repo":"ruvnet/ruflo","slug":"name-must-be-lowercase-kebab-e-g-sales","errorCode":null,"errorMessage":"name must be lowercase-kebab (e.g. \"sales\")","messagePattern":"name must be lowercase-kebab \\(e\\.g\\. \"sales\"\\)","errorType":"validation","errorClass":"PodTemplateValidationError","httpStatus":null,"severity":"error","filePath":"v3/@claude-flow/cli/src/business-pods/pod-schema.ts","lineNumber":193,"sourceCode":"// time. We only catch obviously malformed values here.\nconst CRON_RE = /^([\\d*/,\\-]+\\s+){4,5}[\\d*/,\\-]+$/;\n\n/**\n * Validate `json` and return a typed `PodTemplate`. Throws\n * `PodTemplateValidationError` with a JSON-pointer-style path on failure.\n *\n * Used by:\n *   - `business_pod_validate` MCP tool — returns the error verbatim\n *   - `pod-tick.mjs` — pre-flight check before any pod execution\n *   - any external schema-loader that wants typed templates\n */\nexport function validatePodTemplate(json: unknown): PodTemplate {\n  if (!isObject(json)) {\n    throw new PodTemplateValidationError('pod-template must be a JSON object', '/');\n  }\n  const name = requireString(json, 'name', '/');\n  if (!/^[a-z][a-z0-9-]*$/.test(name)) {\n    throw new PodTemplateValidationError('name must be lowercase-kebab (e.g. \"sales\")', '/');\n  }\n  const displayName = requireString(json, 'displayName', '/');\n  const roomId = requireString(json, 'roomId', '/');\n  if (!/^[A-Za-z0-9_.\\-:/@#]+$/.test(roomId)) {\n    throw new PodTemplateValidationError(\n      'roomId may only contain [A-Za-z0-9_.\\\\-:/@#]',\n      '/',\n    );\n  }\n  const agents = requireArray(json, 'agents', '/', validatePodAgent);\n  if (agents.length === 0) {\n    throw new PodTemplateValidationError('agents must have ≥1 entry', '/');\n  }\n  const allowedMcpTools = requireArray(json, 'allowedMcpTools', '/', (t, tp) => {\n    if (typeof t !== 'string' || t.length === 0) {\n      throw new PodTemplateValidationError(\n        'allowedMcpTools entries must be non-empty strings',\n        tp,","sourceCodeStart":175,"sourceCodeEnd":211,"githubUrl":"https://github.com/ruvnet/ruflo/blob/fa13ee4ad60ac2090b1480656eb233521790d640/v3/@claude-flow/cli/src/business-pods/pod-schema.ts#L175-L211","documentation":"The template's top-level name must match /^[a-z][a-z0-9-]*$/: start with a lowercase letter, followed only by lowercase letters, digits, and hyphens. Uppercase letters, underscores, leading digits/hyphens, spaces, and punctuation are rejected. The kebab name is the pod's stable identifier (used in scheduling, logs, and MCP tooling).","triggerScenarios":"validatePodTemplate() on a template with name values like \"Sales\", \"sales_pod\", \"1sales\", \"-sales\", or \"sales pod\". The error is reported at path '/'.","commonSituations":"Copying the human-facing displayName (\"Sales Pod\") into name; org naming conventions with underscores; title-cased department names pasted from docs.","solutions":["Rewrite name in lowercase-kebab: \"sales\", \"growth-eng\", \"support-tier1\"","Keep the human label in displayName — that field has no format restriction","Verify with a quick regex test before submitting the template to business_pod_validate"],"exampleFix":"// before\n{ \"name\": \"Sales_Pod\", \"displayName\": \"Sales\" }\n// after\n{ \"name\": \"sales-pod\", \"displayName\": \"Sales\" }","handlingStrategy":"validation","validationCode":"if (!/^[a-z][a-z0-9-]*$/.test(template.name)) {\n  template.name = template.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+/, '');\n}","typeGuard":"function isKebabName(v: unknown): v is string {\n  return typeof v === 'string' && /^[a-z][a-z0-9-]*$/.test(v);\n}","tryCatchPattern":"try { validatePodTemplate(json); } catch (err) {\n  if (err instanceof PodTemplateValidationError && /lowercase-kebab/.test(err.message)) {\n    // slugify name, keep the original in displayName, retry\n  }\n}","preventionTips":["Generate name from displayName with a slugify step in your template tooling","Reserve human labels for displayName — name is a machine identifier"],"tags":["schema-validation","business-pods","naming","identifier","pod-template"],"backgroundTag":"schema-validation-failed","analyzedSha":"fa13ee4ad60ac2090b1480656eb233521790d640","analyzedAt":"2026-08-18T21:34:22.708Z","schemaVersion":2},"datasetVersion":"2026-08-21T13:17:26.733Z"}