/yamlscript
Write idiomatic YAMLScript code. Use when asked to write, convert, or review YAMLScript (.ys files). Converts Clojure to idiomatic YAMLScript using confirmed style rules and tested examples.
$ npx -y skills add yaml/yamlscript --skill yamlscript --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
- Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
- You can call itInvoke it directly when you want it.
- Slash command
/yamlscript
Context preview
The summary Claude sees to decide when to auto-load this skill.
Write idiomatic YAMLScript code. Use when asked to write, convert, or review YAMLScript (.ys files). Converts Clojure to idiomatic YAMLScript using confirmed style rules and tested examples.
SKILL.md
yamlscript.SKILL.mdname: yamlscript
description: >
Write idiomatic YAMLScript code. Use when asked to write, convert, or
review YAMLScript (.ys files). Converts Clojure to idiomatic YAMLScript
using confirmed style rules and tested examples.
YAMLScript Skill
Setup
Ensure `ys` version 0.3.5 is available for testing:
[[ -x /tmp/ys-skill/bin/ys-0.3.5 ]] ||
source <(curl -sL https://in-1.cc) --local ys \
YAMLSCRIPT-VERSION=0.3.5 PREFIX=/tmp/ys-skill
YS=/tmp/ys-skill/bin/ysOptionally clone the source for looking up stdlib functions, DWIM support, and docs:
[[ -d /tmp/ys-skill/yamlscript ]] ||
git clone --depth 1 https://github.com/yaml/yamlscript \
/tmp/ys-skill/yamlscript
# Key files:
# core/src/ys/std.clj — YS standard library
# core/src/ys/dwim.clj — functions with auto arg-placement
# doc/ — language documentationWorkflow
1. **Write correct Clojure first** — Clojure is unambiguous; get the logic right before worrying about YS syntax 2. **Convert to YAMLScript** — apply the rules below 3. **Test every attempt** before presenting it:
# Single-line expressions
$YS -pe 'expr'
# Multi-line programs
$YS -c - <<<'!ys-0 ...'
4. **Iterate** until the output is correct and idiomatic 5. **Lint the source** with the `ys-lint.ys` script that ships next to this SKILL.md (same skill directory). Run it against every `.ys` file you wrote or edited:
/path/to/skill/ys-lint.ys FILE...
`ys-lint.ys` flags *possible* surface-form mistakes the compiler can't see because they vanish at the AST stage: `.nth(N)` vs `.N`, `.nth(var)` vs `.$var`, `x + 1` vs `.++`, `x - 1` vs `.--`, `.first()` / `.last()` vs `.0` / `.$` (or `:first` / `:last`), `vector(...)` and inline `V+(...)` vs `:[...]`, inline `M+(...)` vs `:{...}`, avoidable `apply` calls vs direct splats (`f(xs*)` / `f: xs*`), `str(bareVar)` vs `bareVar:S`, `quot(a b)` and `a.quot(b)` vs `a // b`, `rem(a b)` vs `a % b`, parenthesized simple integer-looking divisions such as `(n / d)` vs `(n // d)`, `:zero?` vs `.!` when falsey-zero semantics are OK, ` or(` / ` and(` calls vs `||` / `&&`, any `KW (cond):` test-expression paren-wrap (for `if`, `if-not`, `when`, `when-not`, `while`), any `KW [...]:` bracketed binding form for the reliably-strippable keywords (`binding`, `if-let`/`if-lets`/`if-some`, `let`, `loop`, `when-first`/`when-let`/`when-lets`/`when-some`, `with-open`) and for the iteration keywords (`each`, `for`, `doseq`, `dotimes`) when the binding starts with a named var (not a `_`-var or destructure pattern), `then: nil` / `else: nil` vs `when` / `when-not`, direct `then: false` under `if` as a candidate for reversed `when`, a zero-arg method `x.foo()` vs the colon chain `x:foo`, a `=>:` whose value is a call / colon-chain / dot-chain / spaced binary op vs a pair form (`f: args` / `x: .m(a)` / `a OP: b`), a direct `=>:` child under an `if` block vs `then:` / `else:`, `say: ''` vs bare `say:`, `x.join(' ')` vs the colon chain `x:joins`, `slurp` / `spit` vs `read` / `write`, displaced Clojure I/O names such as `println` and `read-line`, retired `require` vs `use`, plain-YAML structural checks such as scalar `then:` / `else:` branches that can be positional `if` branches, a wide `recur:` / `loop` arg list that should be comma-separated, and lines over 79 cols.
Most linter rules match source text with regex; a few strip the top `!ys-0` tag, load the file as plain YAML, and inspect the YAML shape. Every hit is still a *candidate*, not a verdict. False positives are expected: a long line may be a literal task string the program can't shorten; an `x - 1` inside a generated string isn't a `.--` candidate; an identifier that happens to look like a pattern may not be one. Inspect every reported line, fix the real mistakes, and explicitly justify each hit you treat as a false positive. This step is required: the working program isn't done until you have walked every lint hit and either fixed it or accepted it with reason.
Program Tag
- Always use `!ys-0` — the short idiomatic form
- `!yamlscript/v0` and `!yamlscript/v0/` are legacy — do not use
- `!ys-0` = code mode; `!ys-0:` = data mode
YS vs Clojure Standard Library
Prefer YS stdlib functions (`ys.std`) over their Clojure equivalents — they are more powerful and polymorphic (e.g. `reverse` works on strings, `replace` defaults the replacement to `""`, `rng` works on chars). If performance is a concern, fall back to the specific Clojure function for that case.
Most `Math/*` functions are exposed in `ys.std` (`sqrt`, `sqr`, `floor`, `abs`, `pow`, etc.). Drop the `Math/` prefix when a YS builtin exists; it's more idiomatic.
Common Mistakes
Patterns Claude gets wrong most often. Scan these before writing any YS.
Use `if` for two-branch conditionals — `cond` only for 3+ branches
`cond` is **only** appropriate when there are three or more mutually exclusive branches. Any time you have a single predicate plus an `else:` (one real branch and one fallback), use `if` instead. This is the single most common conditional mistake.
- `cond: x == 0: a / else: b` → `if x == 0: \n then: a \n else: b`
- `cond: pred: x / else: recur(...)` → `if pred: \n then: x \n else: recur(...)`
`if` can drop the `then:` and `else:` keys when both branches are *pair-form* children (mapping entries), because YS reads the two children positionally regardless of their keys. The keys can even collide:
if (n % d) == 0:
recur: quot(n d) d cnt.++
recur: n d.++ cnt
This also lets the then-branch be a nested `if X:` pair while the else-branch is an explicit `else:`:
if n >= 2:
if (n % d) == 0:
recur: ...
recur: ...
else: cntBare-scalar branches (plain identifiers, calls, expressions) can also drop `then:` / `else:` when both branches
Read more
name: yamlscript description: > Write idiomatic YAMLScript code. Use when asked to write, convert, or review YAMLScript (.ys files). Converts Clojure to idiomatic YAMLScript using confirmed style rules and tested examples.
YAMLScript Skill
Setup
Ensure `ys` version 0.3.5 is available for testing:
[[ -x /tmp/ys-skill/bin/ys-0.3.5 ]] ||
source <(curl -sL https://in-1.cc) --local ys \
YAMLSCRIPT-VERSION=0.3.5 PREFIX=/tmp/ys-skill
YS=/tmp/ys-skill/bin/ysOptionally clone the source for looking up stdlib functions, DWIM support, and docs:
[[ -d /tmp/ys-skill/yamlscript ]] ||
git clone --depth 1 https://github.com/yaml/yamlscript \
/tmp/ys-skill/yamlscript
# Key files:
# core/src/ys/std.clj — YS standard library
# core/src/ys/dwim.clj — functions with auto arg-placement
# doc/ — language documentationWorkflow
1. **Write correct Clojure first** — Clojure is unambiguous; get the logic right before worrying about YS syntax 2. **Convert to YAMLScript** — apply the rules below 3. **Test every attempt** before presenting it:
# Single-line expressions $YS -pe 'expr' # Multi-line programs $YS -c - <<<'!ys-0 ...'
4. **Iterate** until the output is correct and idiomatic 5. **Lint the source** with the `ys-lint.ys` script that ships next to this SKILL.md (same skill directory). Run it against every `.ys` file you wrote or edited:
/path/to/skill/ys-lint.ys FILE...
`ys-lint.ys` flags *possible* surface-form mistakes the compiler can't see because they vanish at the AST stage: `.nth(N)` vs `.N`, `.nth(var)` vs `.$var`, `x + 1` vs `.++`, `x - 1` vs `.--`, `.first()` / `.last()` vs `.0` / `.$` (or `:first` / `:last`), `vector(...)` and inline `V+(...)` vs `:[...]`, inline `M+(...)` vs `:{...}`, avoidable `apply` calls vs direct splats (`f(xs*)` / `f: xs*`), `str(bareVar)` vs `bareVar:S`, `quot(a b)` and `a.quot(b)` vs `a // b`, `rem(a b)` vs `a % b`, parenthesized simple integer-looking divisions such as `(n / d)` vs `(n // d)`, `:zero?` vs `.!` when falsey-zero semantics are OK, ` or(` / ` and(` calls vs `||` / `&&`, any `KW (cond):` test-expression paren-wrap (for `if`, `if-not`, `when`, `when-not`, `while`), any `KW [...]:` bracketed binding form for the reliably-strippable keywords (`binding`, `if-let`/`if-lets`/`if-some`, `let`, `loop`, `when-first`/`when-let`/`when-lets`/`when-some`, `with-open`) and for the iteration keywords (`each`, `for`, `doseq`, `dotimes`) when the binding starts with a named var (not a `_`-var or destructure pattern), `then: nil` / `else: nil` vs `when` / `when-not`, direct `then: false` under `if` as a candidate for reversed `when`, a zero-arg method `x.foo()` vs the colon chain `x:foo`, a `=>:` whose value is a call / colon-chain / dot-chain / spaced binary op vs a pair form (`f: args` / `x: .m(a)` / `a OP: b`), a direct `=>:` child under an `if` block vs `then:` / `else:`, `say: ''` vs bare `say:`, `x.join(' ')` vs the colon chain `x:joins`, `slurp` / `spit` vs `read` / `write`, displaced Clojure I/O names such as `println` and `read-line`, retired `require` vs `use`, plain-YAML structural checks such as scalar `then:` / `else:` branches that can be positional `if` branches, a wide `recur:` / `loop` arg list that should be comma-separated, and lines over 79 cols.
Most linter rules match source text with regex; a few strip the top `!ys-0` tag, load the file as plain YAML, and inspect the YAML shape. Every hit is still a *candidate*, not a verdict. False positives are expected: a long line may be a literal task string the program can't shorten; an `x - 1` inside a generated string isn't a `.--` candidate; an identifier that happens to look like a pattern may not be one. Inspect every reported line, fix the real mistakes, and explicitly justify each hit you treat as a false positive. This step is required: the working program isn't done until you have walked every lint hit and either fixed it or accepted it with reason.
Program Tag
- Always use `!ys-0` — the short idiomatic form
- `!yamlscript/v0` and `!yamlscript/v0/` are legacy — do not use
- `!ys-0` = code mode; `!ys-0:` = data mode
YS vs Clojure Standard Library
Prefer YS stdlib functions (`ys.std`) over their Clojure equivalents — they are more powerful and polymorphic (e.g. `reverse` works on strings, `replace` defaults the replacement to `""`, `rng` works on chars). If performance is a concern, fall back to the specific Clojure function for that case.
Most `Math/*` functions are exposed in `ys.std` (`sqrt`, `sqr`, `floor`, `abs`, `pow`, etc.). Drop the `Math/` prefix when a YS builtin exists; it's more idiomatic.
Common Mistakes
Patterns Claude gets wrong most often. Scan these before writing any YS.
Use `if` for two-branch conditionals — `cond` only for 3+ branches
`cond` is **only** appropriate when there are three or more mutually exclusive branches. Any time you have a single predicate plus an `else:` (one real branch and one fallback), use `if` instead. This is the single most common conditional mistake.
- `cond: x == 0: a / else: b` → `if x == 0: \n then: a \n else: b`
- `cond: pred: x / else: recur(...)` → `if pred: \n then: x \n else: recur(...)`
`if` can drop the `then:` and `else:` keys when both branches are *pair-form* children (mapping entries), because YS reads the two children positionally regardless of their keys. The keys can even collide:
if (n % d) == 0: recur: quot(n d) d cnt.++ recur: n d.++ cnt
This also lets the then-branch be a nested `if X:` pair while the else-branch is an explicit `else:`:
if n >= 2:
if (n % d) == 0:
recur: ...
recur: ...
else: cntBare-scalar branches (plain identifiers, calls, expressions) can also drop `then:` / `else:` when both branches
Repo: yaml/yamlscript

