{"record":{"id":"2b911843caef642d","repo":"different-ai/openwork","slug":"command-template-is-required","errorCode":null,"errorMessage":"command.template is required","messagePattern":"command\\.template is required","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/electron/main.mjs","lineNumber":1250,"sourceCode":"}\n\nfunction sanitizeCommandName(raw) {\n  const trimmed = String(raw ?? \"\").trim().replace(/^\\/+/, \"\");\n  if (!trimmed) return null;\n  const safe = Array.from(trimmed)\n    .filter((char) => /[A-Za-z0-9_-]/.test(char))\n    .join(\"\");\n  return safe || null;\n}\n\nfunction escapeYamlScalar(value) {\n  return JSON.stringify(String(value ?? \"\"));\n}\n\nfunction serializeCommandFrontmatter(command) {\n  const template = String(command?.template ?? \"\").trim();\n  if (!template) {\n    throw new Error(\"command.template is required\");\n  }\n\n  let output = \"---\\n\";\n  if (typeof command?.description === \"string\" && command.description.trim()) {\n    output += `description: ${escapeYamlScalar(command.description.trim())}\\n`;\n  }\n  if (typeof command?.agent === \"string\" && command.agent.trim()) {\n    output += `agent: ${escapeYamlScalar(command.agent.trim())}\\n`;\n  }\n  if (typeof command?.model === \"string\" && command.model.trim()) {\n    output += `model: ${escapeYamlScalar(command.model.trim())}\\n`;\n  }\n  if (command?.subtask === true) {\n    output += \"subtask: true\\n\";\n  }\n  output += `---\\n\\n${template}\\n`;\n  return output;\n}","sourceCodeStart":1232,"sourceCodeEnd":1268,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/desktop/electron/main.mjs#L1232-L1268","documentation":"serializeCommandFrontmatter() converts a command definition into markdown with YAML frontmatter for export/sync. The template (the command body) is mandatory: if command.template is missing, empty, or only whitespace after String()+trim(), it throws this error rather than writing an empty command file.","triggerScenarios":"Exporting/writing a command whose object lacks a template field, has template: \"\" or \"   \", or passes null/undefined (command?.template ?? \"\" yields empty string).","commonSituations":"Manually authored command JSON missing the template key; an editor saved an empty template; deserialization dropping the field due to schema drift; importing commands from an older format.","solutions":["Set a non-empty template string on the command before export.","Validate command objects with a schema (e.g. Zod) requiring template before serializing.","Trim and check the template in the producing code path so empty commands never reach serialization.","Fix the source file/config where the command was defined to restore its template."],"exampleFix":"// before\nawait exportCommand({ name: 'deploy' }); // throws: no template\n// after\nawait exportCommand({ name: 'deploy', template: 'pnpm deploy --prod' });","handlingStrategy":"validation","validationCode":"if (typeof command?.template !== 'string' || !command.template.trim()) {\n  throw new TypeError('command.template must be a non-empty string');\n}","typeGuard":"function hasTemplate(c) {\n  return typeof c?.template === 'string' && c.template.trim().length > 0;\n}","tryCatchPattern":"try {\n  await serializeCommandFrontmatter(command);\n} catch (err) {\n  if (String(err.message) === 'command.template is required') {\n    console.error('Skipping command with empty template:', command?.name);\n  } else throw err;\n}","preventionTips":["Validate command objects with a schema before export.","Never construct command objects without a template.","Reject empty templates at the editor/save boundary.","Add a round-trip test exporting sample commands."],"tags":["validation","yaml","commands"],"backgroundTag":"missing-required-argument","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}