mirror of
https://github.com/glittercowboy/get-shit-done
synced 2026-04-25 17:25:23 +02:00
feat(config): support global skills from ~/.claude/skills/ in agent_skills (#1992)
Add global: prefix for agent_skills config entries that resolve to
~/.claude/skills/<name>/SKILL.md instead of the project root. This
allows injecting globally-installed skills (e.g., shadcn, supabase)
into GSD sub-agents without duplicating them into every project.
Example config:
"agent_skills": {
"gsd-executor": ["global:shadcn", "global:supabase-postgres"]
}
Security: skill names are validated against /^[a-zA-Z0-9_-]+$/ to
prevent path traversal. The ~/.claude/skills/ directory is a trusted
runtime-controlled location. Project-relative paths continue to use
validatePath() containment checks as before.
Closes #1992
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1470,6 +1470,24 @@ function buildAgentSkillsBlock(config, agentType, projectRoot) {
|
||||
for (const skillPath of skillPaths) {
|
||||
if (typeof skillPath !== 'string') continue;
|
||||
|
||||
// Support global: prefix for skills installed at ~/.claude/skills/ (#1992)
|
||||
if (skillPath.startsWith('global:')) {
|
||||
const skillName = skillPath.slice(7);
|
||||
// Sanitize: skill name must be alphanumeric, hyphens, or underscores only
|
||||
if (!/^[a-zA-Z0-9_-]+$/.test(skillName)) {
|
||||
process.stderr.write(`[agent-skills] WARNING: Invalid global skill name "${skillName}" — skipping\n`);
|
||||
continue;
|
||||
}
|
||||
const globalSkillDir = path.join(require('os').homedir(), '.claude', 'skills', skillName);
|
||||
const globalSkillMd = path.join(globalSkillDir, 'SKILL.md');
|
||||
if (!fs.existsSync(globalSkillMd)) {
|
||||
process.stderr.write(`[agent-skills] WARNING: Global skill not found at "~/.claude/skills/${skillName}/SKILL.md" — skipping\n`);
|
||||
continue;
|
||||
}
|
||||
validPaths.push({ ref: `${globalSkillDir}/SKILL.md`, display: `~/.claude/skills/${skillName}` });
|
||||
continue;
|
||||
}
|
||||
|
||||
// Validate path safety — must resolve within project root
|
||||
const pathCheck = validatePath(skillPath, projectRoot);
|
||||
if (!pathCheck.safe) {
|
||||
@@ -1484,12 +1502,12 @@ function buildAgentSkillsBlock(config, agentType, projectRoot) {
|
||||
continue;
|
||||
}
|
||||
|
||||
validPaths.push(skillPath);
|
||||
validPaths.push({ ref: `${skillPath}/SKILL.md`, display: skillPath });
|
||||
}
|
||||
|
||||
if (validPaths.length === 0) return '';
|
||||
|
||||
const lines = validPaths.map(p => `- @${p}/SKILL.md`).join('\n');
|
||||
const lines = validPaths.map(p => `- @${p.ref}`).join('\n');
|
||||
return `<agent_skills>\nRead these user-configured skills:\n${lines}\n</agent_skills>`;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user