singularity-claude 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,301 @@
1
+ #!/usr/bin/env bash
2
+ # score-manager.sh — CLI for managing singularity skill scores
3
+ # Uses jq if available, falls back to node -e for JSON manipulation
4
+
5
+ set -euo pipefail
6
+
7
+ SINGULARITY_DATA="${HOME}/.claude/singularity"
8
+ SCORES_DIR="${SINGULARITY_DATA}/scores"
9
+
10
+ # JSON tool detection
11
+ json_tool=""
12
+ if command -v jq &>/dev/null; then
13
+ json_tool="jq"
14
+ elif command -v node &>/dev/null; then
15
+ json_tool="node"
16
+ else
17
+ echo "Error: Neither jq nor node found. Install one to use score-manager." >&2
18
+ exit 1
19
+ fi
20
+
21
+ # Atomic write: write to temp file, then rename
22
+ atomic_write() {
23
+ local target="$1"
24
+ local content="$2"
25
+ local tmp="${target}.tmp.$$"
26
+ printf '%s' "$content" > "$tmp"
27
+ mv "$tmp" "$target"
28
+ }
29
+
30
+ # Read JSON file and extract with jq or node
31
+ json_query() {
32
+ local file="$1"
33
+ local query="$2"
34
+ if [ "$json_tool" = "jq" ]; then
35
+ jq -r "$query" "$file"
36
+ else
37
+ node -e "const d=JSON.parse(require('fs').readFileSync('${file}','utf8')); const q=${query}; console.log(typeof q==='object'?JSON.stringify(q,null,2):q)"
38
+ fi
39
+ }
40
+
41
+ usage() {
42
+ cat <<'EOF'
43
+ Usage: score-manager.sh <command> <skill-name> [options]
44
+
45
+ Commands:
46
+ init <skill> Create score file for a new skill
47
+ add <skill> <score> Record a score (0-100)
48
+ [--version <ver>] Version (auto-detected from git tag or v1.0.0)
49
+ [--context <text>] What the skill was used for
50
+ [--strengths <json-array>] What went well
51
+ [--weaknesses <json-array>] What needs improvement
52
+ [--edge-cases <json-array>] Edge cases encountered
53
+ list <skill> Show score history
54
+ average <skill> [--version <v>] Get average score
55
+ trend <skill> Show score trend across versions
56
+ maturity <skill> Get current maturity level
57
+ EOF
58
+ exit 1
59
+ }
60
+
61
+ cmd_init() {
62
+ local skill="$1"
63
+ local file="${SCORES_DIR}/${skill}.json"
64
+
65
+ if [ -f "$file" ]; then
66
+ echo "Score file already exists for '${skill}'" >&2
67
+ exit 1
68
+ fi
69
+
70
+ mkdir -p "${SCORES_DIR}"
71
+ local now
72
+ now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
73
+
74
+ local content
75
+ content=$(cat <<INIT
76
+ {
77
+ "\$schema": "singularity-score-v1",
78
+ "skillName": "${skill}",
79
+ "versions": [
80
+ {
81
+ "version": "v1.0.0",
82
+ "gitTag": "singularity/${skill}/v1.0.0",
83
+ "scores": [],
84
+ "averageScore": 0,
85
+ "executionCount": 0,
86
+ "maturity": "draft"
87
+ }
88
+ ],
89
+ "currentVersion": "v1.0.0",
90
+ "createdAt": "${now}",
91
+ "lastScoredAt": null
92
+ }
93
+ INIT
94
+ )
95
+ atomic_write "$file" "$content"
96
+ echo "Initialized score file for '${skill}'"
97
+ }
98
+
99
+ cmd_add() {
100
+ local skill="$1"
101
+ local score="$2"
102
+ shift 2
103
+
104
+ # Parse optional args
105
+ local version="" context="" strengths="[]" weaknesses="[]" edge_cases="[]"
106
+ while [ $# -gt 0 ]; do
107
+ case "$1" in
108
+ --version) version="$2"; shift 2 ;;
109
+ --context) context="$2"; shift 2 ;;
110
+ --strengths) strengths="$2"; shift 2 ;;
111
+ --weaknesses) weaknesses="$2"; shift 2 ;;
112
+ --edge-cases) edge_cases="$2"; shift 2 ;;
113
+ *) shift ;;
114
+ esac
115
+ done
116
+
117
+ # Validate score
118
+ if ! [[ "$score" =~ ^[0-9]+$ ]] || [ "$score" -lt 0 ] || [ "$score" -gt 100 ]; then
119
+ echo "Error: Score must be 0-100" >&2
120
+ exit 1
121
+ fi
122
+
123
+ local file="${SCORES_DIR}/${skill}.json"
124
+ if [ ! -f "$file" ]; then
125
+ echo "Error: No score file for '${skill}'. Run 'init' first." >&2
126
+ exit 1
127
+ fi
128
+
129
+ local now
130
+ now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
131
+
132
+ # Use current version if not specified
133
+ if [ -z "$version" ]; then
134
+ version=$(jq -r '.currentVersion' "$file" 2>/dev/null || echo "v1.0.0")
135
+ fi
136
+
137
+ if [ "$json_tool" = "jq" ]; then
138
+ local updated
139
+ updated=$(jq --arg ver "$version" --argjson score "$score" --arg ts "$now" \
140
+ --arg ctx "$context" --argjson str "$strengths" --argjson weak "$weaknesses" \
141
+ --argjson edge "$edge_cases" '
142
+ .lastScoredAt = $ts |
143
+ (.versions[] | select(.version == $ver)) |= (
144
+ .scores += [{
145
+ "timestamp": $ts,
146
+ "score": $score,
147
+ "context": $ctx,
148
+ "strengths": $str,
149
+ "weaknesses": $weak,
150
+ "edgeCasesEncountered": $edge
151
+ }] |
152
+ .executionCount = (.scores | length) |
153
+ .averageScore = ((.scores | map(.score) | add) / (.scores | length) | floor)
154
+ )
155
+ ' "$file")
156
+ atomic_write "$file" "$updated"
157
+ else
158
+ node -e "
159
+ const fs = require('fs');
160
+ const d = JSON.parse(fs.readFileSync('${file}', 'utf8'));
161
+ const v = d.versions.find(v => v.version === '${version}');
162
+ if (!v) { console.error('Version not found'); process.exit(1); }
163
+ v.scores.push({
164
+ timestamp: '${now}', score: ${score}, context: '${context}',
165
+ strengths: ${strengths}, weaknesses: ${weaknesses},
166
+ edgeCasesEncountered: ${edge_cases}
167
+ });
168
+ v.executionCount = v.scores.length;
169
+ v.averageScore = Math.floor(v.scores.reduce((s,e) => s + e.score, 0) / v.scores.length);
170
+ d.lastScoredAt = '${now}';
171
+ fs.writeFileSync('${file}', JSON.stringify(d, null, 2));
172
+ "
173
+ fi
174
+
175
+ # Compute and update maturity
176
+ _update_maturity "$skill" "$version"
177
+
178
+ # Show result
179
+ local avg
180
+ avg=$(jq -r --arg ver "$version" '.versions[] | select(.version == $ver) | .averageScore' "$file" 2>/dev/null || echo "?")
181
+ local count
182
+ count=$(jq -r --arg ver "$version" '.versions[] | select(.version == $ver) | .executionCount' "$file" 2>/dev/null || echo "?")
183
+ echo "Recorded score ${score} for ${skill} ${version} (avg: ${avg}/100, ${count} runs)"
184
+ }
185
+
186
+ _update_maturity() {
187
+ local skill="$1"
188
+ local version="$2"
189
+ local file="${SCORES_DIR}/${skill}.json"
190
+
191
+ if [ "$json_tool" = "jq" ]; then
192
+ local updated
193
+ updated=$(jq --arg ver "$version" '
194
+ (.versions[] | select(.version == $ver)) |= (
195
+ .maturity = (
196
+ if .maturity == "crystallized" then "crystallized"
197
+ elif .executionCount >= 5 and .averageScore >= 80 and (.scores | map(.edgeCasesEncountered // []) | flatten | length) > 0 then "hardened"
198
+ elif .executionCount >= 3 and .averageScore >= 60 then "tested"
199
+ else "draft"
200
+ end
201
+ )
202
+ )
203
+ ' "$file")
204
+ atomic_write "$file" "$updated"
205
+ fi
206
+ }
207
+
208
+ cmd_list() {
209
+ local skill="$1"
210
+ local file="${SCORES_DIR}/${skill}.json"
211
+
212
+ if [ ! -f "$file" ]; then
213
+ echo "No score file for '${skill}'" >&2
214
+ exit 1
215
+ fi
216
+
217
+ if [ "$json_tool" = "jq" ]; then
218
+ jq -r '
219
+ .versions[] |
220
+ "Version: \(.version) | Maturity: \(.maturity) | Avg: \(.averageScore)/100 | Runs: \(.executionCount)",
221
+ (.scores[] | " [\(.timestamp)] Score: \(.score) — \(.context // "no context")")
222
+ ' "$file"
223
+ else
224
+ node -e "
225
+ const d = JSON.parse(require('fs').readFileSync('${file}', 'utf8'));
226
+ d.versions.forEach(v => {
227
+ console.log('Version: ' + v.version + ' | Maturity: ' + v.maturity + ' | Avg: ' + v.averageScore + '/100 | Runs: ' + v.executionCount);
228
+ v.scores.forEach(s => console.log(' [' + s.timestamp + '] Score: ' + s.score + ' — ' + (s.context || 'no context')));
229
+ });
230
+ "
231
+ fi
232
+ }
233
+
234
+ cmd_average() {
235
+ local skill="$1"
236
+ shift
237
+ local version=""
238
+ while [ $# -gt 0 ]; do
239
+ case "$1" in
240
+ --version) version="$2"; shift 2 ;;
241
+ *) shift ;;
242
+ esac
243
+ done
244
+
245
+ local file="${SCORES_DIR}/${skill}.json"
246
+ if [ ! -f "$file" ]; then
247
+ echo "No score file for '${skill}'" >&2
248
+ exit 1
249
+ fi
250
+
251
+ if [ -n "$version" ]; then
252
+ jq -r --arg ver "$version" '.versions[] | select(.version == $ver) | .averageScore' "$file"
253
+ else
254
+ jq -r '.versions[-1].averageScore' "$file"
255
+ fi
256
+ }
257
+
258
+ cmd_trend() {
259
+ local skill="$1"
260
+ local file="${SCORES_DIR}/${skill}.json"
261
+
262
+ if [ ! -f "$file" ]; then
263
+ echo "No score file for '${skill}'" >&2
264
+ exit 1
265
+ fi
266
+
267
+ jq -r '
268
+ .versions | to_entries[] |
269
+ "\(.value.version)\t\(.value.averageScore)\t\(.value.executionCount)\t\(.value.maturity)"
270
+ ' "$file" | while IFS=$'\t' read -r ver avg count mat; do
271
+ printf "%-10s avg: %3s/100 runs: %s maturity: %s\n" "$ver" "$avg" "$count" "$mat"
272
+ done
273
+ }
274
+
275
+ cmd_maturity() {
276
+ local skill="$1"
277
+ local file="${SCORES_DIR}/${skill}.json"
278
+
279
+ if [ ! -f "$file" ]; then
280
+ echo "No score file for '${skill}'" >&2
281
+ exit 1
282
+ fi
283
+
284
+ jq -r '.versions[-1].maturity' "$file"
285
+ }
286
+
287
+ # Main dispatch
288
+ [ $# -lt 2 ] && usage
289
+
290
+ cmd="$1"
291
+ shift
292
+
293
+ case "$cmd" in
294
+ init) cmd_init "$@" ;;
295
+ add) cmd_add "$@" ;;
296
+ list) cmd_list "$@" ;;
297
+ average) cmd_average "$@" ;;
298
+ trend) cmd_trend "$@" ;;
299
+ maturity) cmd_maturity "$@" ;;
300
+ *) usage ;;
301
+ esac
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env bash
2
+ # telemetry-writer.sh — CLI for singularity skill telemetry
3
+ # Writes structured JSON logs for skill execution auditing
4
+
5
+ set -euo pipefail
6
+
7
+ SINGULARITY_DATA="${HOME}/.claude/singularity"
8
+ TELEMETRY_DIR="${SINGULARITY_DATA}/telemetry"
9
+
10
+ usage() {
11
+ cat <<'EOF'
12
+ Usage: telemetry-writer.sh <command> <skill-name> [options]
13
+
14
+ Commands:
15
+ log <skill> [options] Record a telemetry entry
16
+ --trigger <type> How the skill was invoked (user-invoked, auto-repair, gap-detected)
17
+ --version <ver> Skill version (default: from registry)
18
+ --summary <text> What happened
19
+ --score <n> Score if available
20
+ --error <text> Error message if failed
21
+ --edge-case <text> Edge case encountered
22
+ --files-created <json-array> Files created
23
+ --files-modified <json-array> Files modified
24
+ --duration <ms> Execution duration in milliseconds
25
+
26
+ list <skill> [--last <n>] Show recent telemetry entries (default: 10)
27
+
28
+ replay <skill> <timestamp> Show full telemetry entry
29
+
30
+ prune [--days <n>] Remove entries older than n days (default: 90)
31
+ EOF
32
+ exit 1
33
+ }
34
+
35
+ cmd_log() {
36
+ local skill="$1"
37
+ shift
38
+
39
+ # Parse options
40
+ local trigger="user-invoked" version="" summary="" score="" error="" edge_case=""
41
+ local files_created="[]" files_modified="[]" duration="0"
42
+
43
+ while [ $# -gt 0 ]; do
44
+ case "$1" in
45
+ --trigger) trigger="$2"; shift 2 ;;
46
+ --version) version="$2"; shift 2 ;;
47
+ --summary) summary="$2"; shift 2 ;;
48
+ --score) score="$2"; shift 2 ;;
49
+ --error) error="$2"; shift 2 ;;
50
+ --edge-case) edge_case="$2"; shift 2 ;;
51
+ --files-created) files_created="$2"; shift 2 ;;
52
+ --files-modified) files_modified="$2"; shift 2 ;;
53
+ --duration) duration="$2"; shift 2 ;;
54
+ *) shift ;;
55
+ esac
56
+ done
57
+
58
+ # Auto-detect version from registry
59
+ if [ -z "$version" ] && [ -f "${SINGULARITY_DATA}/registry.json" ] && command -v jq &>/dev/null; then
60
+ version=$(jq -r --arg s "$skill" '.skills[$s].currentVersion // "v1.0.0"' "${SINGULARITY_DATA}/registry.json" 2>/dev/null || echo "v1.0.0")
61
+ fi
62
+ [ -z "$version" ] && version="v1.0.0"
63
+
64
+ local now
65
+ now=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
66
+ local short_id
67
+ short_id=$(head -c 4 /dev/urandom | xxd -p | head -c 8)
68
+ local date_part
69
+ date_part=$(date -u +"%Y-%m-%d-%H-%M-%S")
70
+
71
+ local skill_dir="${TELEMETRY_DIR}/${skill}"
72
+ mkdir -p "$skill_dir"
73
+
74
+ local filename="${date_part}-${short_id}.json"
75
+ local filepath="${skill_dir}/${filename}"
76
+
77
+ # Build score field
78
+ local score_field="null"
79
+ [ -n "$score" ] && score_field="$score"
80
+
81
+ # Build errors array
82
+ local errors_field="[]"
83
+ [ -n "$error" ] && errors_field="[\"$(printf '%s' "$error" | sed 's/"/\\"/g')\"]"
84
+
85
+ # Build edge cases array
86
+ local edge_cases_field="[]"
87
+ [ -n "$edge_case" ] && edge_cases_field="[\"$(printf '%s' "$edge_case" | sed 's/"/\\"/g')\"]"
88
+
89
+ cat > "$filepath" << ENTRY
90
+ {
91
+ "\$schema": "singularity-telemetry-v1",
92
+ "skillName": "${skill}",
93
+ "version": "${version}",
94
+ "timestamp": "${now}",
95
+ "trigger": "${trigger}",
96
+ "inputs": {},
97
+ "outputs": {
98
+ "filesCreated": ${files_created},
99
+ "filesModified": ${files_modified},
100
+ "summary": "$(printf '%s' "$summary" | sed 's/"/\\"/g')"
101
+ },
102
+ "duration_ms": ${duration},
103
+ "score": ${score_field},
104
+ "errors": ${errors_field},
105
+ "edgeCases": ${edge_cases_field},
106
+ "repairTriggered": false
107
+ }
108
+ ENTRY
109
+
110
+ echo "Telemetry logged: ${filepath}"
111
+ }
112
+
113
+ cmd_list() {
114
+ local skill="$1"
115
+ shift
116
+ local last=10
117
+
118
+ while [ $# -gt 0 ]; do
119
+ case "$1" in
120
+ --last) last="$2"; shift 2 ;;
121
+ *) shift ;;
122
+ esac
123
+ done
124
+
125
+ local skill_dir="${TELEMETRY_DIR}/${skill}"
126
+ if [ ! -d "$skill_dir" ]; then
127
+ echo "No telemetry for '${skill}'" >&2
128
+ exit 1
129
+ fi
130
+
131
+ # List most recent entries
132
+ ls -1t "$skill_dir"/*.json 2>/dev/null | head -n "$last" | while read -r f; do
133
+ if command -v jq &>/dev/null; then
134
+ jq -r '"[\(.timestamp)] \(.trigger) | score: \(.score // "n/a") | \(.outputs.summary // "no summary")"' "$f"
135
+ else
136
+ basename "$f"
137
+ fi
138
+ done
139
+ }
140
+
141
+ cmd_replay() {
142
+ local skill="$1"
143
+ local timestamp="$2"
144
+ local skill_dir="${TELEMETRY_DIR}/${skill}"
145
+
146
+ # Find matching file
147
+ local match
148
+ match=$(ls -1 "${skill_dir}/"*"${timestamp}"* 2>/dev/null | head -1)
149
+
150
+ if [ -z "$match" ]; then
151
+ echo "No telemetry entry matching '${timestamp}' for '${skill}'" >&2
152
+ exit 1
153
+ fi
154
+
155
+ if command -v jq &>/dev/null; then
156
+ jq '.' "$match"
157
+ else
158
+ cat "$match"
159
+ fi
160
+ }
161
+
162
+ cmd_prune() {
163
+ local days=90
164
+ while [ $# -gt 0 ]; do
165
+ case "$1" in
166
+ --days) days="$2"; shift 2 ;;
167
+ *) shift ;;
168
+ esac
169
+ done
170
+
171
+ local count=0
172
+ find "$TELEMETRY_DIR" -name "*.json" -mtime +"$days" -print0 2>/dev/null | while IFS= read -r -d '' f; do
173
+ rm "$f"
174
+ count=$((count + 1))
175
+ done
176
+ echo "Pruned ${count} entries older than ${days} days"
177
+ }
178
+
179
+ # Main dispatch
180
+ [ $# -lt 1 ] && usage
181
+
182
+ cmd="$1"
183
+ shift
184
+
185
+ case "$cmd" in
186
+ log) [ $# -lt 1 ] && usage; cmd_log "$@" ;;
187
+ list) [ $# -lt 1 ] && usage; cmd_list "$@" ;;
188
+ replay) [ $# -lt 2 ] && usage; cmd_replay "$@" ;;
189
+ prune) cmd_prune "$@" ;;
190
+ *) usage ;;
191
+ esac
@@ -0,0 +1,113 @@
1
+ ---
2
+ name: creating-skills
3
+ description: Use when a new reusable skill needs to be built, either detected by gap analysis, requested by the user, or triggered by /singularity-create
4
+ ---
5
+
6
+ # Create a New Skill
7
+
8
+ Build a new Claude Code skill through a structured workflow that ensures quality, testability, and integration with the singularity evolution engine.
9
+
10
+ ## Prerequisites
11
+
12
+ - Read `superpowers:writing-skills` if available — it defines SKILL.md authoring best practices
13
+ - This skill creates standard Claude Code skills usable by any plugin
14
+
15
+ ## Workflow
16
+
17
+ ### Step 1: Requirements Gathering
18
+
19
+ Ask the user ONE question at a time:
20
+
21
+ 1. **What** does this skill do? (core purpose in one sentence)
22
+ 2. **When** should it trigger? (symptoms, conditions, error messages)
23
+ 3. **What tools** does it need? (Read, Write, Edit, Bash, Agent, etc.)
24
+ 4. **What's the output?** (files created, code modified, analysis produced)
25
+
26
+ ### Step 2: Check Registry
27
+
28
+ Read `~/.claude/singularity/registry.json` to verify no duplicate or overlapping skill exists.
29
+
30
+ If a similar skill exists, ask: *"A skill called '<name>' already covers <overlap>. Should I extend it or create a separate skill?"*
31
+
32
+ ### Step 3: Generate SKILL.md
33
+
34
+ Create the skill following these conventions:
35
+
36
+ ```yaml
37
+ ---
38
+ name: <skill-name> # kebab-case, verb-first (e.g., creating-api-clients)
39
+ description: Use when <triggering conditions> # Max 500 chars, start with "Use when"
40
+ ---
41
+ ```
42
+
43
+ **Content structure:**
44
+ - Overview (1-2 sentences)
45
+ - When to use / when NOT to use
46
+ - Workflow steps (numbered, actionable)
47
+ - Common mistakes / red flags
48
+ - Integration with other skills (if applicable)
49
+
50
+ **Rules:**
51
+ - Description = triggering conditions ONLY, not what the skill does
52
+ - Keep under 500 words for frequently-used skills
53
+ - Use cross-references (`superpowers:skill-name`) not file paths
54
+ - Include a "When NOT to use" section
55
+
56
+ ### Step 4: Write the Skill
57
+
58
+ Write to `~/.claude/skills/<skill-name>/SKILL.md`
59
+
60
+ If the skill needs supporting files (templates, rubrics, scripts), create them in:
61
+ `~/.claude/skills/<skill-name>/references/`
62
+
63
+ ### Step 5: Register
64
+
65
+ Update `~/.claude/singularity/registry.json`:
66
+
67
+ ```bash
68
+ # Using score-manager to initialize scoring
69
+ "${CLAUDE_PLUGIN_ROOT}/scripts/score-manager.sh" init <skill-name>
70
+ ```
71
+
72
+ Then update registry.json to add the skill entry:
73
+ ```json
74
+ {
75
+ "skills": {
76
+ "<skill-name>": {
77
+ "location": "~/.claude/skills/<skill-name>/SKILL.md",
78
+ "createdBy": "singularity-claude:creating-skills",
79
+ "createdAt": "<ISO-8601>",
80
+ "currentVersion": "v1.0.0",
81
+ "maturity": "draft",
82
+ "tags": ["<relevant>", "<tags>"],
83
+ "lastExecuted": null,
84
+ "executionCount": 0,
85
+ "averageScore": 0
86
+ }
87
+ }
88
+ }
89
+ ```
90
+
91
+ ### Step 6: Initial Test
92
+
93
+ Invoke the newly created skill via the `Skill` tool to verify it loads correctly.
94
+
95
+ ### Step 7: Initial Score
96
+
97
+ Run `singularity-claude:scoring` on the test output to establish a baseline score.
98
+
99
+ ### Step 8: Log Telemetry
100
+
101
+ ```bash
102
+ "${CLAUDE_PLUGIN_ROOT}/scripts/telemetry-writer.sh" log <skill-name> \
103
+ --trigger "creation" \
104
+ --summary "Created new skill: <description>"
105
+ ```
106
+
107
+ ## Output
108
+
109
+ After creation, report:
110
+ - Skill location: `~/.claude/skills/<skill-name>/SKILL.md`
111
+ - Initial version: v1.0.0
112
+ - Maturity: draft
113
+ - Next steps: use the skill, then score with `/singularity-score`
@@ -0,0 +1,17 @@
1
+ {
2
+ "$schema": "singularity-score-v1",
3
+ "skillName": "{{SKILL_NAME}}",
4
+ "versions": [
5
+ {
6
+ "version": "v1.0.0",
7
+ "gitTag": "singularity/{{SKILL_NAME}}/v1.0.0",
8
+ "scores": [],
9
+ "averageScore": 0,
10
+ "executionCount": 0,
11
+ "maturity": "draft"
12
+ }
13
+ ],
14
+ "currentVersion": "v1.0.0",
15
+ "createdAt": "{{TIMESTAMP}}",
16
+ "lastScoredAt": null
17
+ }
@@ -0,0 +1,36 @@
1
+ ---
2
+ name: {{SKILL_NAME}}
3
+ description: Use when {{TRIGGERING_CONDITIONS}}
4
+ ---
5
+
6
+ # {{SKILL_TITLE}}
7
+
8
+ {{OVERVIEW — 1-2 sentences describing the core purpose}}
9
+
10
+ ## When to Use
11
+
12
+ - {{Symptom or condition 1}}
13
+ - {{Symptom or condition 2}}
14
+
15
+ ## When NOT to Use
16
+
17
+ - {{Anti-pattern or wrong context}}
18
+
19
+ ## Workflow
20
+
21
+ ### Step 1: {{First action}}
22
+
23
+ {{Instructions}}
24
+
25
+ ### Step 2: {{Second action}}
26
+
27
+ {{Instructions}}
28
+
29
+ ## Common Mistakes
30
+
31
+ - **{{Mistake}}** — {{Why it's wrong and what to do instead}}
32
+
33
+ ## Red Flags
34
+
35
+ - Never {{dangerous action}}
36
+ - Always {{safety measure}}