SPB Git

spb/ultra-sharp-agent-skills Public

Ultra-Sharp Agent Skills — a research-first skill-authoring system + 72 production-ready skills for AI agents.

Python 100%
4.7 KB · 136 lines markdown
Rendered Raw Blame History
1<!--2Author: Simon-Pierre Boucher3Contact: contact@spboucher.ai4-->56# YAML Recipes78## Contents9- Create a config from scratch10- Read: multi-document files and defaults11- Modify: nested keys, lists, comment-preserving edits12- Validate against a schema13- Convert YAML ↔ JSON14- Gotchas (Norway problem, implicit typing, anchors)1516## Create a config from scratch1718```python19import yaml2021config = {22    "server": {"host": "0.0.0.0", "port": 8080},23    "features": ["auth", "metrics"],24    "welcome": "Bienvenue à Montréal",25}26with open("config.yaml", "w") as f:27    yaml.safe_dump(config, f,28                   default_flow_style=False,  # block style, not {a: 1}29                   sort_keys=False,           # keep insertion order30                   allow_unicode=True)        # keep accented chars readable31```3233Force quotes on an ambiguous scalar:3435```python36yaml.safe_dump({"country": "NO", "version": "1.10"}, f,37               default_style=None)  # safe_dump already quotes these on output38# When hand-writing YAML text, quote them yourself: country: "NO"39```4041## Read: multi-document files and defaults4243```python44import yaml4546# Single document47data = yaml.safe_load(open("config.yaml")) or {}   # empty file → None, so `or {}`4849# Multi-document (--- separators), e.g. Kubernetes manifests50docs = list(yaml.safe_load_all(open("manifests.yaml")))5152# Nested read with defaults53port = (data.get("server") or {}).get("port", 8080)54```5556## Modify: nested keys, lists, comment-preserving edits5758PyYAML (comments will be lost):5960```python61data = yaml.safe_load(open("config.yaml"))62data.setdefault("server", {})["port"] = 909063data.setdefault("features", []).append("tracing")64yaml.safe_dump(data, open("config.yaml", "w"),65               default_flow_style=False, sort_keys=False, allow_unicode=True)66```6768ruamel.yaml (comments, quotes, key order all survive):6970```python71from ruamel.yaml import YAML7273y = YAML()                 # round-trip mode74y.indent(mapping=2, sequence=4, offset=2)   # match common k8s/compose style75doc = y.load(open("docker-compose.yml"))76doc["services"]["web"]["ports"] = ["8080:80"]77y.dump(doc, open("docker-compose.yml", "w"))78```7980Multi-document write:8182```python83yaml.safe_dump_all(docs, open("manifests.yaml", "w"),84                   default_flow_style=False, sort_keys=False)85```8687## Validate against a schema8889For structural guarantees use jsonschema (`pip install jsonschema`) on the loaded data — YAML loads to the same shapes JSON Schema describes:9091```python92import yaml, jsonschema9394schema = {95    "type": "object",96    "required": ["server"],97    "properties": {98        "server": {99            "type": "object",100            "required": ["port"],101            "properties": {"port": {"type": "integer",102                                    "minimum": 1, "maximum": 65535}},103        }104    },105}106data = yaml.safe_load(open("config.yaml"))107jsonschema.validate(data, schema)   # raises ValidationError with a JSON path108```109110## Convert YAML ↔ JSON111112```python113import json, yaml114115# YAML → JSON116json.dump(yaml.safe_load(open("config.yaml")), open("config.json", "w"),117          indent=2, ensure_ascii=False)118119# JSON → YAML120yaml.safe_dump(json.load(open("config.json")), open("config.yaml", "w"),121               default_flow_style=False, sort_keys=False, allow_unicode=True)122```123124Caveat: JSON has no equivalent for YAML anchors, multi-doc streams, or non-string keys — conversion resolves/loses them.125126## Gotchas (Norway problem, implicit typing, anchors)127128- **The Norway problem.** In YAML 1.1 (what PyYAML implements), unquoted `no`, `yes`, `on`, `off`, `y`, `n` parse as booleans — `country: NO` becomes `country: False`. Quote them. Same family: `port: 022` is octal 18, `version: 1.10` is the float `1.1`.129- **Timestamps auto-convert.** `date: 2026-08-05` loads as `datetime.date`, not a string. Quote if you need the text.130- **`safe_load` of an empty file returns `None`**, not `{}` — guard with `or {}`.131- **Duplicate keys don't error** in PyYAML — the last one silently wins. ruamel.yaml raises; use it when duplicates would be a bug.132- **Anchors/aliases (`&base`, `*base`, `<<:` merge)** load fine but PyYAML re-dumps them expanded (aliases only re-emitted when the same object identity repeats). If the user's file relies on anchors for maintainability, edit with ruamel.yaml.133- **`sort_keys` defaults to True** in `safe_dump` — it silently alphabetizes configs; always pass `sort_keys=False` when round-tripping.134- **Long strings get folded** with line breaks on dump; pass `width=4096` to keep long values (URLs, tokens) on one line.135- **YAML 1.2 vs 1.1.** ruamel.yaml follows 1.2 (only `true`/`false` are booleans); PyYAML follows 1.1. The same file can load differently across the two libraries — pick one per task and stay with it.136