mirror of
https://github.com/waynesutton/markdown-site.git
synced 2026-01-12 04:09:14 +00:00
feat(copy-dropdown): update skill export to Anthropic Agent Skills format
- Change download filename from {slug}-skill.md to SKILL.md
- Add YAML frontmatter with name and description fields
- Generate compliant skill name from slug (lowercase, hyphens, max 64 chars)
- Build description with "when to use" triggers (max 1024 chars)
- Structure content with ## Instructions and ## Examples sections
- Update UI text to "Download as SKILL.md" with "Anthropic Agent Skills format"
This commit is contained in:
3
TASK.md
3
TASK.md
@@ -2,10 +2,13 @@
|
||||
|
||||
## To Do
|
||||
|
||||
- [ ] add componet fork fix for stats
|
||||
- [ ] Add blog page list and config
|
||||
- [ ] add github code block
|
||||
- [ ] add home to mobile menu
|
||||
- [ ] Add markdown write page with copy option
|
||||
- [ ] create a ui site config page
|
||||
- [ ] create a prompt formator or skill or agent to change everything at once after forking
|
||||
- [ ] Add app background image option
|
||||
|
||||
## Current Status
|
||||
|
||||
@@ -88,27 +88,59 @@ function formatAsMarkdown(props: CopyPageDropdownProps): string {
|
||||
return markdown;
|
||||
}
|
||||
|
||||
// Format content as an Agent Skill file for AI agents
|
||||
// Generate a valid skill name (lowercase, hyphens, max 64 chars)
|
||||
function generateSkillName(slug: string): string {
|
||||
return slug
|
||||
.toLowerCase()
|
||||
.replace(/[^a-z0-9-]/g, "-")
|
||||
.replace(/-+/g, "-")
|
||||
.replace(/^-|-$/g, "")
|
||||
.slice(0, 64);
|
||||
}
|
||||
|
||||
// Format content as an Anthropic Agent Skill file (SKILL.md format)
|
||||
// Follows: https://platform.claude.com/docs/en/agents-and-tools/agent-skills/overview
|
||||
function formatAsSkill(props: CopyPageDropdownProps): string {
|
||||
const { title, content, url, description, tags } = props;
|
||||
const { title, content, slug, description, tags } = props;
|
||||
|
||||
const generatedDate = new Date().toISOString().split("T")[0];
|
||||
const tagList = tags && tags.length > 0 ? tags.join(", ") : "none";
|
||||
// Generate compliant skill name
|
||||
const skillName = generateSkillName(slug);
|
||||
|
||||
let skill = `# ${title}\n\n`;
|
||||
skill += `## Metadata\n`;
|
||||
skill += `- Source: ${url}\n`;
|
||||
skill += `- Tags: ${tagList}\n`;
|
||||
skill += `- Generated: ${generatedDate}\n\n`;
|
||||
// Build description with "when to use" triggers (max 1024 chars)
|
||||
const tagList = tags && tags.length > 0 ? tags.join(", ") : "";
|
||||
let skillDescription = description || `Guide about ${title.toLowerCase()}.`;
|
||||
|
||||
if (description) {
|
||||
skill += `## When to use this skill\n`;
|
||||
skill += `${description}\n\n`;
|
||||
// Add usage triggers to description
|
||||
if (tagList) {
|
||||
skillDescription += ` Use when working with ${tagList.toLowerCase()} or when asked about ${title.toLowerCase()}.`;
|
||||
} else {
|
||||
skillDescription += ` Use when asked about ${title.toLowerCase()}.`;
|
||||
}
|
||||
|
||||
skill += `## Instructions\n`;
|
||||
// Truncate description if needed (max 1024 chars)
|
||||
if (skillDescription.length > 1024) {
|
||||
skillDescription = skillDescription.slice(0, 1021) + "...";
|
||||
}
|
||||
|
||||
// Build YAML frontmatter (required by Agent Skills spec)
|
||||
let skill = `---\n`;
|
||||
skill += `name: ${skillName}\n`;
|
||||
skill += `description: ${skillDescription}\n`;
|
||||
skill += `---\n\n`;
|
||||
|
||||
// Add title
|
||||
skill += `# ${title}\n\n`;
|
||||
|
||||
// Add instructions section
|
||||
skill += `## Instructions\n\n`;
|
||||
skill += content;
|
||||
|
||||
// Add examples section placeholder if content doesn't include examples
|
||||
if (!content.toLowerCase().includes("## example")) {
|
||||
skill += `\n\n## Examples\n\n`;
|
||||
skill += `Use this skill when the user asks about topics covered in this guide.\n`;
|
||||
}
|
||||
|
||||
return skill;
|
||||
}
|
||||
|
||||
@@ -300,16 +332,16 @@ export default function CopyPageDropdown(props: CopyPageDropdownProps) {
|
||||
}
|
||||
};
|
||||
|
||||
// Handle download skill file
|
||||
// Handle download skill file (Anthropic Agent Skills format)
|
||||
const handleDownloadSkill = () => {
|
||||
const skillContent = formatAsSkill(props);
|
||||
const blob = new Blob([skillContent], { type: "text/markdown;charset=utf-8" });
|
||||
const url = URL.createObjectURL(blob);
|
||||
|
||||
// Create temporary link and trigger download
|
||||
// Create temporary link and trigger download as SKILL.md
|
||||
const link = document.createElement("a");
|
||||
link.href = url;
|
||||
link.download = `${props.slug}-skill.md`;
|
||||
link.download = "SKILL.md";
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
document.body.removeChild(link);
|
||||
@@ -445,7 +477,7 @@ export default function CopyPageDropdown(props: CopyPageDropdownProps) {
|
||||
</div>
|
||||
</button>
|
||||
|
||||
{/* Generate Skill option */}
|
||||
{/* Download as SKILL.md option (Anthropic Agent Skills format) */}
|
||||
<button
|
||||
className="copy-page-item"
|
||||
onClick={handleDownloadSkill}
|
||||
@@ -455,10 +487,10 @@ export default function CopyPageDropdown(props: CopyPageDropdownProps) {
|
||||
<Download size={16} className="copy-page-icon" aria-hidden="true" />
|
||||
<div className="copy-page-item-content">
|
||||
<span className="copy-page-item-title">
|
||||
Generate Skill
|
||||
Download as SKILL.md
|
||||
</span>
|
||||
<span className="copy-page-item-desc">
|
||||
Download as AI agent skill
|
||||
Anthropic Agent Skills format
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user