mirror of
https://github.com/OpenClaudia/openclaudia-skills.git
synced 2026-09-19 08:06:49 +08:00
Document allowed-tools field, fix CLI double-clone, add descriptions to list
- Document allowed-tools YAML frontmatter field in CONTRIBUTING.md - Fix install --all cloning repo twice (now clones once and reuses) - Show skill descriptions from YAML frontmatter in list command - Delete merged skill/linkedin-ads branch Closes #3, #4, #5, #6 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -34,6 +34,7 @@ Every skill is a single `SKILL.md` file with YAML frontmatter and detailed instr
|
||||
---
|
||||
name: your-skill-name
|
||||
description: One-line description of what this skill does (shown in skill list)
|
||||
allowed-tools: Bash
|
||||
---
|
||||
|
||||
# Your Skill Name
|
||||
@@ -57,6 +58,21 @@ Step-by-step instructions for the agent:
|
||||
List any API keys needed and how to configure them.
|
||||
```
|
||||
|
||||
### Frontmatter fields
|
||||
|
||||
| Field | Required | Description |
|
||||
|-------|----------|-------------|
|
||||
| `name` | Yes | Skill name (lowercase, hyphenated). Becomes the slash command: `/your-skill-name` |
|
||||
| `description` | Yes | One-line description shown in `npx openclaudia list` |
|
||||
| `allowed-tools` | No | Comma-separated list of tools the skill needs access to (e.g., `Bash`, `Read`, `Write`). Use this when your skill needs to run shell commands (curl, API calls) or perform file operations. If omitted, the skill can only generate text responses. |
|
||||
|
||||
**When to use `allowed-tools`:**
|
||||
- `Bash` — skill makes API calls via curl, runs CLI tools, or executes shell commands
|
||||
- `Read` — skill needs to read files from the user's project
|
||||
- `Write` — skill creates or modifies files
|
||||
|
||||
Example: a skill that sends emails via the Resend API needs `allowed-tools: Bash` to execute curl commands.
|
||||
|
||||
### 4. Skill authoring guidelines
|
||||
|
||||
- **Be specific** — the more precise your instructions, the better the agent performs
|
||||
|
||||
+27
-11
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
import { execSync } from "node:child_process";
|
||||
import { existsSync, mkdirSync, cpSync, rmSync } from "node:fs";
|
||||
import { existsSync, mkdirSync, cpSync, rmSync, readFileSync } from "node:fs";
|
||||
import { readdirSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { homedir, tmpdir } from "node:os";
|
||||
@@ -48,10 +48,22 @@ function getAvailableSkills(repoDir) {
|
||||
});
|
||||
}
|
||||
|
||||
function installSkills(skillNames) {
|
||||
const tmpDir = cloneRepo();
|
||||
const repoSkillsDir = join(tmpDir, "skills");
|
||||
const available = getAvailableSkills(tmpDir);
|
||||
function getSkillDescription(repoDir, skillName) {
|
||||
const skillFile = join(repoDir, "skills", skillName, "SKILL.md");
|
||||
try {
|
||||
const content = readFileSync(skillFile, "utf-8");
|
||||
const match = content.match(/^---\s*\n([\s\S]*?)\n---/);
|
||||
if (match) {
|
||||
const descMatch = match[1].match(/^description:\s*(.+)$/m);
|
||||
if (descMatch) return descMatch[1].trim().replace(/^["']|["']$/g, "");
|
||||
}
|
||||
} catch {}
|
||||
return "";
|
||||
}
|
||||
|
||||
function installSkillsFromDir(repoDir, skillNames) {
|
||||
const repoSkillsDir = join(repoDir, "skills");
|
||||
const available = getAvailableSkills(repoDir);
|
||||
|
||||
if (!existsSync(SKILLS_DIR)) {
|
||||
mkdirSync(SKILLS_DIR, { recursive: true });
|
||||
@@ -74,7 +86,6 @@ function installSkills(skillNames) {
|
||||
installed++;
|
||||
}
|
||||
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
return installed;
|
||||
}
|
||||
|
||||
@@ -89,7 +100,10 @@ if (command === "list") {
|
||||
console.log(`\n ${skills.length} available skills:\n`);
|
||||
for (const s of skills.sort()) {
|
||||
const installed = existsSync(join(SKILLS_DIR, s));
|
||||
console.log(` ${installed ? "[installed]" : " "} ${s}`);
|
||||
const desc = getSkillDescription(tmpDir, s);
|
||||
const status = installed ? "[installed]" : " ";
|
||||
const descStr = desc ? ` ${desc}` : "";
|
||||
console.log(` ${status} ${s.padEnd(24)}${descStr}`);
|
||||
}
|
||||
console.log();
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
@@ -104,20 +118,22 @@ if (command === "install") {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const tmpDir = cloneRepo();
|
||||
|
||||
if (targets.includes("--all")) {
|
||||
const tmpDir = cloneRepo();
|
||||
const all = getAvailableSkills(tmpDir);
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
console.log(`\nInstalling all ${all.length} skills to ${SKILLS_DIR}...\n`);
|
||||
const count = installSkills(all);
|
||||
const count = installSkillsFromDir(tmpDir, all);
|
||||
console.log(`\nDone! ${count} skills installed.`);
|
||||
console.log(`Skills directory: ${SKILLS_DIR}`);
|
||||
console.log(`\nRun "claude" and try /write-blog or /seo-audit to get started.\n`);
|
||||
} else {
|
||||
console.log(`\nInstalling ${targets.length} skill(s) to ${SKILLS_DIR}...\n`);
|
||||
const count = installSkills(targets);
|
||||
const count = installSkillsFromDir(tmpDir, targets);
|
||||
console.log(`\nDone! ${count} skill(s) installed.\n`);
|
||||
}
|
||||
|
||||
rmSync(tmpDir, { recursive: true, force: true });
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user