diff --git a/README.md b/README.md index 12a2c4f..5580749 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,62 @@ A public skill library for AI agents. Skills provide self-contained instructions |-------|-------------|--------| | [blowfish-launch-token](./blowfish-launch-token/) | Launch Solana tokens via the Blowfish Agent API | Active | | [character-image-studio](./character-image-studio/) | Manage character visual identities and generate consistent images via the NeukoAI Image Studio API | Active | +| [lunar](./lunar/) | Get lunar phases, biodynamic calendar (Michel Gros method), and holistic environmental readings for agriculture | Active | +| [weather](./weather/) | Get current weather and forecasts via free APIs (wttr.in, Open-Meteo) — no API key required | Active | + +## Usage Examples + +### 🌾 Smart Farming Assistant + +Combine **lunar** + **weather** skills for biodynamic agriculture guidance: + +``` +User: "Should I plant lettuce today?" + +Agent uses lunar skill: +- Checks current moon phase (waxing/waning) +- Identifies biodynamic day type (Leaf/Root/Flower/Fruit) +- Determines if moon is ascending/descending + +Agent uses weather skill: +- Checks current conditions and 3-day forecast +- Evaluates soil moisture and temperature + +Agent responds: +"Today is a Leaf Day (🌿) with descending moon — perfect for +transplanting lettuce. Weather: 12°C, light rain tomorrow will +help establishment. Ideal timing." +``` + +**Why it matters:** Traditional biodynamic farmers track lunar calendars manually. These skills give any agent instant access to centuries-old agricultural wisdom + modern weather data. + +### 🪙 Token Launch with Character Identity + +Combine **blowfish-launch-token** + **character-image-studio**: + +``` +User: "Launch a token for my rabbit character." + +Agent: +1. Uses character-image-studio to generate consistent avatar +2. Uploads image to IPFS via blowfish API +3. Launches token with image metadata +4. Returns CA + verified visual identity +``` + +### 🌙 Holistic Context Awareness + +The **lunar** skill provides "holistic readings" that merge: +- Moon phase + zodiac position +- Biodynamic calendar recommendations +- Current weather conditions +- Seasonal context + +Perfect for agents assisting with: +- Regenerative agriculture +- Permaculture planning +- Natural rhythms and cycles +- Outdoor event scheduling ## Quick Start diff --git a/lunar/SKILL.md b/lunar/SKILL.md new file mode 100644 index 0000000..221b015 --- /dev/null +++ b/lunar/SKILL.md @@ -0,0 +1,85 @@ +--- +name: lunar +description: Get lunar phases, biodynamic calendar (Michel Gros method), and holistic environmental readings. Use when discussing moon influence, planting calendars, biodynamic agriculture, or requesting environmental/holistic context. +metadata: {"enki": {"emoji": "🌙", "requires": {"bins": ["python3", "curl"]}}} +--- + +# Lunar & Biodynamic Calendar + +Provides lunar phase data and biodynamic calendar guidance based on Michel Gros principles for holistic environmental awareness. + +## Quick Usage + +```bash +# Current lunar phase + biodynamic day type +./scripts/lunar.sh today + +# Weekly view (7 days) +./scripts/lunar.sh week + +# Specific date +./scripts/lunar.sh 2026-02-25 + +# Holistic reading (moon + weather) +./scripts/lunar.sh holistic +``` + +## What It Provides + +1. **Lunar Phases** — Current phase, illumination %, age, rise/set times +2. **Michel Gros Calendar** — Jour Racine/Fleur/Fruit/Feuille based on zodiac +3. **Montante/Descendante** — Ascending/descending moon (planting vs. harvesting) +4. **Croissante/Décroissante** — Waxing/waning (growth vs. consolidation) +5. **Recommandations** — Biodynamic guidance for farming/gardening tasks + +## Moon Phases & Agriculture + +### Croissante (Waxing) → Décroissante (Waning) +- **Croissante (🌒→🌕):** Sève monte, croissance aérienne, bon pour semis de plantes à fruits/feuilles +- **Décroissante (🌖→🌑):** Sève descend, enracinement, bon pour semis racines, taille, récolte conservation + +### Montante → Descendante (Zodiac Position) +- **Montante:** Lune monte dans le ciel (Sagittaire→Gémeaux), sève monte, semis +- **Descendante:** Lune descend (Gémeaux→Sagittaire), sève descend, plantation/repiquage + +### Les 4 Jours (Michel Gros) + +Basé sur la constellation zodiacale traversée : + +- **🌿 Jour Feuille** (Cancer, Scorpion, Poissons) — Salades, épinards, choux +- **🌸 Jour Fleur** (Gémeaux, Balance, Verseau) — Fleurs, brocoli, artichaut +- **🍎 Jour Fruit** (Bélier, Lion, Sagittaire) — Tomates, courges, arbres fruitiers +- **🥕 Jour Racine** (Taureau, Vierge, Capricorne) — Carottes, pommes de terre, oignons + +## API Source + +Uses combination of: +- **Astronomical calculation** (Python ephem library or algorithm) +- **Wttr.in** for basic moon emoji +- **Zodiac position calculation** for Michel Gros calendar + +No API key required. All calculations local or free services. + +## Holistic Reading + +Combines lunar data + weather for complete environmental context: + +```bash +./scripts/lunar.sh holistic Canton+de+Vaud +``` + +Returns: +- Current weather conditions +- Lunar phase & biodynamic day +- Recommendations for farming tasks + +## Notes for Enki + +- **Maraîcher context:** Always consider both croissante/décroissante AND montante/descendante +- **Optimal windows:** Best planting = jour approprié + lune favorable + météo correcte +- **Nœuds lunaires:** Avoid planting within 12h of lunar nodes (script warns) +- **Conservation:** Harvest root crops in lune décroissante, jour racine for best storage + +--- + +*Gardien de la terre. Lecteur des cycles. Cultivateur du sens.* 🌙🐇 diff --git a/lunar/scripts/lunar.sh b/lunar/scripts/lunar.sh new file mode 100755 index 0000000..0a14542 --- /dev/null +++ b/lunar/scripts/lunar.sh @@ -0,0 +1,101 @@ +#!/bin/bash +# Lunar & Biodynamic Calendar Tool +# Usage: lunar.sh [today|week|holistic|YYYY-MM-DD] [location] + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + +show_lunar() { + local date="$1" + if [ -z "$date" ]; then + python3 "$SCRIPT_DIR/lunar_calc.py" + else + python3 "$SCRIPT_DIR/lunar_calc.py" "$date" + fi +} + +format_output() { + local data date phase emoji illum age cycle zodiac element elem_emoji movement move_sym + local in_tips=false + local tips="" + + data=$(cat) + + # Parse all data first + while IFS= read -r line; do + if [[ "$line" == TIPS:* ]]; then + in_tips=true + continue + fi + + if [ "$in_tips" = true ]; then + # This is a tip line + tips+="$line"$'\n' + else + # Parse key:value pairs + key="${line%%:*}" + value="${line#*:}" + case "$key" in + DATE) date="$value" ;; + PHASE) phase="$value" ;; + EMOJI) emoji="$value" ;; + ILLUMINATION) illum="$value" ;; + AGE) age="$value" ;; + CYCLE) cycle="$value" ;; + ZODIAC) zodiac="$value" ;; + ELEMENT) element="$value" ;; + ELEMENT_EMOJI) elem_emoji="$value" ;; + MOVEMENT) movement="$value" ;; + MOVEMENT_SYMBOL) move_sym="$value" ;; + esac + fi + done <<< "$data" + + # Display formatted output + echo "🌙 Lecture Lunaire — $date" + echo "" + echo "$emoji $phase ($cycle)" + echo " Illumination: ${illum}%" + echo " Âge lunaire: ${age} jours" + echo "" + echo "$elem_emoji Jour $element (constellation: $zodiac)" + echo "$move_sym Lune $movement" + + # Display tips + if [ -n "$tips" ]; then + echo "" + echo "📋 Recommandations Biodynamiques:" + echo "$tips" + fi +} + +case "${1:-today}" in + today) + show_lunar "" | format_output + ;; + + week) + for i in {0..6}; do + date=$(date -d "+$i days" +%Y-%m-%d 2>/dev/null || date -v+${i}d +%Y-%m-%d) + echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" + show_lunar "$date" | format_output + echo "" + done + ;; + + holistic) + location="${2:-Canton+de+Vaud}" + echo "🌍 Lecture Holistique — Environnement Complet" + echo "" + echo "━━━ MÉTÉO ━━━━━━━━━━━━━━━━━━━━━━━━━━━" + curl -s "wttr.in/${location}?format=%l:+%c+%t+%h+%w+%m" 2>/dev/null || echo "Météo indisponible" + echo "" + echo "" + echo "━━━ LUNE & BIODYNAMIE ━━━━━━━━━━━━━━" + show_lunar "" | format_output + ;; + + *) + # Assume it's a date in YYYY-MM-DD format + show_lunar "$1" | format_output + ;; +esac diff --git a/lunar/scripts/lunar_calc.py b/lunar/scripts/lunar_calc.py new file mode 100755 index 0000000..c1711f1 --- /dev/null +++ b/lunar/scripts/lunar_calc.py @@ -0,0 +1,195 @@ +#!/usr/bin/env python3 +""" +Lunar phase and biodynamic calendar calculator. +No external dependencies except standard library. +""" + +import sys +import math +from datetime import datetime, timedelta + +def julian_date(dt): + """Convert datetime to Julian Date.""" + a = (14 - dt.month) // 12 + y = dt.year + 4800 - a + m = dt.month + 12 * a - 3 + jdn = dt.day + (153 * m + 2) // 5 + 365 * y + y // 4 - y // 100 + y // 400 - 32045 + jd = jdn + (dt.hour - 12) / 24 + dt.minute / 1440 + dt.second / 86400 + return jd + +def moon_phase(dt): + """ + Calculate moon phase for given datetime. + Returns: (phase_name, illumination_percent, age_days, emoji) + """ + # Known new moon: 2000-01-06 18:14 UTC + known_new_moon = datetime(2000, 1, 6, 18, 14) + synodic_month = 29.530588861 # days + + diff = (dt - known_new_moon).total_seconds() / 86400 + phase_cycle = diff % synodic_month + age = phase_cycle + + # Calculate illumination + illumination = (1 - math.cos(2 * math.pi * phase_cycle / synodic_month)) / 2 * 100 + + # Determine phase name + if age < 1.84566: + phase_name = "Nouvelle Lune" + emoji = "🌑" + elif age < 5.53699: + phase_name = "Premier Croissant" + emoji = "🌒" + elif age < 9.22831: + phase_name = "Premier Quartier" + emoji = "🌓" + elif age < 12.91963: + phase_name = "Gibbeuse Croissante" + emoji = "🌔" + elif age < 16.61096: + phase_name = "Pleine Lune" + emoji = "🌕" + elif age < 20.30228: + phase_name = "Gibbeuse Décroissante" + emoji = "🌖" + elif age < 23.99361: + phase_name = "Dernier Quartier" + emoji = "🌗" + elif age < 27.68493: + phase_name = "Dernier Croissant" + emoji = "🌘" + else: + phase_name = "Nouvelle Lune" + emoji = "🌑" + + waxing = age < synodic_month / 2 + + return { + "phase": phase_name, + "emoji": emoji, + "illumination": round(illumination, 1), + "age": round(age, 1), + "waxing": waxing, + "cycle_name": "Croissante" if waxing else "Décroissante" + } + +def zodiac_sign(dt): + """ + Calculate zodiac sign for moon position (simplified tropical calculation). + Returns constellation for Michel Gros calendar. + """ + # Simplified: moon traverses zodiac ~monthly + # This is approximate - real calculation needs ephemeris + day_of_year = dt.timetuple().tm_yday + lunar_month_offset = (dt.day / 29.53) * 360 + + # Approximate zodiac position (simplified) + signs = [ + ("Bélier", "Fruit", "🍎"), + ("Taureau", "Racine", "🥕"), + ("Gémeaux", "Fleur", "🌸"), + ("Cancer", "Feuille", "🌿"), + ("Lion", "Fruit", "🍎"), + ("Vierge", "Racine", "🥕"), + ("Balance", "Fleur", "🌸"), + ("Scorpion", "Feuille", "🌿"), + ("Sagittaire", "Fruit", "🍎"), + ("Capricorne", "Racine", "🥕"), + ("Verseau", "Fleur", "🌸"), + ("Poissons", "Feuille", "🌿") + ] + + # Rough approximation based on date (2.5 days per sign average) + days_since_new_year = (dt - datetime(dt.year, 1, 1)).days + # Moon takes ~27.3 days for zodiac cycle + zodiac_cycle_days = 27.3 + position = (days_since_new_year % zodiac_cycle_days) / zodiac_cycle_days * 12 + sign_index = int(position) % 12 + + return { + "sign": signs[sign_index][0], + "element": signs[sign_index][1], + "emoji": signs[sign_index][2] + } + +def ascending_descending(dt): + """ + Calculate if moon is ascending or descending. + Simplified: based on zodiac position. + Ascending: Sagittarius → Gemini + Descending: Gemini → Sagittarius + """ + zodiac = zodiac_sign(dt) + ascending_signs = ["Sagittaire", "Capricorne", "Verseau", "Poissons", "Bélier", "Taureau", "Gémeaux"] + + is_ascending = zodiac["sign"] in ascending_signs + + return { + "ascending": is_ascending, + "name": "Montante" if is_ascending else "Descendante", + "symbol": "↗️" if is_ascending else "↘️" + } + +def recommendations(phase_data, zodiac_data, asc_desc): + """Generate biodynamic recommendations.""" + tips = [] + + element = zodiac_data["element"] + waxing = phase_data["waxing"] + ascending = asc_desc["ascending"] + + # Day type recommendation + if element == "Racine": + tips.append(f"Jour Racine 🥕 : carottes, pommes de terre, oignons, radis") + elif element == "Feuille": + tips.append(f"Jour Feuille 🌿 : salades, épinards, choux, herbes") + elif element == "Fruit": + tips.append(f"Jour Fruit 🍎 : tomates, courges, haricots, arbres fruitiers") + elif element == "Fleur": + tips.append(f"Jour Fleur 🌸 : fleurs, brocoli, chou-fleur, artichaut") + + # Moon cycle recommendation + if waxing and ascending: + tips.append("🌱 Excellent pour SEMIS (sève monte, croissance active)") + elif waxing and not ascending: + tips.append("🌿 Bon pour PLANTATION/REPIQUAGE (croissance + enracinement)") + elif not waxing and ascending: + tips.append("✂️ Bon pour RÉCOLTE feuilles/fruits (sève haute, moins d'enracinement)") + elif not waxing and not ascending: + tips.append("🥕 Excellent pour RÉCOLTE conservation, TAILLE, TRAVAIL DU SOL") + + return tips + +def main(): + if len(sys.argv) > 1: + try: + target_date = datetime.strptime(sys.argv[1], "%Y-%m-%d") + except: + print(f"Invalid date format. Use YYYY-MM-DD", file=sys.stderr) + sys.exit(1) + else: + target_date = datetime.now() + + phase = moon_phase(target_date) + zodiac = zodiac_sign(target_date) + asc_desc = ascending_descending(target_date) + tips = recommendations(phase, zodiac, asc_desc) + + # Output as simple parseable format + print(f"DATE:{target_date.strftime('%Y-%m-%d')}") + print(f"PHASE:{phase['phase']}") + print(f"EMOJI:{phase['emoji']}") + print(f"ILLUMINATION:{phase['illumination']}") + print(f"AGE:{phase['age']}") + print(f"CYCLE:{phase['cycle_name']}") + print(f"ZODIAC:{zodiac['sign']}") + print(f"ELEMENT:{zodiac['element']}") + print(f"ELEMENT_EMOJI:{zodiac['emoji']}") + print(f"MOVEMENT:{asc_desc['name']}") + print(f"MOVEMENT_SYMBOL:{asc_desc['symbol']}") + print("TIPS:") + for tip in tips: + print(f" {tip}") + +if __name__ == "__main__": + main() diff --git a/weather/SKILL.md b/weather/SKILL.md new file mode 100644 index 0000000..15c88f4 --- /dev/null +++ b/weather/SKILL.md @@ -0,0 +1,54 @@ +--- +name: weather +description: Get current weather and forecasts (no API key required). +homepage: https://wttr.in/:help +metadata: { "openclaw": { "emoji": "🌤️", "requires": { "bins": ["curl"] } } } +--- + +# Weather + +Two free services, no API keys needed. + +## wttr.in (primary) + +Quick one-liner: + +```bash +curl -s "wttr.in/London?format=3" +# Output: London: ⛅️ +8°C +``` + +Compact format: + +```bash +curl -s "wttr.in/London?format=%l:+%c+%t+%h+%w" +# Output: London: ⛅️ +8°C 71% ↙5km/h +``` + +Full forecast: + +```bash +curl -s "wttr.in/London?T" +``` + +Format codes: `%c` condition · `%t` temp · `%h` humidity · `%w` wind · `%l` location · `%m` moon + +Tips: + +- URL-encode spaces: `wttr.in/New+York` +- Airport codes: `wttr.in/JFK` +- Units: `?m` (metric) `?u` (USCS) +- Today only: `?1` · Current only: `?0` +- PNG: `curl -s "wttr.in/Berlin.png" -o /tmp/weather.png` + +## Open-Meteo (fallback, JSON) + +Free, no key, good for programmatic use: + +```bash +curl -s "https://api.open-meteo.com/v1/forecast?latitude=51.5&longitude=-0.12¤t_weather=true" +``` + +Find coordinates for a city, then query. Returns JSON with temp, windspeed, weathercode. + +Docs: https://open-meteo.com/en/docs