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:
Quanlai Li
2026-02-19 17:14:01 -08:00
parent aa588c97fe
commit b9ebf27f1f
2 changed files with 43 additions and 11 deletions
+16
View File
@@ -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
View File
@@ -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);
}