skill-creator
Create a new IWE skill with proper frontmatter, gates, scaffold and verification. Use when the pilot says: /skill-creator or «создай скилл <name>». The skill enforces WP Gate precondition, Routing Gate, IntegrationGate hard-check, collects parameters in 4 short steps, generates a
Install
npx skills add https://github.com/TserenTserenov/FMT-exocortex-template/tree/main/.claude/skills/skill-creator
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install tserentserenov-fmt-exocortex-template@llmmart
git clone https://github.com/TserenTserenov/FMT-exocortex-template.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole tserentserenov/fmt-exocortex-template collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
/skill-creator — create an IWE skill
Scope: create a new skill OR guide an update to an existing skill in
.claude/skills/or.kimi/skills/. Not in scope: full re-scaffold without deleting the oldSKILL.mdfirst (delete manually, then call/skill-creatoragain); creating a WP; creating a Pack. Role: ad-hoc content-role «Инженер скиллов»; formalize in Pack if ≥3 skills/year.
When to use
- Pilot wants a new skill for a repeated workflow.
- A new tool/agent/system needs a Service Clause + Role + SKILL.md.
- A skill needs promotion from author repo to
FMT-exocortex-template.
Preconditions (checked, not performed)
- WP Gate precondition. The task must be attached to an agreed WP in the weekly plan or explicitly named by the pilot.
/skill-creatordoes not conduct the WP Gate ritual itself. - Routing Gate. Decide target platform (Claude vs Kimi) and level (project vs user). Default: project-level
.claude/skills/in the author repo. - IntegrationGate hard-check.
DP.SC.*andDP.ROLE.*must exist in the PACK repo. If not, the skill stops and offers to create them. Bypass only by explicit pilot instruction «пропусти gate» — no code flag.
Algorithm
Step 1 — Check WP Gate precondition
Look up the current weekly plan (current/WeekPlan W{N}.md) or ask:
К какому РП привязано создание скилла?
If no WP is named and none matches the skill topic → stop:
Создание скилла требует согласованного РП. Сначала откройте РП через WP Gate.
Step 2 — Routing Gate
Ask or infer:
| Question | Default |
|---|---|
| Claude или Kimi? | Claude |
| project-level или user-level? | project-level |
| governance-репо для учёта? | ${IWE_GOVERNANCE_REPO:-DS-strategy} |
Target path:
- Claude project:
.claude/skills/<name>/ - Kimi project:
.kimi/skills/<name>/ - User level:
~/.claude/skills/<name>/or~/.kimi/skills/<name>/
Step 2.5 — Detect existing skill
Check whether <target_path>/SKILL.md already exists.
If it exists → switch to update mode. Do NOT re-scaffold. Show the pilot:
Скилл <name> уже существует (версия X.Y.Z).
Что обновить?
[ ] description
[ ] slash / phrase triggers
[ ] version bump (current: X.Y.Z → new: ?)
[ ] algorithm step (add / edit)
[ ] bundled resource (add scripts/ references/ assets/)
[ ] полный пересоздать → удалите SKILL.md вручную, затем запустите /skill-creator снова
[ ] отмена → ничего не менять
Collect the pilot's choices. Apply changes directly to the existing SKILL.md via Edit.
Skip Steps 3–6 unless the pilot selected "bundled resource" or any change that expands the skill's scope or gates — in that case, run Step 3 (IntegrationGate) before applying.
For Step 7 (register + verify): run verify-skill.sh always. Run generate-skills-catalog.sh only if frontmatter changed (name, description, triggers, version).
Version bump rule: bump patch for trigger / description edits; bump minor for algorithm changes or adding a bundled resource; bump major for gate or scope changes.
If it does not exist → continue to Step 3 (normal creation flow).
Step 3 — IntegrationGate
Check PACK repo for files matching DP.SC.* and DP.ROLE.*. If missing:
Service Clause (DP.SC.*) и Role (DP.ROLE.*) не найдены.
Создайте их сейчас через /pack-new или соответствующий процесс.
Для продолжения без них скажите явно: «пропусти gate».
Stop until the gate is satisfied or explicitly bypassed by pilot words.
Step 4 — Collect parameters (4 short steps)
4a. Name and description
Имя скилла (hyphen-case): <name>
Краткое описание — что делает и когда использовать:
4b. Agents and interaction axes
agents: single | multi
interaction: one-shot | multi-step
4c. Triggers
slash-команды (через запятую):
фразовые триггеры (через запятую):
Keep phrase triggers narrow: include a skill name placeholder to avoid accidental activation.
4d. Bundled resources
Какие bundled resources нужны?
[ ] scripts/
[ ] references/
[ ] assets/
Default: assets/ for scaffold template, scripts/ for verify script.
Step 5 — Generate scaffold
Choose scaffold template based on skill complexity:
- Minimal (
assets/skill-scaffold-minimal.md): single-step skills without external gates - Full (
assets/skill-scaffold-full.md): multi-step skills with Preconditions and Bundled resources
Copy chosen template to target path and substitute:
{{name}},{{description}},{{version}}(default0.1.0),{{status}}(defaultexperimental){{agents}},{{interaction}},{{layer}}{{slash_triggers}},{{phrase_triggers}}{{gates_rationale}}— required whengates_requiredandgates_enforcedare both empty
Create selected bundled resource directories with placeholder files.
Step 6 — Show draft
Print generated SKILL.md and file list to stdout. No P5 question. Pilot can cancel with:
/skill-creator undo
Undo works only before next commit or within 15 minutes.
Step 7 — Write files, register, verify
Write files to target path. Then regenerate the catalog and run verify:
bash scripts/generate-skills-catalog.sh # register in skills-catalog.yaml
bash scripts/verify-skill.sh <name> # 33-point structural check
Both commands must pass before the skill is considered created.
Tell the user where the new skill lives and that nothing preserves it (issue #873): a
project-local skill under .claude/skills/<name>/ is usually outside git and outside the
day-close.sh backup, and update.sh neither erases nor carries it over. Until the template
owner picks a backup model, suggest keeping a copy in a git repository the user controls.
For skills with interaction: multi-step: run /vdv audit on the Algorithm section.
Not a gate — does not block creation — but catches steps with missing Input/Output linkage
before the skill is used in practice.
Bundled resources
assets/skill-scaffold-minimal.md— scaffold for single-step skills without external gatesassets/skill-scaffold-full.md— scaffold for multi-step skills with Preconditions and Bundled resourcesscripts/verify-skill.sh— validates frontmatter, gates fields, bundled resource existence, L1 location
Known schema gaps
Fields used by some existing skills but not yet in the standard frontmatter schema:
argument-hint— CLI-style hint for script-executor skills (e.g. agent-fault, apply-captures). Encodes the argument contract. Keep until schema is extended or absorbed intodescription.routing.executor— indicates whether the skill runs viascript,sonnet, or another executor. Useful for the dispatcher but not validated byverify-skill.sh. Candidate for standardization.
Until standardized: leave these fields as-is in existing skills; do not remove during Step 2.5 updates.
Known tool gaps
verify-skill.shL1 location check for.kimi/skills/:check_l1_locationonly checksFMT-exocortex-template/.claude/skills/. For skills placed at.kimi/skills/(platform:kimi), the L1 location check is skipped whenlayer: L2, or produces a spurious FAIL whenlayer: L1. Until verify-skill.sh is extended with a--platform kimiflag, uselayer: L2for.kimi/skills/test skills, and document any intentional L1 Kimi skills separately.content-audit.shcoverage (Ф9): audit script checks 5 structural criteria (gates_rationale, Algorithm section, step headings ≥3, step content ≥2 lines, When-to-use section). 7 YELLOW skills (single C3 issue) are simple alias/mode skills without numbered step headings. This is structural noise, not content error — these skills are functionally correct. Seescripts/content-audit.shfor full output.
Anti-patterns
- Do not create a skill without a linked WP.
- Do not bypass IntegrationGate with a code flag.
- Do not put wide phrase triggers like «надо сделать скилл».
- Run
generate-skills-catalog.shafter writing files (Step 7) — not before, not manually. - Do not make the skill verify itself; use
scripts/verify-skill.sh. - Do not skip
verify-skill.shafter editing an existing skill — always run it after any update. - Do not re-scaffold for minor updates (triggers, description, version bump, algorithm); use Step 2.5 update mode instead. Exception: platform or layer change (e.g. Claude→Kimi, L1→L3) requires a new path and a fresh scaffold — delete old SKILL.md first.
- Do not forget version bump when changing gates, scope, or algorithm steps (bump minor or major).
Verification
After creation, run:
bash scripts/verify-skill.sh <skill-name>
Expected result: PASS with checks for: valid YAML frontmatter, non-empty description, recognized triggers, gates_required/gates_enforced fields with valid enum values, bundled resource files exist, scaffold templates valid, L1 skills present in FMT.
Files (fmt-exocortex-template)
-
assets
-
skill-scaffold-full.md 1.6 KB
--- name: {{name}} description: | {{description}} version: {{version}} status: {{status}} layer: {{layer}} agents: {{agents}} interaction: {{interaction}} gates_required: {{gates_required}} gates_enforced: {{gates_enforced}} gates_rationale: "{{gates_rationale}}" triggers: slash: {{slash_triggers}} phrases: {{phrase_triggers}} --- # /{{name}} > **Scope:** <one-sentence scope> > **Not in scope:** <what this skill does NOT do> > **Role:** <content-role that uses this skill> ## When to use - <trigger situation 1> - <trigger situation 2> - <trigger situation 3> ## Preconditions 1. **WP Gate precondition.** The task must be attached to an agreed WP in the weekly plan. 2. <additional gate or precondition> ## Algorithm <!-- Each step: Input (what must be ready), Action (what the agent does), Output (artifact or state produced). For multi-step skills, run /vdv audit on this section before finalizing. --> ### Step 1 — <action> Input: <what must be ready at this step> Action: <what the agent does> Output: <artifact or state produced> ### Step 2 — <action> Input: <output of step 1 + anything else> Action: <what the agent does> Output: <artifact or state produced> ### Step 3 — <action> Input: <output of step 2 + anything else> Action: <what the agent does> Output: <artifact or state produced> ## Bundled resources - `scripts/` — <what scripts do> - `assets/` — <what assets contain> ## Anti-patterns - <anti-pattern 1> - <anti-pattern 2> - <anti-pattern 3> ## Verification <how to verify the skill works; reference verify-skill.sh if applicable> -
skill-scaffold-minimal.md 696 B
--- name: {{name}} description: | {{description}} version: {{version}} status: {{status}} layer: {{layer}} agents: {{agents}} interaction: {{interaction}} gates_required: {{gates_required}} gates_enforced: {{gates_enforced}} gates_rationale: "{{gates_rationale}}" triggers: slash: {{slash_triggers}} phrases: {{phrase_triggers}} --- # /{{name}} > **Scope:** <one-sentence scope> > **Not in scope:** <what this skill does NOT do> > **Role:** <content-role that uses this skill> ## When to use - <trigger situation 1> - <trigger situation 2> ## Algorithm ### Step 1 — <action> <what to do and how> ### Step 2 — <action> <what to do and how> ## Anti-patterns - <anti-pattern 1>
-
-
scripts
-
batch-fix-skills.py 6 KB
#!/usr/bin/env python3 """Batch fix for SKILL.md files missing required fields/sections. Adds: agents, interaction, gates_required, gates_enforced, gates_rationale, ## When to use, ## Algorithm. """ import os import re import sys SKILLS_DIR = os.path.expanduser("~/IWE/.claude/skills") # Already PASS — skip SKIP = {"agent-fault", "apply-captures", "skill-creator"} # executor:script + deterministic:true → agents: none, interaction: one-shot SCRIPT_EXECUTOR = { "check-secret", "connect-guide", "consent", "extend", "iwe-bug-report", "lesson-close", "setup-wakatime", "transcribe", "w-reflection" } # Skills where ## Scope should be renamed to ## When to use (Scope = When-to-use content) SCOPE_AS_WTU = {"ke"} def get_description(content): m = re.search(r'^description:\s*["\']?(.*?)["\']?$', content, re.MULTILINE) return m.group(1).strip() if m else "" def has_field(content, field): return bool(re.search(rf'^{re.escape(field)}:', content, re.MULTILINE)) def add_frontmatter(content, skill_name): """Insert missing frontmatter fields before closing ---.""" is_script = skill_name in SCRIPT_EXECUTOR agents_val = "none" if is_script else "single" inter_val = "one-shot" if is_script else "multi-step" # Find end of frontmatter (second occurrence of ---) idx = content.find('\n---', 4) if idx == -1: return content additions = [] if not has_field(content, 'agents'): additions.append(f'agents: {agents_val}') if not has_field(content, 'interaction'): additions.append(f'interaction: {inter_val}') if not has_field(content, 'gates_required'): additions.append('gates_required: []') if not has_field(content, 'gates_enforced'): additions.append('gates_enforced: []') # Rationale needed when both gates are empty if not has_field(content, 'gates_rationale'): # Determine if gates will be empty after fix req_val = re.search(r'^gates_required:\s*(.*)', content, re.MULTILINE) enf_val = re.search(r'^gates_enforced:\s*(.*)', content, re.MULTILINE) req_empty = (req_val is None) or re.match(r'\[\s*\]', req_val.group(1).strip()) enf_empty = (enf_val is None) or re.match(r'\[\s*\]', enf_val.group(1).strip()) if req_empty and enf_empty: additions.append( 'gates_rationale: ' '"операционный скилл; WP Gate применим только при создании нового РП, ' 'не для операционных вызовов"' ) if additions: content = content[:idx] + '\n' + '\n'.join(additions) + content[idx:] return content def add_when_to_use(content, description, skill_name): """Add ## When to use section if missing.""" if '## When to use' in content: return content # ke: rename ## Scope → ## When to use (Scope IS the when-to-use content) if skill_name in SCOPE_AS_WTU: if re.search(r'^## Scope\b', content, re.MULTILINE): return re.sub(r'^## Scope\b', '## When to use', content, count=1, flags=re.MULTILINE) # Insert before first level-2 section in the body fm_end = content.find('\n---\n', 4) if fm_end == -1: return content body_start = fm_end + 4 m = re.search(r'\n## ', content[body_start:]) if m: pos = body_start + m.start() else: pos = len(content) section = f'\n## When to use\n\n{description}\n' return content[:pos] + section + content[pos:] def add_algorithm(content): """Add ## Algorithm section if missing.""" if '## Algorithm' in content: return content # Priority order: rename known Russian/alternative headings first rename_map = [ r'^## Алгоритм\b', r'^## Инструкция для Claude\b', r'^## Порядок выполнения\b', r'^## Поведение\b', ] for pattern in rename_map: if re.search(pattern, content, re.MULTILINE): return re.sub(pattern, '## Algorithm', content, count=1, flags=re.MULTILINE) # Numbered sections ## N. (like think skill) m = re.search(r'\n## \d+\.', content) if m: return content[:m.start()] + '\n## Algorithm\n' + content[m.start():] # Level-2 ## Шаг or ## Step m = re.search(r'\n## (Шаг|Step)\b', content) if m: return content[:m.start()] + '\n## Algorithm\n' + content[m.start():] # Level-2 ## Режим (multi-mode skills like vdv) m = re.search(r'\n## Режим\b', content) if m: return content[:m.start()] + '\n## Algorithm\n' + content[m.start():] # Fallback: append minimal section return content.rstrip() + '\n\n## Algorithm\n\nВыполнить согласно инструкции в теле скилла.\n' def process_skill(skill_name): path = os.path.join(SKILLS_DIR, skill_name, 'SKILL.md') if not os.path.exists(path): return False with open(path, encoding='utf-8') as f: orig = f.read() content = orig desc = get_description(content) content = add_frontmatter(content, skill_name) content = add_when_to_use(content, desc, skill_name) content = add_algorithm(content) if content != orig: with open(path, 'w', encoding='utf-8') as f: f.write(content) return True return False def main(): target = sys.argv[1] if len(sys.argv) > 1 else None skills = [target] if target else sorted(os.listdir(SKILLS_DIR)) fixed = [] skipped = [] for skill_name in skills: if skill_name in SKIP: skipped.append(skill_name) continue skill_dir = os.path.join(SKILLS_DIR, skill_name) if not os.path.isdir(skill_dir): continue if process_skill(skill_name): fixed.append(skill_name) print(f" fixed: {skill_name}") else: print(f" no-op: {skill_name}") print(f"\nDone: {len(fixed)} fixed, {len(skipped)} skipped (already PASS)") if __name__ == '__main__': main() -
content-audit.sh 7.4 KB
#!/usr/bin/env bash # content-audit.sh — minimal content check for IWE skills (WP-422 Ф9 + Ф10) # Ф9: 5 structural+content criteria (C1-C5). # Ф10: C6 verification-anchor (ВДВ — выгода-действие-верификация), calibrated. # Outputs: RED (>=2 issues), YELLOW (1 issue), GREEN (0 issues) set -euo pipefail SKILLS_DIR="${IWE_DIR:-$HOME/IWE}/.claude/skills" # SKIP_SKILLS — intentional exemptions, NOT "forgot to remove" (WP-422 Ф10): # skill-creator — meta-skill that bundles this very script (bootstrap circularity); # its own quality is gated by verify-skill.sh + /vdv audit (Step 7). # agent-fault — script-executor skill (argument-hint contract, no numbered steps); # apply-captures — script-executor skill; both structurally diverge from the step template. SKIP_SKILLS="${SKIP_SKILLS:-agent-fault apply-captures skill-creator}" # C6 verification-anchor vocabulary (Ф10). Broad on purpose — a skill "has a verification # notion" if any of: a Verification section (RU/EN), a verify/audit script, an acceptance # criterion, or an inline check (Expected/PASS/FAIL/smoke/test -f/проверь). C6_ANCHOR_RE='(^## .*[Вв]ерификаци|^## (Verification|Проверка)|[Вв]ерификаци|verify[-_a-z]*\.sh|[-_a-z]*audit\.sh|verify-skill|критери[йи] (готовности|приёмки|приемки)|acceptance|Expected result|Expected:|PASS\b|FAIL\b|smoke|смоук|test -f |проверь|проверить, что|sanity)' # Gate-critical = skill performs an irreversible/blocking action or enforces a gate. # Narrow on purpose: mere mention of "Pack"/"запиши" does NOT make a skill gate-critical # (that flagged 41/43 — manufactured churn). Only real side-effects count. C6_GATECRIT_RE='git push|git commit|deploy|skill-promote|promote\.sh|--no-verify' RED=0; YELLOW=0; GREEN=0 declare -a RED_LIST YELLOW_LIST # C6 advisory: non-gate-critical skills lacking any verification notion. Listed for manual # triage, NOT counted as an issue (many are inherently advisory: classifiers, transcribers). declare -a C6_ADVISORY_LIST audit_skill() { local name="$1" local skill_md="$SKILLS_DIR/$name/SKILL.md" local issues=0 local issue_list="" if [[ ! -f "$skill_md" ]]; then return fi # C1: gates_rationale non-empty when gates_required or gates_enforced are non-empty local gates_req gates_enf gates_rat gates_req=$(grep -E '^gates_required:' "$skill_md" | sed 's/gates_required:[[:space:]]*//' | tr -d '[]' | tr -d ' ' || true) gates_enf=$(grep -E '^gates_enforced:' "$skill_md" | sed 's/gates_enforced:[[:space:]]*//' | tr -d '[]' | tr -d ' ' || true) gates_rat=$(grep -E '^gates_rationale:' "$skill_md" | sed 's/gates_rationale:[[:space:]]*//' | tr -d '"' | tr -d "'" | xargs 2>/dev/null || true) local has_gates=false [[ -n "$gates_req" && "$gates_req" != "" ]] && has_gates=true [[ -n "$gates_enf" && "$gates_enf" != "" ]] && has_gates=true if $has_gates && [[ -z "$gates_rat" || "$gates_rat" == "\"\"" || "$gates_rat" == "''" ]]; then issues=$((issues + 1)) issue_list+=" C1:gates_rationale_missing" fi # C2: "## Algorithm" section present if ! grep -q '^## Algorithm' "$skill_md"; then issues=$((issues + 1)) issue_list+=" C2:no_algorithm_section" fi # C3: >= 3 step-like headings (##/### level) anywhere in file # Accepts: "## Шаг N", "## Step N", "### N.", "### Фn", "### n —", etc. local step_count step_count=$(grep -cE '^#{2,3} (Step|Шаг|Phase) [0-9]|^#{2,3} Ф[0-9]|^#{2,3} [0-9]+[а-яa-z]?\. |^#{2,3} [0-9]+[а-яa-z]? (—|-)' "$skill_md" || true) if [[ "$step_count" -lt 3 ]]; then issues=$((issues + 1)) issue_list+=" C3:steps_lt_3(found:${step_count})" fi # C4: each "### Step N" has >= 2 non-empty lines after it local step_fail=0 local in_step=false local step_content_count=0 while IFS= read -r line; do if [[ "$line" =~ ^###\ Step\ [0-9] ]]; then # check previous step if $in_step && [[ "$step_content_count" -lt 2 ]]; then step_fail=$((step_fail + 1)) fi in_step=true step_content_count=0 elif $in_step; then if [[ "$line" =~ ^## ]]; then # new top-level section, close current step if [[ "$step_content_count" -lt 2 ]]; then step_fail=$((step_fail + 1)) fi in_step=false elif [[ -n "$line" && ! "$line" =~ ^#+ ]]; then step_content_count=$((step_content_count + 1)) fi fi done < "$skill_md" # check last step if $in_step && [[ "$step_content_count" -lt 2 ]]; then step_fail=$((step_fail + 1)) fi if [[ "$step_fail" -gt 0 ]]; then issues=$((issues + 1)) issue_list+=" C4:empty_steps(${step_fail})" fi # C5: "## When to use" section present if ! grep -q '^## When to use' "$skill_md"; then issues=$((issues + 1)) issue_list+=" C5:no_when_to_use" fi # C6: verification-anchor (Ф10, ВДВ). Calibrated two-tier: # - gate-critical skill (irreversible action) WITHOUT any verify notion → counted issue; # - non-gate skill without anchor → advisory only (not counted), for manual triage. local has_anchor=false gate_crit=false grep -qiE "$C6_ANCHOR_RE" "$skill_md" && has_anchor=true grep -qE "$C6_GATECRIT_RE" "$skill_md" && gate_crit=true local genf genf=$(grep -E '^gates_enforced:' "$skill_md" | sed 's/gates_enforced:[[:space:]]*//' | tr -d '[] ' || true) [[ -n "$genf" ]] && gate_crit=true if ! $has_anchor; then if $gate_crit; then issues=$((issues + 1)) issue_list+=" C6:gate_critical_no_verification" else C6_ADVISORY_LIST+=("$name") fi fi # Classify if [[ "$issues" -ge 2 ]]; then RED=$((RED + 1)) RED_LIST+=("$name$issue_list") printf " RED %-30s %s\n" "$name" "$issue_list" elif [[ "$issues" -eq 1 ]]; then YELLOW=$((YELLOW + 1)) YELLOW_LIST+=("$name$issue_list") printf " YELLOW %-30s %s\n" "$name" "$issue_list" else GREEN=$((GREEN + 1)) printf " GREEN %-30s\n" "$name" fi } echo "=== content-audit.sh — WP-422 Ф9 ===" echo "Skills dir: $SKILLS_DIR" echo "Skipping: $SKIP_SKILLS" echo "" for skill_path in "$SKILLS_DIR"/*/; do skill_name=$(basename "$skill_path") if echo "$SKIP_SKILLS" | grep -qw "$skill_name"; then continue fi audit_skill "$skill_name" done TOTAL=$((RED + YELLOW + GREEN)) echo "" echo "=== Summary: $TOTAL skills audited ===" echo " GREEN (0 issues, minimal-content gate): $GREEN" echo " YELLOW (1 issue, fix by type): $YELLOW" echo " RED (2+ issues, needs VDV audit): $RED" echo "" echo "NOTE: GREEN = minimal structural+content barrier, not 'perfect skill'." echo " Logic errors in GREEN skills are possible — this audit checks structure only." echo "" if [[ ${#RED_LIST[@]} -gt 0 ]]; then echo "=== RED skills (need VDV audit) ===" for s in "${RED_LIST[@]}"; do echo " $s" done fi if [[ ${#YELLOW_LIST[@]} -gt 0 ]]; then echo "=== YELLOW skills (single fix) ===" for s in "${YELLOW_LIST[@]}"; do echo " $s" done fi if [[ ${#C6_ADVISORY_LIST[@]} -gt 0 ]]; then echo "" echo "=== C6 advisory: no verification anchor, NOT gate-critical (${#C6_ADVISORY_LIST[@]}) ===" echo " Manual triage: add a verification step only where it genuinely applies." echo " Inherently advisory skills (classifiers, transcribers, recorders) may stay as-is." for s in "${C6_ADVISORY_LIST[@]}"; do echo " $s" done fi -
scaffold-init.sh 5.6 KB
#!/bin/bash # scaffold-init.sh — substitute {{placeholders}} in a skill scaffold template # Usage: bash scripts/scaffold-init.sh --name <name> [options] # Output: path to created SKILL.md (stdout) set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" SKILL_CREATOR_DIR="$(dirname "$SCRIPT_DIR")" usage() { cat >&2 <<'EOF' Usage: bash scaffold-init.sh --name <name> [options] Required: --name <name> Skill name (hyphen-case) Optional: --description <text> Skill description --layer L1|L2|L3 Skill layer (default: L2) --agents single|multi Agent count (default: single) --interaction one-shot|multi-step Interaction type (default: multi-step) --version <semver> Version (default: 0.1.0) --status <status> Status (default: experimental) --slash-trigger <cmd> Slash trigger, repeatable --phrase-trigger <phrase> Phrase trigger (may include spaces), repeatable --gates-required wp|integration|routing Gate, repeatable --gates-enforced wp|integration|routing Gate, repeatable --gates-rationale <text> Required explanation when no gates declared --full Use full scaffold template (default: minimal) --target <path> Output path (default: .claude/skills/<name>/SKILL.md) EOF exit 1 } SKILL_NAME="" SKILL_DESCRIPTION="TODO: describe this skill" SKILL_LAYER="L2" SKILL_AGENTS="single" SKILL_INTERACTION="multi-step" SKILL_VERSION="0.1.0" SKILL_STATUS="experimental" SKILL_GATES_RATIONALE="" USE_FULL=false TARGET_PATH="" declare -a SLASH_TRIGGERS=() declare -a PHRASE_TRIGGERS=() declare -a GATES_REQUIRED=() declare -a GATES_ENFORCED=() while [[ $# -gt 0 ]]; do case "$1" in --name) SKILL_NAME="$2"; shift 2 ;; --description) SKILL_DESCRIPTION="$2"; shift 2 ;; --layer) SKILL_LAYER="$2"; shift 2 ;; --agents) SKILL_AGENTS="$2"; shift 2 ;; --interaction) SKILL_INTERACTION="$2"; shift 2 ;; --version) SKILL_VERSION="$2"; shift 2 ;; --status) SKILL_STATUS="$2"; shift 2 ;; --slash-trigger) SLASH_TRIGGERS+=("$2"); shift 2 ;; --phrase-trigger) PHRASE_TRIGGERS+=("$2"); shift 2 ;; --gates-required) GATES_REQUIRED+=("$2"); shift 2 ;; --gates-enforced) GATES_ENFORCED+=("$2"); shift 2 ;; --gates-rationale) SKILL_GATES_RATIONALE="$2"; shift 2 ;; --full) USE_FULL=true; shift ;; --target) TARGET_PATH="$2"; shift 2 ;; -h|--help) usage ;; *) echo "ERROR: Unknown option: $1" >&2; usage ;; esac done if [ -z "$SKILL_NAME" ]; then echo "ERROR: --name is required" >&2 usage fi if $USE_FULL; then TEMPLATE="$SKILL_CREATOR_DIR/assets/skill-scaffold-full.md" else TEMPLATE="$SKILL_CREATOR_DIR/assets/skill-scaffold-minimal.md" fi if [ ! -f "$TEMPLATE" ]; then echo "ERROR: template not found: $TEMPLATE" >&2 exit 1 fi if [ -z "$TARGET_PATH" ]; then TARGET_PATH=".claude/skills/$SKILL_NAME/SKILL.md" fi mkdir -p "$(dirname "$TARGET_PATH")" # Build YAML trigger list fragment (4-space indent under slash:/phrases: key) build_trigger_yaml() { local result="" local item for item in "$@"; do result="${result} - ${item}"$'\n' done printf '%s' "$result" } # Build inline YAML list: [] or [a, b, c] build_gates_yaml() { if [ $# -eq 0 ]; then echo "[]" return fi local result="[" local g for g in "$@"; do result="${result}${g}, " done result="${result%, }]" echo "$result" } SKILL_SLASH_TRIGGERS="$(build_trigger_yaml "${SLASH_TRIGGERS[@]+"${SLASH_TRIGGERS[@]}"}")" SKILL_PHRASE_TRIGGERS="$(build_trigger_yaml "${PHRASE_TRIGGERS[@]+"${PHRASE_TRIGGERS[@]}"}")" SKILL_GATES_REQUIRED="$(build_gates_yaml "${GATES_REQUIRED[@]+"${GATES_REQUIRED[@]}"}")" SKILL_GATES_ENFORCED="$(build_gates_yaml "${GATES_ENFORCED[@]+"${GATES_ENFORCED[@]}"}")" if [ "$SKILL_GATES_REQUIRED" = "[]" ] && [ "$SKILL_GATES_ENFORCED" = "[]" ] && [ -z "$SKILL_GATES_RATIONALE" ]; then echo "WARNING: gates_required=[] and gates_enforced=[] but --gates-rationale not set." >&2 echo " verify-skill.sh will FAIL. Pass --gates-rationale to explain why no gates." >&2 fi export SKILL_NAME SKILL_DESCRIPTION SKILL_LAYER SKILL_AGENTS SKILL_INTERACTION export SKILL_VERSION SKILL_STATUS SKILL_GATES_RATIONALE export SKILL_SLASH_TRIGGERS SKILL_PHRASE_TRIGGERS export SKILL_GATES_REQUIRED SKILL_GATES_ENFORCED python3 - "$TEMPLATE" "$TARGET_PATH" <<'PYEOF' import sys, os, pathlib template_path, output_path = sys.argv[1], sys.argv[2] text = pathlib.Path(template_path).read_text() replacements = { "{{name}}": os.environ["SKILL_NAME"], "{{description}}": os.environ["SKILL_DESCRIPTION"], "{{version}}": os.environ["SKILL_VERSION"], "{{status}}": os.environ["SKILL_STATUS"], "{{layer}}": os.environ["SKILL_LAYER"], "{{agents}}": os.environ["SKILL_AGENTS"], "{{interaction}}": os.environ["SKILL_INTERACTION"], "{{slash_triggers}}": os.environ["SKILL_SLASH_TRIGGERS"], "{{phrase_triggers}}": os.environ["SKILL_PHRASE_TRIGGERS"], "{{gates_required}}": os.environ["SKILL_GATES_REQUIRED"], "{{gates_enforced}}": os.environ["SKILL_GATES_ENFORCED"], "{{gates_rationale}}": os.environ["SKILL_GATES_RATIONALE"], } for placeholder, value in replacements.items(): text = text.replace(placeholder, value) pathlib.Path(output_path).write_text(text) PYEOF echo "$TARGET_PATH" -
verify-skill.sh 4.5 KB
#!/bin/bash # verify-skill.sh — smoke test for a newly created IWE skill # Usage: bash scripts/verify-skill.sh <skill-name> [skills-dir] set -euo pipefail SKILL_NAME="${1:-}" SKILLS_DIR="${2:-.claude/skills}" if [ -z "$SKILL_NAME" ]; then echo "Usage: bash scripts/verify-skill.sh <skill-name> [skills-dir]" exit 1 fi SKILL_PATH="$SKILLS_DIR/$SKILL_NAME/SKILL.md" SKILL_DIR="$SKILLS_DIR/$SKILL_NAME" FAILED=0 fail() { echo "FAIL: $1"; FAILED=1; } ok() { echo "OK: $1"; } check_frontmatter_fields() { local file="$1" label="$2" for field in name description version status layer agents interaction; do if grep -qE "^${field}:" "$file"; then ok "$label frontmatter.$field" else fail "$label missing frontmatter.$field" fi done } check_body_sections() { local file="$1" label="$2" for section in "## When to use" "## Algorithm"; do if grep -qF "$section" "$file"; then ok "$label section '${section}'" else fail "$label missing required section '${section}'" fi done } check_gates() { local file="$1" local has_req has_enf has_req=$(grep -cE "^gates_required:" "$file" || true) has_enf=$(grep -cE "^gates_enforced:" "$file" || true) if [ "$has_req" -eq 0 ] || [ "$has_enf" -eq 0 ]; then fail "missing frontmatter: both gates_required and gates_enforced are mandatory" return fi ok "gates_required + gates_enforced present" local valid_re="^(wp|integration|routing)$" for gfield in gates_required gates_enforced; do while IFS= read -r v; do v_clean=$(echo "$v" | tr -d ' "'"'"'[],' ) [ -z "$v_clean" ] && continue if ! echo "$v_clean" | grep -qE "$valid_re"; then fail "$gfield: unknown value '$v_clean' (allowed: wp, integration, routing)" fi done < <(grep "^${gfield}:" "$file" | sed 's/^.*\[//;s/\].*//;s/,/\n/g') done local req_empty enf_empty req_empty=$(grep "^gates_required:" "$file" | grep -cE "\[\s*\]" || true) enf_empty=$(grep "^gates_enforced:" "$file" | grep -cE "\[\s*\]" || true) if [ "$req_empty" -gt 0 ] && [ "$enf_empty" -gt 0 ]; then local rationale rationale=$(grep "^gates_rationale:" "$file" | sed 's/^gates_rationale: *//' | tr -d '"' | xargs) if [ -z "$rationale" ]; then fail "both gates lists empty but gates_rationale is missing" else ok "gates_rationale present (no gates declared)" fi fi } check_bundled_resources() { local file="$1" skill_dir="$2" grep -qE "^## Bundled resources" "$file" || return 0 while IFS= read -r line; do [[ "$line" =~ ^\-\ \`(scripts|assets)/[^\`]+\` ]] || continue local resource="${line#*\`}" resource="${resource%%\`*}" if [ -f "$skill_dir/$resource" ]; then ok "bundled resource exists: $resource" else fail "bundled resource missing: $skill_dir/$resource" fi done < "$file" } check_scaffold_templates() { local skill_dir="$1" for tmpl in "$skill_dir/assets/skill-scaffold-minimal.md" "$skill_dir/assets/skill-scaffold-full.md"; do local label label="template/$(basename "$tmpl")" if [ ! -f "$tmpl" ]; then fail "$label missing" continue fi check_frontmatter_fields "$tmpl" "$label" check_body_sections "$tmpl" "$label" done } check_l1_location() { local file="$1" skill_name="$2" local layer layer=$(grep "^layer:" "$file" | sed 's/^layer: *//' | tr -d '"' | xargs) [ "$layer" = "L1" ] || return 0 local fmt_path="$HOME/IWE/FMT-exocortex-template/.claude/skills/$skill_name/SKILL.md" if [ -f "$fmt_path" ]; then ok "L1 skill present in FMT-exocortex-template" else fail "L1 skill not found in FMT ($fmt_path)" fi } # --- Main --- if [ ! -f "$SKILL_PATH" ]; then echo "FAIL: $SKILL_PATH not found" exit 1 fi echo "=== verify-skill: $SKILL_NAME ===" check_frontmatter_fields "$SKILL_PATH" "skill" DESC_WORDS=$(grep -A 10 "^description:" "$SKILL_PATH" | sed '1d' | tr '\n' ' ' | wc -w | tr -d ' ') if [ "$DESC_WORDS" -ge 10 ]; then ok "description length ($DESC_WORDS words)" else fail "description too short ($DESC_WORDS words, need ≥10)" fi if grep -qE "^triggers:" "$SKILL_PATH"; then ok "triggers section" else fail "missing triggers section" fi check_body_sections "$SKILL_PATH" "skill" check_gates "$SKILL_PATH" check_bundled_resources "$SKILL_PATH" "$SKILL_DIR" [ "$SKILL_NAME" = "skill-creator" ] && check_scaffold_templates "$SKILL_DIR" check_l1_location "$SKILL_PATH" "$SKILL_NAME" echo "" if [ "$FAILED" -eq 0 ]; then echo "PASS: $SKILL_NAME — all checks passed" exit 0 else echo "FAIL: $SKILL_NAME — one or more checks failed (see above)" exit 1 fi
-
-
SKILL.md 10.5 KB
--- name: skill-creator description: | Create a new IWE skill with proper frontmatter, gates, scaffold and verification. Use when the pilot says: /skill-creator or «создай скилл <name>». The skill enforces WP Gate precondition, Routing Gate, IntegrationGate hard-check, collects parameters in 4 short steps, generates a scaffold SKILL.md from a template, shows a draft, writes files, and reminds about verify-skill.sh. version: 0.3.2 status: experimental browser_safe: false layer: L1 agents: single interaction: multi-step gates_required: [wp] gates_enforced: [integration, routing] gates_rationale: "wp — создание скилла = нетривиальный артефакт (>15 мин), требует согласованного РП до начала (WP Gate precondition). integration — новый скилл-обёртка над инструментом/ролью требует существующих DP.SC.* + DP.ROLE.* до реализации (IntegrationGate hard-block). routing — размещение (Claude/Kimi, project/user, L1-L3) есть решение Routing Gate до scaffold." triggers: slash: - /skill-creator phrases: - "создай скилл <name>" - "новый скилл <name>" --- # /skill-creator — create an IWE skill > **Scope:** create a new skill OR guide an update to an existing skill in `.claude/skills/` or `.kimi/skills/`. > **Not in scope:** full re-scaffold without deleting the old `SKILL.md` first (delete manually, then call `/skill-creator` again); creating a WP; creating a Pack. > **Role:** ad-hoc content-role «Инженер скиллов»; formalize in Pack if ≥3 skills/year. ## When to use - Pilot wants a new skill for a repeated workflow. - A new tool/agent/system needs a Service Clause + Role + SKILL.md. - A skill needs promotion from author repo to `FMT-exocortex-template`. ## Preconditions (checked, not performed) 1. **WP Gate precondition.** The task must be attached to an agreed WP in the weekly plan or explicitly named by the pilot. `/skill-creator` does not conduct the WP Gate ritual itself. 2. **Routing Gate.** Decide target platform (Claude vs Kimi) and level (project vs user). Default: project-level `.claude/skills/` in the author repo. 3. **IntegrationGate hard-check.** `DP.SC.*` and `DP.ROLE.*` must exist in the PACK repo. If not, the skill stops and offers to create them. Bypass only by explicit pilot instruction «пропусти gate» — no code flag. ## Algorithm ### Step 1 — Check WP Gate precondition Look up the current weekly plan (`current/WeekPlan W{N}.md`) or ask: ``` К какому РП привязано создание скилла? ``` If no WP is named and none matches the skill topic → stop: ``` Создание скилла требует согласованного РП. Сначала откройте РП через WP Gate. ``` ### Step 2 — Routing Gate Ask or infer: | Question | Default | |----------|---------| | Claude или Kimi? | Claude | | project-level или user-level? | project-level | | governance-репо для учёта? | `${IWE_GOVERNANCE_REPO:-DS-strategy}` | Target path: - Claude project: `.claude/skills/<name>/` - Kimi project: `.kimi/skills/<name>/` - User level: `~/.claude/skills/<name>/` or `~/.kimi/skills/<name>/` ### Step 2.5 — Detect existing skill Check whether `<target_path>/SKILL.md` already exists. **If it exists** → switch to update mode. Do NOT re-scaffold. Show the pilot: ``` Скилл <name> уже существует (версия X.Y.Z). Что обновить? [ ] description [ ] slash / phrase triggers [ ] version bump (current: X.Y.Z → new: ?) [ ] algorithm step (add / edit) [ ] bundled resource (add scripts/ references/ assets/) [ ] полный пересоздать → удалите SKILL.md вручную, затем запустите /skill-creator снова [ ] отмена → ничего не менять ``` Collect the pilot's choices. Apply changes directly to the existing `SKILL.md` via Edit. Skip Steps 3–6 **unless** the pilot selected "bundled resource" or any change that expands the skill's scope or gates — in that case, run **Step 3 (IntegrationGate)** before applying. For Step 7 (register + verify): run `verify-skill.sh` always. Run `generate-skills-catalog.sh` only if frontmatter changed (name, description, triggers, version). Version bump rule: bump patch for trigger / description edits; bump minor for algorithm changes **or adding a bundled resource**; bump major for gate or scope changes. **If it does not exist** → continue to Step 3 (normal creation flow). ### Step 3 — IntegrationGate Check PACK repo for files matching `DP.SC.*` and `DP.ROLE.*`. If missing: ``` Service Clause (DP.SC.*) и Role (DP.ROLE.*) не найдены. Создайте их сейчас через /pack-new или соответствующий процесс. Для продолжения без них скажите явно: «пропусти gate». ``` Stop until the gate is satisfied or explicitly bypassed by pilot words. ### Step 4 — Collect parameters (4 short steps) **4a. Name and description** ``` Имя скилла (hyphen-case): <name> Краткое описание — что делает и когда использовать: ``` **4b. Agents and interaction axes** ``` agents: single | multi interaction: one-shot | multi-step ``` **4c. Triggers** ``` slash-команды (через запятую): фразовые триггеры (через запятую): ``` Keep phrase triggers narrow: include a skill name placeholder to avoid accidental activation. **4d. Bundled resources** ``` Какие bundled resources нужны? [ ] scripts/ [ ] references/ [ ] assets/ ``` Default: `assets/` for scaffold template, `scripts/` for verify script. ### Step 5 — Generate scaffold Choose scaffold template based on skill complexity: - **Minimal** (`assets/skill-scaffold-minimal.md`): single-step skills without external gates - **Full** (`assets/skill-scaffold-full.md`): multi-step skills with Preconditions and Bundled resources Copy chosen template to target path and substitute: - `{{name}}`, `{{description}}`, `{{version}}` (default `0.1.0`), `{{status}}` (default `experimental`) - `{{agents}}`, `{{interaction}}`, `{{layer}}` - `{{slash_triggers}}`, `{{phrase_triggers}}` - `{{gates_rationale}}` — required when `gates_required` and `gates_enforced` are both empty Create selected bundled resource directories with placeholder files. ### Step 6 — Show draft Print generated `SKILL.md` and file list to stdout. No P5 question. Pilot can cancel with: ``` /skill-creator undo ``` Undo works only before next commit or within 15 minutes. ### Step 7 — Write files, register, verify Write files to target path. Then regenerate the catalog and run verify: ```bash bash scripts/generate-skills-catalog.sh # register in skills-catalog.yaml bash scripts/verify-skill.sh <name> # 33-point structural check ``` Both commands must pass before the skill is considered created. Tell the user where the new skill lives and that nothing preserves it (issue #873): a project-local skill under `.claude/skills/<name>/` is usually outside git and outside the `day-close.sh` backup, and `update.sh` neither erases nor carries it over. Until the template owner picks a backup model, suggest keeping a copy in a git repository the user controls. For skills with `interaction: multi-step`: run `/vdv audit` on the Algorithm section. Not a gate — does not block creation — but catches steps with missing Input/Output linkage before the skill is used in practice. ## Bundled resources - `assets/skill-scaffold-minimal.md` — scaffold for single-step skills without external gates - `assets/skill-scaffold-full.md` — scaffold for multi-step skills with Preconditions and Bundled resources - `scripts/verify-skill.sh` — validates frontmatter, gates fields, bundled resource existence, L1 location ## Known schema gaps Fields used by some existing skills but not yet in the standard frontmatter schema: - `argument-hint` — CLI-style hint for script-executor skills (e.g. agent-fault, apply-captures). Encodes the argument contract. Keep until schema is extended or absorbed into `description`. - `routing.executor` — indicates whether the skill runs via `script`, `sonnet`, or another executor. Useful for the dispatcher but not validated by `verify-skill.sh`. Candidate for standardization. Until standardized: leave these fields as-is in existing skills; do not remove during Step 2.5 updates. ## Known tool gaps - **`verify-skill.sh` L1 location check for `.kimi/skills/`**: `check_l1_location` only checks `FMT-exocortex-template/.claude/skills/`. For skills placed at `.kimi/skills/` (platform:kimi), the L1 location check is skipped when `layer: L2`, or produces a spurious FAIL when `layer: L1`. Until verify-skill.sh is extended with a `--platform kimi` flag, use `layer: L2` for `.kimi/skills/` test skills, and document any intentional L1 Kimi skills separately. - **`content-audit.sh` coverage (Ф9)**: audit script checks 5 structural criteria (gates_rationale, Algorithm section, step headings ≥3, step content ≥2 lines, When-to-use section). 7 YELLOW skills (single C3 issue) are simple alias/mode skills without numbered step headings. This is structural noise, not content error — these skills are functionally correct. See `scripts/content-audit.sh` for full output. ## Anti-patterns - Do not create a skill without a linked WP. - Do not bypass IntegrationGate with a code flag. - Do not put wide phrase triggers like «надо сделать скилл». - Run `generate-skills-catalog.sh` after writing files (Step 7) — not before, not manually. - Do not make the skill verify itself; use `scripts/verify-skill.sh`. - Do not skip `verify-skill.sh` after editing an existing skill — always run it after any update. - Do not re-scaffold for minor updates (triggers, description, version bump, algorithm); use Step 2.5 update mode instead. Exception: platform or layer change (e.g. Claude→Kimi, L1→L3) requires a new path and a fresh scaffold — delete old SKILL.md first. - Do not forget version bump when changing gates, scope, or algorithm steps (bump minor or major). ## Verification After creation, run: ```bash bash scripts/verify-skill.sh <skill-name> ``` Expected result: PASS with checks for: valid YAML frontmatter, non-empty description, recognized triggers, `gates_required`/`gates_enforced` fields with valid enum values, bundled resource files exist, scaffold templates valid, L1 skills present in FMT. <!-- USER-SPACE --> <!-- /USER-SPACE -->
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.