Skip to main content

sniffable-python

Structure Python so LLMs can understand it in 50 lines.

Informations de source

Dépôt
SimHacker/moollm
Dernière activité de la source
9 février 2026 à 21:17
Langue détectée de SKILL.md
anglais
Étoiles
60
Forks
5

Options d'installation

Le prompt qui vérifie d'abord la source est sélectionné par défaut. Vous pouvez passer à une commande directe ou télécharger une copie locale.

Vérifiez les fichiers source

Lisez SKILL.md et les fichiers associés affichés par SkillsMP avant de décider de l'installer.

Explorateur de fichiers
6 fichiers

Affichage de SKILL.md

SKILL.md
Instructions source · Aperçu en lecture seule
name
sniffable-python
description
Structure Python so LLMs can understand it in 50 lines.
license
MIT
tier
0
allowed-tools
["read_file","write_file"]
related
["moollm","sister-script","play-learn-lift","yaml-jazz","plain-text","postel","adventure","debugging"]
tags
["moollm","python","structure","llm-readable","code"]
credits
["MOOLLM — Dual-audience code structure","Python argparse — Built-in CLI with clean structure/implementation separation","Steve Jobs — Lickable pixels as quality signal (Aqua, 2000)"]
# Sniffable Python > **"Structure code for the first 50 lines. That's all the LLM needs."** Don't invent new syntax — **structure existing syntax** for optimal LLM comprehension. *If your code smells good, the LLM can sniff it from the first whiff.* *Steve Jobs wanted pixels you could lick. We want code you can sniff.* --- ## The Problem LLMs can read Python. But: - Large files overwhelm context - Implementation details bury the API - Comments scattered or missing - No clear entry point for understanding **Solution:** Structure Python so the first ~50 lines contain everything needed to understand and use the tool. Make your code's bouquet apparent from the opening notes. --- ## The Pattern ### Canonical Structure ```python #!/usr/bin/env python3 """skill-name: Brief description of what the script does. This docstring becomes --help output AND is immediately visible to the LLM. It should contain: - Purpose (one sentence) - Usage examples - Key behaviors Usage: python script.py command [options] Examples: python script.py move north --quiet python script.py examine sword --verbose """ import argparse from pathlib import Path import yaml # Configuration DEFAULT_ROOM = "start" VALID_DIRECTIONS = ["north", "south", "east", "west"] MAX_INVENTORY = 10 def main(): """Main entry point — CLI structure only, no implementation.""" parser = argparse.ArgumentParser( description=__doc__.split('\n')[0], # First line of module docstring formatter_class=argparse.RawDescriptionHelpFormatter ) subparsers = parser.add_subparsers(dest="command", required=True) # move command move_parser = subparsers.add_parser("move", help="Move in a direction") move_parser.add_argument("direction", choices=VALID_DIRECTIONS, help="Direction to move") move_parser.add_argument("--quiet", "-q", action="store_true", help="Suppress output") # examine command examine_parser = subparsers.add_parser("examine", help="Look at something") examine_parser.add_argument("target", help="What to examine") examine_parser.add_argument("--verbose", "-v", action="store_true", help="Show details") # status command status_parser = subparsers.add_parser("status", help="Show game state") status_parser.add_argument("--verbose", "-v", action="store_true", help="Show details") args = parser.parse_args() _dispatch(args) # Implementation (LLM only reads past here if modifying behavior) def _dispatch(args): """Route to appropriate handler.""" if args.command == "move": _do_move(args.direction, args.quiet) elif args.command == "examine": _do_examine(args.target, args.verbose) elif args.command == "status": _show_status(args.verbose) def _do_move(direction: str, quiet: bool) -> None: """Internal: Execute movement.""" ... def _do_examine(target: str, verbose: bool) -> None: """Internal: Examine an object.""" ... def _show_status(verbose: bool) -> None: """Internal: Display status.""" ... if __name__ == "__main__": main() ``` ### The Zones | Zone | Lines | Purpose | |------|-------|---------| | **Shebang + Docstring** | 1-15 | Purpose, usage, becomes `--help` | | **Imports** | 16-22 | Dependencies visible at a glance | | **Constants** | 23-30 | Configuration, valid values, limits | | **CLI Structure** | 31-50 | Command tree with types and docs | | **Implementation** | 51+ | Only read if modifying | --- ## Why This Works ### Dual-Audience Design ```yaml # One file, two audiences, same source of truth dual_audience: source: "Python file (sniffable)" audiences: human: entry_point: "--help" sees: "CLI usage, arguments, examples" llm: entry_point: "first 50 lines" sees: "docstring, imports, constants, CLI tree" convergence: "Same source of truth — no duplication, no drift" ``` ### DRY Principle The CLI decorators ARE the documentation: ```python @click.option('--verbose', '-v', is_flag=True, help='Show details') ``` This single line defines: - The flag name (`--verbose`) - The short form (`-v`) - The type (boolean flag) - The help text - The Python parameter name and type No duplication. No drift. One source. --- ## Why Syntax Compression Fails Some argue for compressing syntax to save tokens — dense symbols, sigils, minimal keywords. This is the wrong optimization. **Perl is the cautionary tale.** Its obsessive fetish for compact syntax, sigils, punctuation, and performative TMTOWTDI one-liners — to the point of looking like line noise — is exactly why it's no longer relevant for LLM comprehension and generation. | Approach | Tokens | Comprehension | Training Data | |----------|--------|---------------|---------------| | Dense novel syntax | Fewer | Low (unfamiliar) | Minimal | | Sniffable Python | More | High (known syntax) | Billions | **The LLM already knows Python cold.** Teaching it a novel syntax costs millions of tokens per context window (docs, examples, corrections) — and that cost is paid every single prompt, because prompting is not training. LLMs have no memory. Sniffable Python costs zero tokens to teach — the LLM just reads code it understands deeply from massive pre-training. ### The Symbol Collision Problem Short symbols cause semantic collisions. When `@` appears, it activates Python decorators, shell patterns, email addresses, and more — simultaneously. The model has to do disambiguation work that wouldn't exist with unambiguous keywords. That disambiguation costs compute and introduces error modes. ### Comprehension Fidelity > Token Count You're not optimizing for token count. You're optimizing for **how well the LLM understands your code**. Dense punctuation is anti-optimized for how transformers tokenize and reason. Verbose, well-structured code with semantic comments actually compresses better in the LLM's internal representations. --- ## Comments as YAML Jazz Apply YAML-JAZZ principles to Python comments: ```python # CONSTANTS TIMEOUT = 30 # generous — API is flaky on Mondays MAX_RETRIES = 3 # based on observed failure patterns in prod BATCH_SIZE = 100 # memory-safe for 8GB instances # TODO: Add circuit breaker after next major outage # FIXME: Rate limiting not yet implemented # NOTE: This duplicates logic in api_client.py — consider extracting ``` These comments ARE data. The LLM reads them. Acts on them. Uses them to understand *why*, not just *what*. --- ## Comments: Substance Over Decoration **Don't waste tokens on decorative separators:** ```python # BAD: Decorative separators (long = or - lines add no meaning) # GOOD: Plain and functional # Imports import argparse ``` **Don't trim Christmas trees:** Avoid ASCII art or box-drawing in comments. Use plain section comments instead: ```python # Configuration TIMEOUT = 30 # generous — API flaky on Mondays ``` **Do include useful semantic comments:** ```python # ✓ GOOD: Explains WHY TIMEOUT = 30 # generous — API flaky on Mondays MAX_RETRIES = 3 # based on observed failure patterns BATCH_SIZE = 100 # memory-safe for 8GB instances # ✓ GOOD: Documents intent # TODO: Add circuit breaker after next outage # NOTE: Duplicates logic in api_client.py — consider extracting ``` **The rule:** Every comment token should carry meaning. If it's just decoration, delete it. --- ## Argparse vs Click vs Typer **Argparse is preferred** for sniffable Python because it separates structure from implementation: | Feature | Argparse | Click | Typer | |---------|----------|-------|-------| | Structure/impl separation | ✓ Clean | ✗ Mixed | ✗ Mixed | | Top-down tree order | ✓ | ✗ | ✗ | | Built-in (no deps) | ✓ | ✗ | ✗ | | Training data | Abundant | Abundant | Growing | | LLM familiarity | Highest | High | Medium | ### The Argparse Advantage With Click/Typer, decorators attach to functions — so CLI structure is **interleaved** with implementation: ```python # Click: structure mixed with implementation @cli.command() def examine(target: str): # ← implementation starts here """Look at something.""" do_stuff() # ← can't sniff without reading this ``` With argparse, `main()` contains the **entire CLI tree** with no implementation: ```python # Argparse: clean separation def main(): """CLI structure only — no implementation.""" parser = argparse.ArgumentParser(description="Tool description") subparsers = parser.add_subparsers(dest="command") # examine command examine_parser = subparsers.add_parser("examine", help="Look at something") examine_parser.add_argument("target", help="What to examine") examine_parser.add_argument("--verbose", "-v", action="store_true") # move command move_parser = subparsers.add_parser("move", help="Move in a direction") move_parser.add_argument("direction", choices=VALID_DIRECTIONS) args = parser.parse_args() _dispatch(args) # ← implementation is ELSEWHERE # IMPLEMENTATION (completely separate, below the fold) def _dispatch(args): ... ``` **The LLM reads `main()` and sees the entire command tree** — arguments, types, choices, help text — without any implementation noise. Pure sniffability. No need to hold your nose. --- ## Integration with Sister Scripts Sniffable Python is how sister scripts should be structured: ``` skill/ ├── SKILL.md # Tells LLM how to generate scripts ├── CARD.yml # Interface definition └── scripts/ └── helper.py # Sniffable Python ``` When the skill/SKILL.md instructs the LLM to generate a sister script, it should follow sniffable-python conventions: 1. Docstring with usage at top, no decorations 2. Imports grouped and labeled 3. Constants with explanatory comments 4. CLI structure before implementation 5. Implementation below the fold --- ## Directory-Agnostic Invocation **Critical pattern:** All scripts — including sniffable Python — must work when invoked from ANY directory. Scripts find their skill context using `__file__`, not `os.getcwd()`. For bash scripts, see [sister-script/](../sister-script/) for the equivalent pattern. ### The Pattern ```python from pathlib import Path # Find THIS script's location (not the caller's cwd) SCRIPT_DIR = Path(__file__).resolve().parent SKILL_DIR = SCRIPT_DIR.parent # If script is in skill/scripts/ # Now find sibling files relative to script location CONFIG_FILE = SKILL_DIR / "config.yml" PATTERNS_DIR = SKILL_DIR / "patterns" TEMPLATES_DIR = SKILL_DIR / "templates" ``` **Why `__file__`?** - `Path(__file__)` — path to THIS script file - `.resolve()` — resolve symlinks to get real location - `.parent` — containing directory **Why NOT `os.getcwd()`?** - `os.getcwd()` returns the CALLER's directory - Script invoked from `/home/user/` won't find `skills/foo/patterns/` ### The Complete Template ```python #!/usr/bin/env python3 """sister-tool: Brief description. Usage: python3 skills/my-skill/scripts/sister-tool.py command [options] Can be invoked from any directory — finds its own context. """ from pathlib import Path import argparse import yaml # DIRECTORY CONTEXT # Find script location regardless of caller's cwd SCRIPT_DIR = Path(__file__).resolve().parent SKILL_DIR = SCRIPT_DIR.parent # scripts/ is one level down from skill/ # Skill-relative paths CARD_FILE = SKILL_DIR / "CARD.yml" PATTERNS_DIR = SKILL_DIR / "patterns" TEMPLATES_DIR = SKILL_DIR / "templates" CONFIG_DIR = SKILL_DIR / ".moollm" / "skills" / SKILL_DIR.name # CONFIGURATION def load_card(): """Load skill's CARD.yml for metadata.""" if CARD_FILE.exists(): return yaml.safe_load(CARD_FILE.read_text()) return {} def main(): """CLI structure — sniffable, directory-agnostic.""" card = load_card() parser = argparse.ArgumentParser( description=card.get("description", __doc__.split('\n')[0]) ) # ... CLI structure ... args = parser.parse_args() _dispatch(args) # IMPLEMENTATION def _dispatch(args): ... if __name__ == "__main__": main() ``` ### Why This Matters | Invocation | `os.getcwd()` | `Path(__file__).parent` | |------------|---------------|-------------------------|
Voir sur GitHub
Ce SKILL.md est tres volumineux, SkillsMP affiche donc ici seulement la premiere section. Voir sur GitHub