skill-author
Draft a well-formed new skill (a SKILL.md scaffold, optionally with scripts/references) from a described recurring need, for human review and approval. Use whenever a repeated workflow gap has no existing skill covering it, when someone wants to propose or create a new skill or c
Install
npx skills add https://github.com/Zhonghao1995/agentic-swmm-workflow/tree/main/skills/skill-author
claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install zhonghao1995-agentic-swmm-workflow@llmmart
git clone https://github.com/Zhonghao1995/agentic-swmm-workflow.git
The skills CLI installs just this skill, for any of its supported agents. Claude Code installs the whole zhonghao1995/agentic-swmm-workflow collection as a plugin from our marketplace. Git is the plain clone.
Skill manifest
Skill author
Turn a description of a recurring need into a draft skill that a human can review and approve. This skill writes proposals; it never installs, activates, or edits skills on its own — a freshly drafted skill is a proposal, not a verified capability.
It is domain-general: nothing here is specific to stormwater or SWMM. The same recipe produces a skill for any modeling or workflow domain.
When to use
- A recurring problem keeps showing up and no existing skill covers it — the gap itself is the trigger to propose a new one.
- Someone asks to "create / propose / draft a new skill" for some capability.
- An agentic system (e.g. a memory or lessons-learned layer) flags a repeated pattern that warrants a new skill rather than a tweak to an existing one.
If an existing skill already covers most of the need, improve that one instead — don't create a near-duplicate (see step 2).
How to draft a skill
Capture intent. Pin down three things before writing: (a) what should this skill let the agent do? (b) when should it trigger — what phrases or contexts? (c) what does it produce (output format)? Pull answers from the conversation or the evidence you were handed; only ask the human for what's genuinely missing.
Check for overlap first. List the existing skills and check whether one already does most of this. If so, propose refining that skill instead of adding a new one — avoiding skill sprawl keeps the library discoverable.
Fill the template. Copy
assets/SKILL.template.mdand fill it in. The two fields that matter most:name— kebab-case, matches the folder name.description— this is how the agent decides to use the skill, so make it specific and slightly pushy: say what it does AND the concrete situations it should trigger in. A vague description means the skill never fires.
Keep the body lean and explain the why behind each instruction — a capable model follows reasoning better than rigid ALL-CAPS rules. See
references/skill-format.mdfor the full recipe (anatomy, progressive disclosure, writing patterns).Validate. Run the checker and fix anything it flags:
python3 scripts/validate_skill.py path/to/draft-skillIt confirms the SKILL.md has a name and a real description, the name matches the folder, and the body isn't empty.
Present for approval. Show the human the drafted skill plus the need/evidence that motivated it, and let them accept or reject. Nothing is installed until they say yes. Keep their part to a single yes/no — do the drafting work for them.
What makes a good skill
Read references/skill-format.md before writing the body. It condenses the skill anatomy (SKILL.md + optional scripts/ references/ assets/), progressive disclosure (keep SKILL.md lean, push detail to references/), how to write a description that actually triggers, and the writing patterns that make instructions work.
Output contract
A draft skill folder:
<skill-name>/
├── SKILL.md (required: name + description frontmatter, lean body)
├── references/ (optional: detailed docs loaded on demand)
├── assets/ (optional: templates / files used in output)
└── scripts/ (optional: deterministic helpers)
Place the draft in a staging / proposals area for review — do not drop it into a live skills directory until the human approves.
Safety / boundaries
- Propose, never auto-apply. Don't install a drafted skill, activate it, or edit existing skills without explicit human approval.
- A draft is not a verified capability. It still needs human review and, where the domain has them, benchmark or test verification before it's trusted.
- No surprises. A skill's contents must match its stated intent — no hidden behavior, no malware, nothing that exfiltrates data or does something the description doesn't admit.
- Stay domain-general. Don't bake one domain's assumptions (specific node names, a fixed file layout) into this authoring skill itself.
Files (agentic-swmm-workflow)
-
assets
-
SKILL.template.md 610 B
--- name: <kebab-case-name-matching-this-folder> description: <what it does AND when to trigger — specific and a little pushy so it doesn't under-fire; one or two sentences> --- # <Skill title> <One line: what this skill lets the agent do.> ## When to use - <concrete trigger context> - <another trigger context> ## How it works <Imperative steps. Explain the *why* behind each one. Keep it lean; push long reference detail into references/ and point to it from here.> ## Output <What the skill produces, and the output format if it matters.> ## Safety / boundaries - <what this skill must not do>
-
-
references
-
skill-format.md 2.6 KB
# What makes a good skill A condensed authoring recipe (distilled from the skill-creator approach). Read this before writing a new skill's body. ## Anatomy ``` skill-name/ ├── SKILL.md (required) │ ├── YAML frontmatter — name, description (both required) │ └── Markdown body — the instructions └── optional bundled resources: ├── scripts/ — executable helpers for deterministic / repetitive work ├── references/ — docs loaded into context only when needed └── assets/ — files used in the output (templates, icons, fonts) ``` ## Progressive disclosure (the core idea) A skill loads in three levels — keep the cheap things small so the expensive ones load only when needed: 1. **name + description** — always in context (~100 words). The triggering surface. 2. **SKILL.md body** — loaded when the skill triggers. Keep it lean (well under ~500 lines). 3. **Bundled resources** — loaded on demand; scripts can run without being read into context. If the body grows past ~500 lines, move detail into `references/*.md` and point to it with a one-line "read X when you need Y." ## The description field (most important) The description is the *only* thing the agent sees when deciding whether to use the skill. So: - Say **what it does** AND **when to trigger** — concrete phrases, contexts, file types. - Be a little **pushy** — models tend to *under*-trigger skills. e.g. "Use this whenever the user mentions X, Y, or Z, even if they don't say the word 'skill'." - One or two sentences. Put everything else in the body. ## Writing the body - **Imperative voice.** "Read the manifest", not "the skill reads the manifest." - **Explain the why.** A capable model follows reasoning better than rigid rules. Prefer "do X because Y" over "ALWAYS DO X." If you catch yourself writing ALL-CAPS MUSTs, reframe and explain instead. - **Output formats** — when the output shape matters, give an explicit template. - **Examples** — a couple of Input → Output examples beat a paragraph of prose. - **General, not overfit.** Write for the whole class of cases, not the single example in front of you. ## Bundle a script when work repeats If every use of the skill would re-derive the same helper (parse the same file, build the same artifact), write it once into `scripts/` and have the skill call it. Deterministic, faster, consistent. ## Lack of surprise (safety) A skill's contents must match its stated intent. No malware, no exploit code, nothing that does something the description doesn't admit. If a described skill would surprise the user in what it actually does, don't write it that way.
-
-
scripts
-
validate_skill.py 4.3 KB
#!/usr/bin/env python3 """Validate that a skill folder is well-formed before it is proposed for review. Domain-general: this knows nothing about SWMM or any specific domain. It checks the structural contract every skill must satisfy — a SKILL.md carrying a name + description in its frontmatter and a non-empty body — so a freshly drafted skill can be auto-checked before a human is asked to approve it. Usage: python3 validate_skill.py path/to/skill-dir Exit code 0 = valid, 1 = problems (printed to stderr), 2 = bad invocation. """ from __future__ import annotations import re import sys from pathlib import Path _NAME_RE = re.compile(r"^[a-z0-9]+(-[a-z0-9]+)*$") _MIN_DESCRIPTION_CHARS = 40 _BLOCK_SCALAR_RE = re.compile(r"^[>|][+-]?$") def _parse_frontmatter(text): """Split leading ``---`` YAML frontmatter from the body. Returns ``(front, body)`` where ``front`` is a dict of the simple ``key: value`` scalars (all a skill header needs), or ``(None, text)`` if there is no frontmatter block. Values written as YAML block scalars (``key: >`` / ``key: |`` with indented continuation lines) are joined so a multi-line description measures its real length, and indented continuation lines are never misread as keys. """ lines = text.splitlines() if not lines or lines[0].strip() != "---": return None, text for i in range(1, len(lines)): if lines[i].strip() == "---": front = {} j = 1 while j < i: raw = lines[j] if raw.startswith((" ", "\t")) or ":" not in raw: j += 1 continue key, _, val = raw.partition(":") val = val.strip() if _BLOCK_SCALAR_RE.match(val): # Folded (>) joins with spaces; literal (|) keeps newlines. sep = " " if val.startswith(">") else "\n" parts = [] j += 1 while j < i and ( lines[j].startswith((" ", "\t")) or not lines[j].strip() ): parts.append(lines[j].strip()) j += 1 front[key.strip()] = sep.join(p for p in parts if p) continue front[key.strip()] = val j += 1 return front, "\n".join(lines[i + 1:]) return None, text def validate(skill_dir): """Check one skill folder. Return a list of human-readable problems (empty = OK).""" skill_dir = Path(skill_dir) skill_md = skill_dir / "SKILL.md" if not skill_md.is_file(): return [f"no SKILL.md found in {skill_dir}"] front, body = _parse_frontmatter(skill_md.read_text(encoding="utf-8", errors="ignore")) if front is None: return ["SKILL.md has no '---' YAML frontmatter block at the top"] problems = [] name = front.get("name", "") if not name: problems.append("frontmatter is missing a 'name'") else: if not _NAME_RE.match(name): problems.append(f"name '{name}' is not kebab-case (lowercase words joined by '-')") if name != skill_dir.name: problems.append(f"name '{name}' does not match the folder name '{skill_dir.name}'") description = front.get("description", "") if not description: problems.append( "frontmatter is missing a 'description' (this is how the agent decides when to use the skill)" ) elif len(description) < _MIN_DESCRIPTION_CHARS: problems.append( f"description is only {len(description)} chars; write a fuller one that says " "what it does AND when to use it" ) if not body.strip(): problems.append("SKILL.md has an empty body below the frontmatter") return problems def main(argv): if len(argv) != 2: print("usage: python3 validate_skill.py path/to/skill-dir", file=sys.stderr) return 2 problems = validate(argv[1]) if problems: print(f"INVALID: {argv[1]}", file=sys.stderr) for p in problems: print(f" - {p}", file=sys.stderr) return 1 print(f"PASS: {argv[1]} is a well-formed skill") return 0 if __name__ == "__main__": raise SystemExit(main(sys.argv))
-
-
tests
-
test_validate_skill.py 3.1 KB
"""Contract tests for validate_skill.py — a well-formed skill passes, malformed ones fail.""" import importlib.util from pathlib import Path _SCRIPT = Path(__file__).resolve().parent.parent / "scripts" / "validate_skill.py" _spec = importlib.util.spec_from_file_location("validate_skill", _SCRIPT) validate_skill = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(validate_skill) def _write_skill(parent, name="demo-skill", description=None, body="# Demo\n\nDoes a thing."): if description is None: description = "A demo skill that does a thing and triggers when the user asks for that thing." skill = parent / name skill.mkdir(parents=True, exist_ok=True) front = ["---", f"name: {name}"] if description is not False: front.append(f"description: {description}") front.append("---") (skill / "SKILL.md").write_text("\n".join(front) + "\n\n" + body, encoding="utf-8") return skill def test_wellformed_skill_passes(tmp_path): skill = _write_skill(tmp_path) assert validate_skill.validate(skill) == [] def test_missing_skill_md_fails(tmp_path): empty = tmp_path / "empty-skill" empty.mkdir() problems = validate_skill.validate(empty) assert problems and "no SKILL.md" in problems[0] def test_missing_description_fails(tmp_path): skill = _write_skill(tmp_path, description=False) # omit the description line assert any("description" in p for p in validate_skill.validate(skill)) def test_name_must_match_folder(tmp_path): skill = _write_skill(tmp_path, name="demo-skill") renamed = skill.parent / "other-folder" skill.rename(renamed) assert any("match the folder name" in p for p in validate_skill.validate(renamed)) def test_real_skill_author_passes(): # dogfood: the skill-author skill itself must be well-formed skill_author = _SCRIPT.resolve().parent.parent assert validate_skill.validate(skill_author) == [] def test_folded_block_description_measures_full_length(tmp_path): """``description: >`` continuation lines count toward the length check. Regression: the parser used to read the block-scalar marker itself (1 char) as the value, failing legitimate multi-line descriptions. """ skill = tmp_path / "demo-skill" skill.mkdir() (skill / "SKILL.md").write_text( "---\n" "name: demo-skill\n" "description: >\n" " A folded multi-line description that says what the skill does\n" " and when the agent should reach for it.\n" "---\n\n# Demo\n\nBody.\n", encoding="utf-8", ) assert validate_skill.validate(skill) == [] def test_literal_block_description_measures_full_length(tmp_path): skill = tmp_path / "demo-skill" skill.mkdir() (skill / "SKILL.md").write_text( "---\n" "name: demo-skill\n" "description: |-\n" " A literal multi-line description that says what the skill does\n" " and when the agent should reach for it.\n" "---\n\n# Demo\n\nBody.\n", encoding="utf-8", ) assert validate_skill.validate(skill) == []
-
-
SKILL.md 4.6 KB
--- name: skill-author description: Draft a well-formed new skill (a SKILL.md scaffold, optionally with scripts/references) from a described recurring need, for human review and approval. Use whenever a repeated workflow gap has no existing skill covering it, when someone wants to propose or create a new skill or capability, or when an agentic system detects a recurring problem that warrants a brand-new skill rather than editing an existing one. Domain-general — works for any modeling or workflow domain; SWMM is just one example. --- # Skill author Turn a description of a recurring need into a **draft skill** that a human can review and approve. This skill writes proposals; it never installs, activates, or edits skills on its own — a freshly drafted skill is a proposal, not a verified capability. It is domain-general: nothing here is specific to stormwater or SWMM. The same recipe produces a skill for any modeling or workflow domain. ## When to use - A recurring problem keeps showing up and **no existing skill covers it** — the gap itself is the trigger to propose a new one. - Someone asks to "create / propose / draft a new skill" for some capability. - An agentic system (e.g. a memory or lessons-learned layer) flags a repeated pattern that warrants a new skill rather than a tweak to an existing one. If an existing skill already covers most of the need, **improve that one instead** — don't create a near-duplicate (see step 2). ## How to draft a skill 1. **Capture intent.** Pin down three things before writing: (a) what should this skill let the agent *do*? (b) *when* should it trigger — what phrases or contexts? (c) what does it *produce* (output format)? Pull answers from the conversation or the evidence you were handed; only ask the human for what's genuinely missing. 2. **Check for overlap first.** List the existing skills and check whether one already does most of this. If so, propose refining that skill instead of adding a new one — avoiding skill sprawl keeps the library discoverable. 3. **Fill the template.** Copy `assets/SKILL.template.md` and fill it in. The two fields that matter most: - `name` — kebab-case, matches the folder name. - `description` — this is *how the agent decides to use the skill*, so make it specific and slightly pushy: say what it does AND the concrete situations it should trigger in. A vague description means the skill never fires. Keep the body lean and **explain the why** behind each instruction — a capable model follows reasoning better than rigid ALL-CAPS rules. See `references/skill-format.md` for the full recipe (anatomy, progressive disclosure, writing patterns). 4. **Validate.** Run the checker and fix anything it flags: ```bash python3 scripts/validate_skill.py path/to/draft-skill ``` It confirms the SKILL.md has a name and a real description, the name matches the folder, and the body isn't empty. 5. **Present for approval.** Show the human the drafted skill plus the need/evidence that motivated it, and let them accept or reject. **Nothing is installed until they say yes.** Keep their part to a single yes/no — do the drafting work for them. ## What makes a good skill Read `references/skill-format.md` before writing the body. It condenses the skill anatomy (SKILL.md + optional `scripts/` `references/` `assets/`), progressive disclosure (keep SKILL.md lean, push detail to `references/`), how to write a `description` that actually triggers, and the writing patterns that make instructions work. ## Output contract A draft skill folder: ``` <skill-name>/ ├── SKILL.md (required: name + description frontmatter, lean body) ├── references/ (optional: detailed docs loaded on demand) ├── assets/ (optional: templates / files used in output) └── scripts/ (optional: deterministic helpers) ``` Place the draft in a staging / proposals area for review — do **not** drop it into a live skills directory until the human approves. ## Safety / boundaries - **Propose, never auto-apply.** Don't install a drafted skill, activate it, or edit existing skills without explicit human approval. - **A draft is not a verified capability.** It still needs human review and, where the domain has them, benchmark or test verification before it's trusted. - **No surprises.** A skill's contents must match its stated intent — no hidden behavior, no malware, nothing that exfiltrates data or does something the description doesn't admit. - **Stay domain-general.** Don't bake one domain's assumptions (specific node names, a fixed file layout) into this authoring skill itself.
Comments (0)
Sign in to join the conversation.
Reviews (0)
No reviews yet.
No comments yet.