different-ai/openwork · error
skill name must be kebab-case
Error message
skill name must be kebab-case
What it means
validateSkillName() enforces that a skill's directory/name is lowercase kebab-case: non-empty and matching /^[a-z0-9]+(?:-[a-z0-9]+)*$/. Names with uppercase, spaces, underscores, leading/trailing hyphens, or empty strings throw this error.
Source
Thrown at apps/desktop/electron/main.mjs:1273
output += `description: ${escapeYamlScalar(command.description.trim())}\n`;
}
if (typeof command?.agent === "string" && command.agent.trim()) {
output += `agent: ${escapeYamlScalar(command.agent.trim())}\n`;
}
if (typeof command?.model === "string" && command.model.trim()) {
output += `model: ${escapeYamlScalar(command.model.trim())}\n`;
}
if (command?.subtask === true) {
output += "subtask: true\n";
}
output += `---\n\n${template}\n`;
return output;
}
function validateSkillName(raw) {
const trimmed = String(raw ?? "").trim();
if (!trimmed || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(trimmed)) {
throw new Error("skill name must be kebab-case");
}
return trimmed;
}
const runtimeManager = createRuntimeManager({
app,
desktopRoot: path.resolve(__dirname, ".."),
listLocalWorkspacePaths: () => workspaceStore.listLocalWorkspacePaths(),
// When OPENWORK_ENCRYPTION_KEY is set, skip the safeStorage provider so it does not shadow the documented env override used by CI/headless/enterprise.
localManagedMcpVaultKey: process.env.OPENWORK_ENCRYPTION_KEY?.trim()
? undefined
: createDesktopVaultKeyProvider({
filePath: path.join(app.getPath("userData"), "local-managed-mcp-vault-key.bin"),
loadSafeStorage: () => require("electron").safeStorage,
}),
});
const initialRunnerBootstrap = workspaceStore.readDesktopBootstrapConfigSync();
const legacyRunnerBaseUrls = [View on GitHub (pinned to 2b7df46e8a)
Solutions
- Rename the skill to lowercase kebab-case, e.g. "My Skill" → "my-skill".
- Replace underscores with hyphens and strip leading/trailing hyphens.
- Slugify the name before validation: lowercase, replace non-alphanumerics with '-', collapse repeats.
- Sanitize at the creation entry point so invalid names are rejected or transformed before persisting.
Example fix
// before
validateSkillName('My_Cool Skill'); // throws
// after
const name = 'My_Cool Skill'
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-+|-+$/g, '');
validateSkillName(name); // 'my-cool-skill' Defensive patterns
Strategy: validation
Validate before calling
const KEBAB = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
if (!KEBAB.test(name.trim())) throw new TypeError('skill name must be kebab-case'); Type guard
function isKebabCase(v) {
return typeof v === 'string' && /^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(v);
} Try / catch
try {
validateSkillName(rawName);
} catch (err) {
if (String(err.message) === 'skill name must be kebab-case') {
console.error('Invalid skill name:', rawName, '→ use lowercase-with-hyphens');
} else throw err;
} Prevention
- Slugify names at creation: lowercase, strip non [a-z0-9-], collapse hyphens.
- Show kebab-case hinting in any skill naming UI.
- Reject names at input time, not at validation time.
- Add unit tests for spaces, underscores, uppercase, and edge hyphens.
When it happens
Trigger: Creating, importing, or syncing a skill whose name is "My Skill", "my_skill", "MySkill", "-skill", "skill-", or an empty/undefined value passed to validateSkillName().
Common situations: Users naming skills with spaces or CamelCase in the UI; importing skills from external sources that allow other conventions (e.g. snake_case); filesystem-derived names with non-ASCII characters; refactors leaving name undefined.
Related errors
- invalid_env_key
- invalid_skill_name
- Agent Skill name must match its parent directory.
- command.name is required
- Agent context diagnostics timeout must be between 1 ms and 3
AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01).
Data as JSON: /api/errors/8e05ba481d0f84f5.
Report an issue: GitHub.