diff --git a/agent-communication/SKILL.md b/agent-communication/SKILL.md
new file mode 100644
index 0000000..0ac77b3
--- /dev/null
+++ b/agent-communication/SKILL.md
@@ -0,0 +1,30 @@
+---
+name: agent-communication
+description: How the agent communicates with this user — conciseness, code display, decision-making, and tone rules that apply across all tasks and profiles.
+version: 1.0.0
+---
+
+# Agent Communication Style
+
+User-enforced rules for how the agent communicates. These apply universally — every task, every profile, every session. Violating any of these triggers a strong negative correction.
+
+## Rules
+
+1. **Concise always.** No long multi-section explanations. No fluff. Trim to what's needed. The user will ask for detail if they want it. Prefer short direct answers over comprehensive ones.
+
+2. **Never show code unless explicitly requested.** Describe what changed, not the diff. The user can open the file. Code blocks are unwelcome by default — only emit them when the user says "show me the code" or equivalent.
+
+3. **Never assume or pick a default.** When offering choices, present them clearly and wait for the user to pick. Picking for the user — even when a default seems obvious or low-stakes — triggers a strong negative correction. Treat this as a hard rule. The user makes their own decisions.
+
+4. **Follow instructions exactly.** If the user says "discuss only" or "don't build yet," do not start building. If they say "fix all," fix all. Do not add extra steps or scope creep without asking.
+
+## Pitfalls
+
+- **Over-explaining after a correction.** When corrected, acknowledge briefly and fix. Do not explain why you made the mistake or what you learned — just apply the correction.
+- **Offering unsolicited options.** If the user hasn't asked "what are my options," don't enumerate them. Answer the question asked.
+- **Code blocks in responses.** Default to no code. Only include code when the user explicitly requests it (e.g., "show me the command" or "what's the exact syntax").
+- **Picking option A when the user hasn't chosen.** Even when one option is clearly best, wait. The user's correction on 2026-06-21 ("I did not pick an option!!") is the canonical example.
+
+## Trigger
+
+Load this skill at the start of every session. It governs all agent behavior, not a specific task class.
diff --git a/airtable/SKILL.md b/airtable/SKILL.md
new file mode 100644
index 0000000..3fa1b0a
--- /dev/null
+++ b/airtable/SKILL.md
@@ -0,0 +1,229 @@
+---
+name: airtable
+description: Airtable REST API via curl. Records CRUD, filters, upserts.
+version: 1.1.0
+author: community
+license: MIT
+platforms: [linux, macos, windows]
+prerequisites:
+ env_vars: [AIRTABLE_API_KEY]
+ commands: [curl]
+metadata:
+ hermes:
+ tags: [Airtable, Productivity, Database, API]
+ homepage: https://airtable.com/developers/web/api/introduction
+---
+
+# Airtable — Bases, Tables & Records
+
+Work with Airtable's REST API directly via `curl` using the `terminal` tool. No MCP server, no OAuth flow, no Python SDK — just `curl` and a personal access token.
+
+## Prerequisites
+
+1. Create a **Personal Access Token (PAT)** at https://airtable.com/create/tokens (tokens start with `pat...`).
+2. Grant these scopes (minimum):
+ - `data.records:read` — read rows
+ - `data.records:write` — create / update / delete rows
+ - `schema.bases:read` — list bases and tables
+3. **Important:** in the same token UI, add each base you want to access to the token's **Access** list. PATs are scoped per-base — a valid token on the wrong base returns `403`.
+4. Store the token in `${HERMES_HOME:-~/.hermes}/.env` (or via `hermes setup`):
+ ```
+ AIRTABLE_API_KEY=pat_your_token_here
+ ```
+
+> Note: legacy `key...` API keys were deprecated Feb 2024. Only PATs and OAuth tokens work now.
+
+## API Basics
+
+- **Endpoint:** `https://api.airtable.com/v0`
+- **Auth header:** `Authorization: Bearer $AIRTABLE_API_KEY`
+- **All requests** use JSON (`Content-Type: application/json` for any POST/PATCH/PUT body).
+- **Object IDs:** bases `app...`, tables `tbl...`, records `rec...`, fields `fld...`. IDs never change; names can. Prefer IDs in automations.
+- **Rate limit:** 5 requests/sec/base. `429` → back off. Burst on a single base will be throttled.
+
+Base curl pattern:
+```bash
+curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?maxRecords=5" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
+```
+
+`-s` suppresses curl's progress bar — keep it set for every call so the tool output stays clean for Hermes. Pipe through `python3 -m json.tool` (always present) or `jq` (if installed) for readable JSON.
+
+## Field Types (request body shapes)
+
+| Field type | Write shape |
+|---|---|
+| Single line text | `"Name": "hello"` |
+| Long text | `"Notes": "multi\nline"` |
+| Number | `"Score": 42` |
+| Checkbox | `"Done": true` |
+| Single select | `"Status": "Todo"` (name must already exist unless `typecast: true`) |
+| Multi-select | `"Tags": ["urgent", "bug"]` |
+| Date | `"Due": "2026-04-01"` |
+| DateTime (UTC) | `"At": "2026-04-01T14:30:00.000Z"` |
+| URL / Email / Phone | `"Link": "https://…"` |
+| Attachment | `"Files": [{"url": "https://…"}]` (Airtable fetches + rehosts) |
+| Linked record | `"Owner": ["recXXXXXXXXXXXXXX"]` (array of record IDs) |
+| User | `"AssignedTo": {"id": "usrXXXXXXXXXXXXXX"}` |
+
+Pass `"typecast": true` at the top level of a create/update body to let Airtable auto-coerce values (e.g. create a new select option on the fly, convert `"42"` → `42`).
+
+## Common Queries
+
+### List bases the token can see
+```bash
+curl -s "https://api.airtable.com/v0/meta/bases" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
+```
+
+### List tables + schema for a base
+```bash
+curl -s "https://api.airtable.com/v0/meta/bases/$BASE_ID/tables" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
+```
+Use this BEFORE mutating — confirms exact field names and IDs, surfaces `options.choices` for select fields, and shows primary-field names.
+
+### List records (first 10)
+```bash
+curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?maxRecords=10" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
+```
+
+### Get a single record
+```bash
+curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
+```
+
+### Filter records (filterByFormula)
+Airtable formulas must be URL-encoded. Let Python stdlib do it — never hand-encode:
+```bash
+FORMULA="{Status}='Todo'"
+ENC=$(python3 -c 'import sys, urllib.parse; print(urllib.parse.quote(sys.argv[1], safe=""))' "$FORMULA")
+curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?filterByFormula=$ENC&maxRecords=20" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
+```
+
+Useful formula patterns:
+- Exact match: `{Email}='user@example.com'`
+- Contains: `FIND('bug', LOWER({Title}))`
+- Multiple conditions: `AND({Status}='Todo', {Priority}='High')`
+- Or: `OR({Owner}='alice', {Owner}='bob')`
+- Not empty: `NOT({Assignee}='')`
+- Date comparison: `IS_AFTER({Due}, TODAY())`
+
+### Sort + select specific fields
+```bash
+curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?sort%5B0%5D%5Bfield%5D=Priority&sort%5B0%5D%5Bdirection%5D=asc&fields%5B%5D=Name&fields%5B%5D=Status" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
+```
+Square brackets in query params MUST be URL-encoded (`%5B` / `%5D`).
+
+### Use a named view
+```bash
+curl -s "https://api.airtable.com/v0/$BASE_ID/$TABLE?view=Grid%20view&maxRecords=50" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
+```
+Views apply their saved filter + sort server-side.
+
+## Common Mutations
+
+### Create a record
+```bash
+curl -s -X POST "https://api.airtable.com/v0/$BASE_ID/$TABLE" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{"fields":{"Name":"New task","Status":"Todo","Priority":"High"}}' | python3 -m json.tool
+```
+
+### Create up to 10 records in one call
+```bash
+curl -s -X POST "https://api.airtable.com/v0/$BASE_ID/$TABLE" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "typecast": true,
+ "records": [
+ {"fields": {"Name": "Task A", "Status": "Todo"}},
+ {"fields": {"Name": "Task B", "Status": "In progress"}}
+ ]
+ }' | python3 -m json.tool
+```
+Batch endpoints are capped at **10 records per request**. For larger inserts, loop in batches of 10 with a short sleep to respect 5 req/sec/base.
+
+### Update a record (PATCH — merges, preserves unchanged fields)
+```bash
+curl -s -X PATCH "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{"fields":{"Status":"Done"}}' | python3 -m json.tool
+```
+
+### Upsert by a merge field (no ID needed)
+```bash
+curl -s -X PATCH "https://api.airtable.com/v0/$BASE_ID/$TABLE" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" \
+ -H "Content-Type: application/json" \
+ -d '{
+ "performUpsert": {"fieldsToMergeOn": ["Email"]},
+ "records": [
+ {"fields": {"Email": "user@example.com", "Status": "Active"}}
+ ]
+ }' | python3 -m json.tool
+```
+`performUpsert` creates records whose merge-field values are new, patches records whose merge-field values already exist. Great for idempotent syncs.
+
+### Delete a record
+```bash
+curl -s -X DELETE "https://api.airtable.com/v0/$BASE_ID/$TABLE/$RECORD_ID" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
+```
+
+### Delete up to 10 records in one call
+```bash
+curl -s -X DELETE "https://api.airtable.com/v0/$BASE_ID/$TABLE?records%5B%5D=rec1&records%5B%5D=rec2" \
+ -H "Authorization: Bearer $AIRTABLE_API_KEY" | python3 -m json.tool
+```
+
+## Pagination
+
+List endpoints return at most **100 records per page**. If the response includes `"offset": "..."`, pass it back on the next call. Loop until the field is absent:
+
+```bash
+OFFSET=""
+while :; do
+ URL="https://api.airtable.com/v0/$BASE_ID/$TABLE?pageSize=100"
+ [ -n "$OFFSET" ] && URL="$URL&offset=$OFFSET"
+ RESP=$(curl -s "$URL" -H "Authorization: Bearer $AIRTABLE_API_KEY")
+ echo "$RESP" | python3 -c 'import json,sys; d=json.load(sys.stdin); [print(r["id"], r["fields"].get("Name","")) for r in d["records"]]'
+ OFFSET=$(echo "$RESP" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(d.get("offset",""))')
+ [ -z "$OFFSET" ] && break
+done
+```
+
+## Typical Hermes Workflow
+
+1. **Confirm auth.** `curl -s -o /dev/null -w "%{http_code}\n" https://api.airtable.com/v0/meta/bases -H "Authorization: Bearer $AIRTABLE_API_KEY"` — expect `200`.
+2. **Find the base.** List bases (step above) OR ask the user for the `app...` ID directly if the token lacks `schema.bases:read`.
+3. **Inspect the schema.** `GET /v0/meta/bases/$BASE_ID/tables` — cache the exact field names and primary-field name locally in the session before mutating anything.
+4. **Read before you write.** For "update X where Y", `filterByFormula` first to resolve the `rec...` ID, then `PATCH /v0/$BASE_ID/$TABLE/$RECORD_ID`. Never guess record IDs.
+5. **Batch writes.** Combine related creates into one 10-record POST to stay under the 5 req/sec budget.
+6. **Destructive ops.** Deletions can't be undone via API. If the user says "delete all Xs", echo back the filter + record count and confirm before firing.
+
+## Pitfalls
+
+- **`filterByFormula` MUST be URL-encoded.** Field names with spaces or non-ASCII also need encoding (`{My Field}` → `%7BMy%20Field%7D`). Use Python stdlib (pattern above) — never hand-escape.
+- **Empty fields are omitted from responses.** A missing `"Assignee"` key doesn't mean the field doesn't exist — it means this record's value is empty. Check the schema (step 3) before concluding a field is missing.
+- **PATCH vs PUT.** `PATCH` merges supplied fields into the record. `PUT` replaces the record entirely and clears any field you didn't include. Default to `PATCH`.
+- **Single-select options must exist.** Writing `"Status": "Shipping"` when `Shipping` isn't in the field's option list errors with `INVALID_MULTIPLE_CHOICE_OPTIONS` unless you pass `"typecast": true` (which auto-creates the option).
+- **Per-base token scoping.** A `403` on one base while another works means the token's Access list doesn't include that base — not a scope or auth issue. Send the user to https://airtable.com/create/tokens to grant it.
+- **Rate limits are per base, not per token.** 5 req/sec on `baseA` and 5 req/sec on `baseB` is fine; 6 req/sec on `baseA` alone will throttle. Monitor the `Retry-After` header on `429`.
+
+## Important Notes for Hermes
+
+- **Always use the `terminal` tool with `curl`.** Do NOT use `web_extract` (it can't send auth headers) or `browser_navigate` (needs UI auth and is slow).
+- **`AIRTABLE_API_KEY` flows from `${HERMES_HOME:-~/.hermes}/.env` into the subprocess automatically** when this skill is loaded — no need to re-export it before each `curl` call.
+- **Escape curly braces in formulas carefully.** In a heredoc body, `{Status}` is literal. In a shell argument, `{Status}` is safe outside `{...}` brace-expansion context — but pass dynamic strings through `python3 urllib.parse.quote` before splicing into a URL.
+- **Pretty-print with `python3 -m json.tool`** (always present) rather than `jq` (optional). Only reach for `jq` when you need filtering/projection.
+- **Pagination is per-page, not global.** Airtable's 100-record cap is a hard limit; there is no way to bump it. Loop with `offset` until the field is absent.
+- **Read the `errors` array** on non-2xx responses — Airtable returns structured error codes like `AUTHENTICATION_REQUIRED`, `INVALID_PERMISSIONS`, `MODEL_ID_NOT_FOUND`, `INVALID_MULTIPLE_CHOICE_OPTIONS` that tell you exactly what's wrong.
diff --git a/apple-notes/SKILL.md b/apple-notes/SKILL.md
new file mode 100644
index 0000000..020f0d6
--- /dev/null
+++ b/apple-notes/SKILL.md
@@ -0,0 +1,90 @@
+---
+name: apple-notes
+description: "Manage Apple Notes via memo CLI: create, search, edit."
+version: 1.0.0
+author: Hermes Agent
+license: MIT
+platforms: [macos]
+metadata:
+ hermes:
+ tags: [Notes, Apple, macOS, note-taking]
+ related_skills: [obsidian]
+prerequisites:
+ commands: [memo]
+---
+
+# Apple Notes
+
+Use `memo` to manage Apple Notes directly from the terminal. Notes sync across all Apple devices via iCloud.
+
+## Prerequisites
+
+- **macOS** with Notes.app
+- Install: `brew tap antoniorodr/memo && brew install antoniorodr/memo/memo`
+- Grant Automation access to Notes.app when prompted (System Settings → Privacy → Automation)
+
+## When to Use
+
+- User asks to create, view, or search Apple Notes
+- Saving information to Notes.app for cross-device access
+- Organizing notes into folders
+- Exporting notes to Markdown/HTML
+
+## When NOT to Use
+
+- Obsidian vault management → use the `obsidian` skill
+- Bear Notes → separate app (not supported here)
+- Quick agent-only notes → use the `memory` tool instead
+
+## Quick Reference
+
+### View Notes
+
+```bash
+memo notes # List all notes
+memo notes -f "Folder Name" # Filter by folder
+memo notes -s "query" # Search notes (fuzzy)
+```
+
+### Create Notes
+
+```bash
+memo notes -a # Interactive editor
+memo notes -a "Note Title" # Quick add with title
+```
+
+### Edit Notes
+
+```bash
+memo notes -e # Interactive selection to edit
+```
+
+### Delete Notes
+
+```bash
+memo notes -d # Interactive selection to delete
+```
+
+### Move Notes
+
+```bash
+memo notes -m # Move note to folder (interactive)
+```
+
+### Export Notes
+
+```bash
+memo notes -ex # Export to HTML/Markdown
+```
+
+## Limitations
+
+- Cannot edit notes containing images or attachments
+- Interactive prompts require terminal access (use pty=true if needed)
+- macOS only — requires Apple Notes.app
+
+## Rules
+
+1. Prefer Apple Notes when user wants cross-device sync (iPhone/iPad/Mac)
+2. Use the `memory` tool for agent-internal notes that don't need to sync
+3. Use the `obsidian` skill for Markdown-native knowledge management
diff --git a/apple-reminders/SKILL.md b/apple-reminders/SKILL.md
new file mode 100644
index 0000000..4536644
--- /dev/null
+++ b/apple-reminders/SKILL.md
@@ -0,0 +1,130 @@
+---
+name: apple-reminders
+description: "Apple Reminders via remindctl: add, list, complete."
+version: 1.0.0
+author: Hermes Agent
+license: MIT
+platforms: [macos]
+metadata:
+ hermes:
+ tags: [Reminders, tasks, todo, macOS, Apple]
+prerequisites:
+ commands: [remindctl]
+---
+
+# Apple Reminders
+
+Use `remindctl` to manage Apple Reminders directly from the terminal. Tasks sync across all Apple devices via iCloud.
+
+## Prerequisites
+
+- **macOS** with Reminders.app
+- Install: `brew install steipete/tap/remindctl`
+- Grant Reminders permission when prompted
+- Check: `remindctl status` / Request: `remindctl authorize`
+
+## When to Use
+
+- User mentions "reminder" or "Reminders app"
+- Creating personal to-dos with due dates that sync to iOS
+- Managing Apple Reminders lists
+- User wants tasks to appear on their iPhone/iPad
+
+## When NOT to Use
+
+- Scheduling agent alerts → use the cronjob tool instead
+- Calendar events → use Apple Calendar or Google Calendar
+- Project task management → use GitHub Issues, Notion, etc.
+- If user says "remind me" but means an agent alert → clarify first
+
+## Quick Reference
+
+### View Reminders
+
+```bash
+remindctl # Today's reminders
+remindctl today # Today
+remindctl tomorrow # Tomorrow
+remindctl week # This week
+remindctl overdue # Past due
+remindctl all # Everything
+remindctl 2026-01-04 # Specific date
+```
+
+### Manage Lists
+
+```bash
+remindctl list # List all lists
+remindctl list Work # Show specific list
+remindctl list Projects --create # Create list
+remindctl list Work --delete # Delete list
+```
+
+### Create Reminders
+
+```bash
+remindctl add "Buy milk"
+remindctl add --title "Call mom" --list Personal --due tomorrow
+remindctl add --title "Meeting prep" --due "2026-02-15 09:00"
+```
+
+### Due Time vs Alarm / Early Nudge
+
+`--due` and `--alarm` are different fields:
+
+- `--due` sets the reminder's due date/time.
+- `--alarm` sets the EventKit alarm/notification trigger. Timed due reminders may default to an alarm at the due time, but pass `--alarm` explicitly when the user asks for an earlier nudge.
+
+For a reminder due at 2:00 PM with a notification 30 minutes earlier:
+
+```bash
+remindctl add --title "Hairdresser" --due "2026-05-15 14:00" --alarm "2026-05-15 13:30"
+```
+
+To edit an existing reminder:
+
+```bash
+remindctl edit 87354 --due "2026-05-15 14:00" --alarm "2026-05-15 13:30"
+```
+
+The Reminders UI may show or group the item by the alarm time because that is when the notification fires. Verify with JSON instead of assuming the due time moved:
+
+```bash
+remindctl today --json
+```
+
+Expected shape:
+
+- `dueDate`: actual due time
+- `alarmDate`: notification / early nudge time
+
+Apple's public `EKReminder` docs list only reminder-specific properties. Alarm support comes from inherited `EKCalendarItem` behavior exposed by remindctl's `--alarm` flag.
+
+### Complete / Delete
+
+```bash
+remindctl complete 1 2 3 # Complete by ID
+remindctl delete 4A83 --force # Delete by ID
+```
+
+### Output Formats
+
+```bash
+remindctl today --json # JSON for scripting
+remindctl today --plain # TSV format
+remindctl today --quiet # Counts only
+```
+
+## Date Formats
+
+Accepted by `--due` and date filters:
+- `today`, `tomorrow`, `yesterday`
+- `YYYY-MM-DD`
+- `YYYY-MM-DD HH:mm`
+- ISO 8601 (`2026-01-04T12:34:56Z`)
+
+## Rules
+
+1. When user says "remind me", clarify: Apple Reminders (syncs to phone) vs agent cronjob alert
+2. Always confirm reminder content and due date before creating
+3. Use `--json` for programmatic parsing
diff --git a/architecture-diagram/SKILL.md b/architecture-diagram/SKILL.md
new file mode 100644
index 0000000..2c813c5
--- /dev/null
+++ b/architecture-diagram/SKILL.md
@@ -0,0 +1,148 @@
+---
+name: architecture-diagram
+description: "Dark-themed SVG architecture/cloud/infra diagrams as HTML."
+version: 1.0.0
+author: Cocoon AI (hello@cocoon-ai.com), ported by Hermes Agent
+license: MIT
+dependencies: []
+platforms: [linux, macos, windows]
+metadata:
+ hermes:
+ tags: [architecture, diagrams, SVG, HTML, visualization, infrastructure, cloud]
+ related_skills: [concept-diagrams, excalidraw]
+---
+
+# Architecture Diagram Skill
+
+Generate professional, dark-themed technical architecture diagrams as standalone HTML files with inline SVG graphics. No external tools, no API keys, no rendering libraries — just write the HTML file and open it in a browser.
+
+## Scope
+
+**Best suited for:**
+- Software system architecture (frontend / backend / database layers)
+- Cloud infrastructure (VPC, regions, subnets, managed services)
+- Microservice / service-mesh topology
+- Database + API map, deployment diagrams
+- Anything with a tech-infra subject that fits a dark, grid-backed aesthetic
+
+**Look elsewhere first for:**
+- Physics, chemistry, math, biology, or other scientific subjects
+- Physical objects (vehicles, hardware, anatomy, cross-sections)
+- Floor plans, narrative journeys, educational / textbook-style visuals
+- Hand-drawn whiteboard sketches (consider `excalidraw`)
+- Animated explainers (consider an animation skill)
+
+If a more specialized skill is available for the subject, prefer that. If none fits, this skill can also serve as a general SVG diagram fallback — the output will just carry the dark tech aesthetic described below.
+
+Based on [Cocoon AI's architecture-diagram-generator](https://github.com/Cocoon-AI/architecture-diagram-generator) (MIT).
+
+## Workflow
+
+1. User describes their system architecture (components, connections, technologies)
+2. Generate the HTML file following the design system below
+3. Save with `write_file` to a `.html` file (e.g. `~/architecture-diagram.html`)
+4. User opens in any browser — works offline, no dependencies
+
+### Output Location
+
+Save diagrams to a user-specified path, or default to the current working directory:
+```
+./[project-name]-architecture.html
+```
+
+### Preview
+
+After saving, suggest the user open it:
+```bash
+# macOS
+open ./my-architecture.html
+# Linux
+xdg-open ./my-architecture.html
+```
+
+## Design System & Visual Language
+
+### Color Palette (Semantic Mapping)
+
+Use specific `rgba` fills and hex strokes to categorize components:
+
+| Component Type | Fill (rgba) | Stroke (Hex) |
+| :--- | :--- | :--- |
+| **Frontend** | `rgba(8, 51, 68, 0.4)` | `#22d3ee` (cyan-400) |
+| **Backend** | `rgba(6, 78, 59, 0.4)` | `#34d399` (emerald-400) |
+| **Database** | `rgba(76, 29, 149, 0.4)` | `#a78bfa` (violet-400) |
+| **AWS/Cloud** | `rgba(120, 53, 15, 0.3)` | `#fbbf24` (amber-400) |
+| **Security** | `rgba(136, 19, 55, 0.4)` | `#fb7185` (rose-400) |
+| **Message Bus** | `rgba(251, 146, 60, 0.3)` | `#fb923c` (orange-400) |
+| **External** | `rgba(30, 41, 59, 0.5)` | `#94a3b8` (slate-400) |
+
+### Typography & Background
+- **Font:** JetBrains Mono (Monospace), loaded from Google Fonts
+- **Sizes:** 12px (Names), 9px (Sublabels), 8px (Annotations), 7px (Tiny labels)
+- **Background:** Slate-950 (`#020617`) with a subtle 40px grid pattern
+
+```svg
+
+
` tags. Fetch the page with curl, then extract art with a small Python snippet.
+
+**URL pattern:** `https://ascii.co.uk/art/{subject}`
+
+**Step 1 — Fetch the page:**
+
+```bash
+curl -s 'https://ascii.co.uk/art/cat' -o /tmp/ascii_art.html
+```
+
+**Step 2 — Extract art from pre tags:**
+
+```python
+import re, html
+with open('/tmp/ascii_art.html') as f:
+ text = f.read()
+arts = re.findall(r']*>(.*?)
', text, re.DOTALL)
+for art in arts:
+ clean = re.sub(r'<[^>]+>', '', art)
+ clean = html.unescape(clean).strip()
+ if len(clean) > 30:
+ print(clean)
+ print('\n---\n')
+```
+
+**Available subjects** (use as URL path):
+- Animals: `cat`, `dog`, `horse`, `bird`, `fish`, `dragon`, `snake`, `rabbit`, `elephant`, `dolphin`, `butterfly`, `owl`, `wolf`, `bear`, `penguin`, `turtle`
+- Objects: `car`, `ship`, `airplane`, `rocket`, `guitar`, `computer`, `coffee`, `beer`, `cake`, `house`, `castle`, `sword`, `crown`, `key`
+- Nature: `tree`, `flower`, `sun`, `moon`, `star`, `mountain`, `ocean`, `rainbow`
+- Characters: `skull`, `robot`, `angel`, `wizard`, `pirate`, `ninja`, `alien`
+- Holidays: `christmas`, `halloween`, `valentine`
+
+**Tips:**
+- Preserve artist signatures/initials — important etiquette
+- Multiple art pieces per page — pick the best one for the user
+- Works reliably via curl, no JavaScript needed
+
+### Source B: GitHub Octocat API (fun easter egg)
+
+Returns a random GitHub Octocat with a wise quote. No auth needed.
+
+```bash
+curl -s https://api.github.com/octocat
+```
+
+## Tool 8: Fun ASCII Utilities (via curl)
+
+These free services return ASCII art directly — great for fun extras.
+
+### QR Codes as ASCII Art
+
+```bash
+curl -s "qrenco.de/Hello+World"
+curl -s "qrenco.de/https://example.com"
+```
+
+### Weather as ASCII Art
+
+```bash
+curl -s "wttr.in/London" # Full weather report with ASCII graphics
+curl -s "wttr.in/Moon" # Moon phase in ASCII art
+curl -s "v2.wttr.in/London" # Detailed version
+```
+
+## Tool 9: LLM-Generated Custom Art (Fallback)
+
+When tools above don't have what's needed, generate ASCII art directly using these Unicode characters:
+
+### Character Palette
+
+**Box Drawing:** `╔ ╗ ╚ ╝ ║ ═ ╠ ╣ ╦ ╩ ╬ ┌ ┐ └ ┘ │ ─ ├ ┤ ┬ ┴ ┼ ╭ ╮ ╰ ╯`
+
+**Block Elements:** `░ ▒ ▓ █ ▄ ▀ ▌ ▐ ▖ ▗ ▘ ▝ ▚ ▞`
+
+**Geometric & Symbols:** `◆ ◇ ◈ ● ○ ◉ ■ □ ▲ △ ▼ ▽ ★ ☆ ✦ ✧ ◀ ▶ ◁ ▷ ⬡ ⬢ ⌂`
+
+### Rules
+
+- Max width: 60 characters per line (terminal-safe)
+- Max height: 15 lines for banners, 25 for scenes
+- Monospace only: output must render correctly in fixed-width fonts
+
+## Decision Flow
+
+1. **Text as a banner** → pyfiglet if installed, otherwise asciified API via curl
+2. **Wrap a message in fun character art** → cowsay
+3. **Add decorative border/frame** → boxes (can combine with pyfiglet/asciified)
+4. **Art of a specific thing** (cat, rocket, dragon) → ascii.co.uk via curl + parsing
+5. **Convert an image to ASCII** → ascii-image-converter or jp2a
+6. **QR code** → qrenco.de via curl
+7. **Weather/moon art** → wttr.in via curl
+8. **Something custom/creative** → LLM generation with Unicode palette
+9. **Any tool not installed** → install it, or fall back to next option
diff --git a/ascii-video/SKILL.md b/ascii-video/SKILL.md
new file mode 100644
index 0000000..2a42e31
--- /dev/null
+++ b/ascii-video/SKILL.md
@@ -0,0 +1,242 @@
+---
+name: ascii-video
+description: "ASCII video: convert video/audio to colored ASCII MP4/GIF."
+version: 1.0.0
+platforms: [linux, macos, windows]
+---
+
+# ASCII Video Production Pipeline
+
+## When to use
+
+Use when users request: ASCII video, text art video, terminal-style video, character art animation, retro text visualization, audio visualizer in ASCII, converting video to ASCII art, matrix-style effects, or any animated ASCII output.
+
+## What's inside
+
+Production pipeline for ASCII art video — any format. Converts video/audio/images/generative input into colored ASCII character video output (MP4, GIF, image sequence). Covers: video-to-ASCII conversion, audio-reactive music visualizers, generative ASCII art animations, hybrid video+audio reactive, text/lyrics overlays, real-time terminal rendering.
+
+## Creative Standard
+
+This is visual art. ASCII characters are the medium; cinema is the standard.
+
+**Before writing a single line of code**, articulate the creative concept. What is the mood? What visual story does this tell? What makes THIS project different from every other ASCII video? The user's prompt is a starting point — interpret it with creative ambition, not literal transcription.
+
+**First-render excellence is non-negotiable.** The output must be visually striking without requiring revision rounds. If something looks generic, flat, or like "AI-generated ASCII art," it is wrong — rethink the creative concept before shipping.
+
+**Go beyond the reference vocabulary.** The effect catalogs, shader presets, and palette libraries in the references are a starting vocabulary. For every project, combine, modify, and invent new patterns. The catalog is a palette of paints — you write the painting.
+
+**Be proactively creative.** Extend the skill's vocabulary when the project calls for it. If the references don't have what the vision demands, build it. Include at least one visual moment the user didn't ask for but will appreciate — a transition, an effect, a color choice that elevates the whole piece.
+
+**Cohesive aesthetic over technical correctness.** All scenes in a video must feel connected by a unifying visual language — shared color temperature, related character palettes, consistent motion vocabulary. A technically correct video where every scene uses a random different effect is an aesthetic failure.
+
+**Dense, layered, considered.** Every frame should reward viewing. Never flat black backgrounds. Always multi-grid composition. Always per-scene variation. Always intentional color.
+
+## Modes
+
+| Mode | Input | Output | Reference |
+|------|-------|--------|-----------|
+| **Video-to-ASCII** | Video file | ASCII recreation of source footage | `references/inputs.md` § Video Sampling |
+| **Audio-reactive** | Audio file | Generative visuals driven by audio features | `references/inputs.md` § Audio Analysis |
+| **Generative** | None (or seed params) | Procedural ASCII animation | `references/effects.md` |
+| **Hybrid** | Video + audio | ASCII video with audio-reactive overlays | Both input refs |
+| **Lyrics/text** | Audio + text/SRT | Timed text with visual effects | `references/inputs.md` § Text/Lyrics |
+| **TTS narration** | Text quotes + TTS API | Narrated testimonial/quote video with typed text | `references/inputs.md` § TTS Integration |
+
+## Stack
+
+Single self-contained Python script per project. No GPU required.
+
+| Layer | Tool | Purpose |
+|-------|------|---------|
+| Core | Python 3.10+, NumPy | Math, array ops, vectorized effects |
+| Signal | SciPy | FFT, peak detection (audio modes) |
+| Imaging | Pillow (PIL) | Font rasterization, frame decoding, image I/O |
+| Video I/O | ffmpeg (CLI) | Decode input, encode output, mux audio |
+| Parallel | concurrent.futures | N workers for batch/clip rendering |
+| TTS | ElevenLabs API (optional) | Generate narration clips |
+| Optional | OpenCV | Video frame sampling, edge detection |
+
+## Pipeline Architecture
+
+Every mode follows the same 6-stage pipeline:
+
+```
+INPUT → ANALYZE → SCENE_FN → TONEMAP → SHADE → ENCODE
+```
+
+1. **INPUT** — Load/decode source material (video frames, audio samples, images, or nothing)
+2. **ANALYZE** — Extract per-frame features (audio bands, video luminance/edges, motion vectors)
+3. **SCENE_FN** — Scene function renders to pixel canvas (`uint8 H,W,3`). Composes multiple character grids via `_render_vf()` + pixel blend modes. See `references/composition.md`
+4. **TONEMAP** — Percentile-based adaptive brightness normalization. See `references/composition.md` § Adaptive Tonemap
+5. **SHADE** — Post-processing via `ShaderChain` + `FeedbackBuffer`. See `references/shaders.md`
+6. **ENCODE** — Pipe raw RGB frames to ffmpeg for H.264/GIF encoding
+
+## Creative Direction
+
+### Aesthetic Dimensions
+
+| Dimension | Options | Reference |
+|-----------|---------|-----------|
+| **Character palette** | Density ramps, block elements, symbols, scripts (katakana, Greek, runes, braille), project-specific | `architecture.md` § Palettes |
+| **Color strategy** | HSV, OKLAB/OKLCH, discrete RGB palettes, auto-generated harmony, monochrome, temperature | `architecture.md` § Color System |
+| **Background texture** | Sine fields, fBM noise, domain warp, voronoi, reaction-diffusion, cellular automata, video | `effects.md` |
+| **Primary effects** | Rings, spirals, tunnel, vortex, waves, interference, aurora, fire, SDFs, strange attractors | `effects.md` |
+| **Particles** | Sparks, snow, rain, bubbles, runes, orbits, flocking boids, flow-field followers, trails | `effects.md` § Particles |
+| **Shader mood** | Retro CRT, clean modern, glitch art, cinematic, dreamy, industrial, psychedelic | `shaders.md` |
+| **Grid density** | xs(8px) through xxl(40px), mixed per layer | `architecture.md` § Grid System |
+| **Coordinate space** | Cartesian, polar, tiled, rotated, fisheye, Möbius, domain-warped | `effects.md` § Transforms |
+| **Feedback** | Zoom tunnel, rainbow trails, ghostly echo, rotating mandala, color evolution | `composition.md` § Feedback |
+| **Masking** | Circle, ring, gradient, text stencil, animated iris/wipe/dissolve | `composition.md` § Masking |
+| **Transitions** | Crossfade, wipe, dissolve, glitch cut, iris, mask-based reveal | `shaders.md` § Transitions |
+
+### Per-Section Variation
+
+Never use the same config for the entire video. For each section/scene:
+- **Different background effect** (or compose 2-3)
+- **Different character palette** (match the mood)
+- **Different color strategy** (or at minimum a different hue)
+- **Vary shader intensity** (more bloom during peaks, more grain during quiet)
+- **Different particle types** if particles are active
+
+### Project-Specific Invention
+
+For every project, invent at least one of:
+- A custom character palette matching the theme
+- A custom background effect (combine/modify existing building blocks)
+- A custom color palette (discrete RGB set matching the brand/mood)
+- A custom particle character set
+- A novel scene transition or visual moment
+
+Don't just pick from the catalog. The catalog is vocabulary — you write the poem.
+
+## Workflow
+
+### Step 1: Creative Vision
+
+Before any code, articulate the creative concept:
+
+- **Mood/atmosphere**: What should the viewer feel? Energetic, meditative, chaotic, elegant, ominous?
+- **Visual story**: What happens over the duration? Build tension? Transform? Dissolve?
+- **Color world**: Warm/cool? Monochrome? Neon? Earth tones? What's the dominant hue?
+- **Character texture**: Dense data? Sparse stars? Organic dots? Geometric blocks?
+- **What makes THIS different**: What's the one thing that makes this project unique?
+- **Emotional arc**: How do scenes progress? Open with energy, build to climax, resolve?
+
+Map the user's prompt to aesthetic choices. A "chill lo-fi visualizer" demands different everything from a "glitch cyberpunk data stream."
+
+### Step 2: Technical Design
+
+- **Mode** — which of the 6 modes above
+- **Resolution** — landscape 1920x1080 (default), portrait 1080x1920, square 1080x1080 @ 24fps
+- **Hardware detection** — auto-detect cores/RAM, set quality profile. See `references/optimization.md`
+- **Sections** — map timestamps to scene functions, each with its own effect/palette/color/shader config
+- **Output format** — MP4 (default), GIF (640x360 @ 15fps), PNG sequence
+
+### Step 3: Build the Script
+
+Single Python file. Components (with references):
+
+1. **Hardware detection + quality profile** — `references/optimization.md`
+2. **Input loader** — mode-dependent; `references/inputs.md`
+3. **Feature analyzer** — audio FFT, video luminance, or synthetic
+4. **Grid + renderer** — multi-density grids with bitmap cache; `references/architecture.md`
+5. **Character palettes** — multiple per project; `references/architecture.md` § Palettes
+6. **Color system** — HSV + discrete RGB + harmony generation; `references/architecture.md` § Color
+7. **Scene functions** — each returns `canvas (uint8 H,W,3)`; `references/scenes.md`
+8. **Tonemap** — adaptive brightness normalization; `references/composition.md`
+9. **Shader pipeline** — `ShaderChain` + `FeedbackBuffer`; `references/shaders.md`
+10. **Scene table + dispatcher** — time → scene function + config; `references/scenes.md`
+11. **Parallel encoder** — N-worker clip rendering with ffmpeg pipes
+12. **Main** — orchestrate full pipeline
+
+### Step 4: Quality Verification
+
+- **Test frames first**: render single frames at key timestamps before full render
+- **Brightness check**: `canvas.mean() > 8` for all ASCII content. If dark, lower gamma
+- **Visual coherence**: do all scenes feel like they belong to the same video?
+- **Creative vision check**: does the output match the concept from Step 1? If it looks generic, go back
+
+## Critical Implementation Notes
+
+### Brightness — Use `tonemap()`, Not Linear Multipliers
+
+This is the #1 visual issue. ASCII on black is inherently dark. **Never use `canvas * N` multipliers** — they clip highlights. Use adaptive tonemap:
+
+```python
+def tonemap(canvas, gamma=0.75):
+ f = canvas.astype(np.float32)
+ lo, hi = np.percentile(f[::4, ::4], [1, 99.5])
+ if hi - lo < 10: hi = lo + 10
+ f = np.clip((f - lo) / (hi - lo), 0, 1) ** gamma
+ return (f * 255).astype(np.uint8)
+```
+
+Pipeline: `scene_fn() → tonemap() → FeedbackBuffer → ShaderChain → ffmpeg`
+
+Per-scene gamma: default 0.75, solarize 0.55, posterize 0.50, bright scenes 0.85. Use `screen` blend (not `overlay`) for dark layers.
+
+### Font Cell Height
+
+macOS Pillow: `textbbox()` returns wrong height. Use `font.getmetrics()`: `cell_height = ascent + descent`. See `references/troubleshooting.md`.
+
+### ffmpeg Pipe Deadlock
+
+Never `stderr=subprocess.PIPE` with long-running ffmpeg — buffer fills at 64KB and deadlocks. Redirect to file. See `references/troubleshooting.md`.
+
+### Font Compatibility
+
+Not all Unicode chars render in all fonts. Validate palettes at init — render each char, check for blank output. See `references/troubleshooting.md`.
+
+### Per-Clip Architecture
+
+For segmented videos (quotes, scenes, chapters), render each as a separate clip file for parallel rendering and selective re-rendering. See `references/scenes.md`.
+
+## Performance Targets
+
+| Component | Budget |
+|-----------|--------|
+| Feature extraction | 1-5ms |
+| Effect function | 2-15ms |
+| Character render | 80-150ms (bottleneck) |
+| Shader pipeline | 5-25ms |
+| **Total** | ~100-200ms/frame |
+
+## References
+
+| File | Contents |
+|------|----------|
+| `references/architecture.md` | Grid system, resolution presets, font selection, character palettes (20+), color system (HSV + OKLAB + discrete RGB + harmony generation), `_render_vf()` helper, GridLayer class |
+| `references/composition.md` | Pixel blend modes (20 modes), `blend_canvas()`, multi-grid composition, adaptive `tonemap()`, `FeedbackBuffer`, `PixelBlendStack`, masking/stencil system |
+| `references/effects.md` | Effect building blocks: value field generators, hue fields, noise/fBM/domain warp, voronoi, reaction-diffusion, cellular automata, SDFs, strange attractors, particle systems, coordinate transforms, temporal coherence |
+| `references/shaders.md` | `ShaderChain`, `_apply_shader_step()` dispatch, 38 shader catalog, audio-reactive scaling, transitions, tint presets, output format encoding, terminal rendering |
+| `references/scenes.md` | Scene protocol, `Renderer` class, `SCENES` table, `render_clip()`, beat-synced cutting, parallel rendering, design patterns (layer hierarchy, directional arcs, visual metaphors, compositional techniques), complete scene examples at every complexity level, scene design checklist |
+| `references/inputs.md` | Audio analysis (FFT, bands, beats), video sampling, image conversion, text/lyrics, TTS integration (ElevenLabs, voice assignment, audio mixing) |
+| `references/optimization.md` | Hardware detection, quality profiles, vectorized patterns, parallel rendering, memory management, performance budgets |
+| `references/troubleshooting.md` | NumPy broadcasting traps, blend mode pitfalls, multiprocessing/pickling, brightness diagnostics, ffmpeg issues, font problems, common mistakes |
+
+---
+
+## Creative Divergence (use only when user requests experimental/creative/unique output)
+
+If the user asks for creative, experimental, surprising, or unconventional output, select the strategy that best fits and reason through its steps BEFORE generating code.
+
+- **Forced Connections** — when the user wants cross-domain inspiration ("make it look organic," "industrial aesthetic")
+- **Conceptual Blending** — when the user names two things to combine ("ocean meets music," "space + calligraphy")
+- **Oblique Strategies** — when the user is maximally open ("surprise me," "something I've never seen")
+
+### Forced Connections
+1. Pick a domain unrelated to the visual goal (weather systems, microbiology, architecture, fluid dynamics, textile weaving)
+2. List its core visual/structural elements (erosion → gradual reveal; mitosis → splitting duplication; weaving → interlocking patterns)
+3. Map those elements onto ASCII characters and animation patterns
+4. Synthesize — what does "erosion" or "crystallization" look like in a character grid?
+
+### Conceptual Blending
+1. Name two distinct visual/conceptual spaces (e.g., ocean waves + sheet music)
+2. Map correspondences (crests = high notes, troughs = rests, foam = staccato)
+3. Blend selectively — keep the most interesting mappings, discard forced ones
+4. Develop emergent properties that exist only in the blend
+
+### Oblique Strategies
+1. Draw one: "Honor thy error as a hidden intention" / "Use an old idea" / "What would your closest friend do?" / "Emphasize the flaws" / "Turn it upside down" / "Only a part, not the whole" / "Reverse"
+2. Interpret the directive against the current ASCII animation challenge
+3. Apply the lateral insight to the visual design before writing code
diff --git a/audiocraft/SKILL.md b/audiocraft/SKILL.md
new file mode 100644
index 0000000..824147f
--- /dev/null
+++ b/audiocraft/SKILL.md
@@ -0,0 +1,568 @@
+---
+name: audiocraft-audio-generation
+description: "AudioCraft: MusicGen text-to-music, AudioGen text-to-sound."
+version: 1.0.0
+author: Orchestra Research
+license: MIT
+dependencies: [audiocraft, torch>=2.0.0, transformers>=4.30.0]
+platforms: [linux, macos]
+metadata:
+ hermes:
+ tags: [Multimodal, Audio Generation, Text-to-Music, Text-to-Audio, MusicGen]
+
+---
+
+# AudioCraft: Audio Generation
+
+Comprehensive guide to using Meta's AudioCraft for text-to-music and text-to-audio generation with MusicGen, AudioGen, and EnCodec.
+
+## When to use AudioCraft
+
+**Use AudioCraft when:**
+- Need to generate music from text descriptions
+- Creating sound effects and environmental audio
+- Building music generation applications
+- Need melody-conditioned music generation
+- Want stereo audio output
+- Require controllable music generation with style transfer
+
+**Key features:**
+- **MusicGen**: Text-to-music generation with melody conditioning
+- **AudioGen**: Text-to-sound effects generation
+- **EnCodec**: High-fidelity neural audio codec
+- **Multiple model sizes**: Small (300M) to Large (3.3B)
+- **Stereo support**: Full stereo audio generation
+- **Style conditioning**: MusicGen-Style for reference-based generation
+
+**Use alternatives instead:**
+- **Stable Audio**: For longer commercial music generation
+- **Bark**: For text-to-speech with music/sound effects
+- **Riffusion**: For spectogram-based music generation
+- **OpenAI Jukebox**: For raw audio generation with lyrics
+
+## Quick start
+
+### Installation
+
+```bash
+# From PyPI
+pip install audiocraft
+
+# From GitHub (latest)
+pip install git+https://github.com/facebookresearch/audiocraft.git
+
+# Or use HuggingFace Transformers
+pip install transformers torch torchaudio
+```
+
+### Basic text-to-music (AudioCraft)
+
+```python
+import torchaudio
+from audiocraft.models import MusicGen
+
+# Load model
+model = MusicGen.get_pretrained('facebook/musicgen-small')
+
+# Set generation parameters
+model.set_generation_params(
+ duration=8, # seconds
+ top_k=250,
+ temperature=1.0
+)
+
+# Generate from text
+descriptions = ["happy upbeat electronic dance music with synths"]
+wav = model.generate(descriptions)
+
+# Save audio
+torchaudio.save("output.wav", wav[0].cpu(), sample_rate=32000)
+```
+
+### Using HuggingFace Transformers
+
+```python
+from transformers import AutoProcessor, MusicgenForConditionalGeneration
+import scipy
+
+# Load model and processor
+processor = AutoProcessor.from_pretrained("facebook/musicgen-small")
+model = MusicgenForConditionalGeneration.from_pretrained("facebook/musicgen-small")
+model.to("cuda")
+
+# Generate music
+inputs = processor(
+ text=["80s pop track with bassy drums and synth"],
+ padding=True,
+ return_tensors="pt"
+).to("cuda")
+
+audio_values = model.generate(
+ **inputs,
+ do_sample=True,
+ guidance_scale=3,
+ max_new_tokens=256
+)
+
+# Save
+sampling_rate = model.config.audio_encoder.sampling_rate
+scipy.io.wavfile.write("output.wav", rate=sampling_rate, data=audio_values[0, 0].cpu().numpy())
+```
+
+### Text-to-sound with AudioGen
+
+```python
+from audiocraft.models import AudioGen
+
+# Load AudioGen
+model = AudioGen.get_pretrained('facebook/audiogen-medium')
+
+model.set_generation_params(duration=5)
+
+# Generate sound effects
+descriptions = ["dog barking in a park with birds chirping"]
+wav = model.generate(descriptions)
+
+torchaudio.save("sound.wav", wav[0].cpu(), sample_rate=16000)
+```
+
+## Core concepts
+
+### Architecture overview
+
+```
+AudioCraft Architecture:
+┌──────────────────────────────────────────────────────────────┐
+│ Text Encoder (T5) │
+│ │ │
+│ Text Embeddings │
+└────────────────────────┬─────────────────────────────────────┘
+ │
+┌────────────────────────▼─────────────────────────────────────┐
+│ Transformer Decoder (LM) │
+│ Auto-regressively generates audio tokens │
+│ Using efficient token interleaving patterns │
+└────────────────────────┬─────────────────────────────────────┘
+ │
+┌────────────────────────▼─────────────────────────────────────┐
+│ EnCodec Audio Decoder │
+│ Converts tokens back to audio waveform │
+└──────────────────────────────────────────────────────────────┘
+```
+
+### Model variants
+
+| Model | Size | Description | Use Case |
+|-------|------|-------------|----------|
+| `musicgen-small` | 300M | Text-to-music | Quick generation |
+| `musicgen-medium` | 1.5B | Text-to-music | Balanced |
+| `musicgen-large` | 3.3B | Text-to-music | Best quality |
+| `musicgen-melody` | 1.5B | Text + melody | Melody conditioning |
+| `musicgen-melody-large` | 3.3B | Text + melody | Best melody |
+| `musicgen-stereo-*` | Varies | Stereo output | Stereo generation |
+| `musicgen-style` | 1.5B | Style transfer | Reference-based |
+| `audiogen-medium` | 1.5B | Text-to-sound | Sound effects |
+
+### Generation parameters
+
+| Parameter | Default | Description |
+|-----------|---------|-------------|
+| `duration` | 8.0 | Length in seconds (1-120) |
+| `top_k` | 250 | Top-k sampling |
+| `top_p` | 0.0 | Nucleus sampling (0 = disabled) |
+| `temperature` | 1.0 | Sampling temperature |
+| `cfg_coef` | 3.0 | Classifier-free guidance |
+
+## MusicGen usage
+
+### Text-to-music generation
+
+```python
+from audiocraft.models import MusicGen
+import torchaudio
+
+model = MusicGen.get_pretrained('facebook/musicgen-medium')
+
+# Configure generation
+model.set_generation_params(
+ duration=30, # Up to 30 seconds
+ top_k=250, # Sampling diversity
+ top_p=0.0, # 0 = use top_k only
+ temperature=1.0, # Creativity (higher = more varied)
+ cfg_coef=3.0 # Text adherence (higher = stricter)
+)
+
+# Generate multiple samples
+descriptions = [
+ "epic orchestral soundtrack with strings and brass",
+ "chill lo-fi hip hop beat with jazzy piano",
+ "energetic rock song with electric guitar"
+]
+
+# Generate (returns [batch, channels, samples])
+wav = model.generate(descriptions)
+
+# Save each
+for i, audio in enumerate(wav):
+ torchaudio.save(f"music_{i}.wav", audio.cpu(), sample_rate=32000)
+```
+
+### Melody-conditioned generation
+
+```python
+from audiocraft.models import MusicGen
+import torchaudio
+
+# Load melody model
+model = MusicGen.get_pretrained('facebook/musicgen-melody')
+model.set_generation_params(duration=30)
+
+# Load melody audio
+melody, sr = torchaudio.load("melody.wav")
+
+# Generate with melody conditioning
+descriptions = ["acoustic guitar folk song"]
+wav = model.generate_with_chroma(descriptions, melody, sr)
+
+torchaudio.save("melody_conditioned.wav", wav[0].cpu(), sample_rate=32000)
+```
+
+### Stereo generation
+
+```python
+from audiocraft.models import MusicGen
+
+# Load stereo model
+model = MusicGen.get_pretrained('facebook/musicgen-stereo-medium')
+model.set_generation_params(duration=15)
+
+descriptions = ["ambient electronic music with wide stereo panning"]
+wav = model.generate(descriptions)
+
+# wav shape: [batch, 2, samples] for stereo
+print(f"Stereo shape: {wav.shape}") # [1, 2, 480000]
+torchaudio.save("stereo.wav", wav[0].cpu(), sample_rate=32000)
+```
+
+### Audio continuation
+
+```python
+from transformers import AutoProcessor, MusicgenForConditionalGeneration
+
+processor = AutoProcessor.from_pretrained("facebook/musicgen-medium")
+model = MusicgenForConditionalGeneration.from_pretrained("facebook/musicgen-medium")
+
+# Load audio to continue
+import torchaudio
+audio, sr = torchaudio.load("intro.wav")
+
+# Process with text and audio
+inputs = processor(
+ audio=audio.squeeze().numpy(),
+ sampling_rate=sr,
+ text=["continue with a epic chorus"],
+ padding=True,
+ return_tensors="pt"
+)
+
+# Generate continuation
+audio_values = model.generate(**inputs, do_sample=True, guidance_scale=3, max_new_tokens=512)
+```
+
+## MusicGen-Style usage
+
+### Style-conditioned generation
+
+```python
+from audiocraft.models import MusicGen
+
+# Load style model
+model = MusicGen.get_pretrained('facebook/musicgen-style')
+
+# Configure generation with style
+model.set_generation_params(
+ duration=30,
+ cfg_coef=3.0,
+ cfg_coef_beta=5.0 # Style influence
+)
+
+# Configure style conditioner
+model.set_style_conditioner_params(
+ eval_q=3, # RVQ quantizers (1-6)
+ excerpt_length=3.0 # Style excerpt length
+)
+
+# Load style reference
+style_audio, sr = torchaudio.load("reference_style.wav")
+
+# Generate with text + style
+descriptions = ["upbeat dance track"]
+wav = model.generate_with_style(descriptions, style_audio, sr)
+```
+
+### Style-only generation (no text)
+
+```python
+# Generate matching style without text prompt
+model.set_generation_params(
+ duration=30,
+ cfg_coef=3.0,
+ cfg_coef_beta=None # Disable double CFG for style-only
+)
+
+wav = model.generate_with_style([None], style_audio, sr)
+```
+
+## AudioGen usage
+
+### Sound effect generation
+
+```python
+from audiocraft.models import AudioGen
+import torchaudio
+
+model = AudioGen.get_pretrained('facebook/audiogen-medium')
+model.set_generation_params(duration=10)
+
+# Generate various sounds
+descriptions = [
+ "thunderstorm with heavy rain and lightning",
+ "busy city traffic with car horns",
+ "ocean waves crashing on rocks",
+ "crackling campfire in forest"
+]
+
+wav = model.generate(descriptions)
+
+for i, audio in enumerate(wav):
+ torchaudio.save(f"sound_{i}.wav", audio.cpu(), sample_rate=16000)
+```
+
+## EnCodec usage
+
+### Audio compression
+
+```python
+from audiocraft.models import CompressionModel
+import torch
+import torchaudio
+
+# Load EnCodec
+model = CompressionModel.get_pretrained('facebook/encodec_32khz')
+
+# Load audio
+wav, sr = torchaudio.load("audio.wav")
+
+# Ensure correct sample rate
+if sr != 32000:
+ resampler = torchaudio.transforms.Resample(sr, 32000)
+ wav = resampler(wav)
+
+# Encode to tokens
+with torch.no_grad():
+ encoded = model.encode(wav.unsqueeze(0))
+ codes = encoded[0] # Audio codes
+
+# Decode back to audio
+with torch.no_grad():
+ decoded = model.decode(codes)
+
+torchaudio.save("reconstructed.wav", decoded[0].cpu(), sample_rate=32000)
+```
+
+## Common workflows
+
+### Workflow 1: Music generation pipeline
+
+```python
+import torch
+import torchaudio
+from audiocraft.models import MusicGen
+
+class MusicGenerator:
+ def __init__(self, model_name="facebook/musicgen-medium"):
+ self.model = MusicGen.get_pretrained(model_name)
+ self.sample_rate = 32000
+
+ def generate(self, prompt, duration=30, temperature=1.0, cfg=3.0):
+ self.model.set_generation_params(
+ duration=duration,
+ top_k=250,
+ temperature=temperature,
+ cfg_coef=cfg
+ )
+
+ with torch.no_grad():
+ wav = self.model.generate([prompt])
+
+ return wav[0].cpu()
+
+ def generate_batch(self, prompts, duration=30):
+ self.model.set_generation_params(duration=duration)
+
+ with torch.no_grad():
+ wav = self.model.generate(prompts)
+
+ return wav.cpu()
+
+ def save(self, audio, path):
+ torchaudio.save(path, audio, sample_rate=self.sample_rate)
+
+# Usage
+generator = MusicGenerator()
+audio = generator.generate(
+ "epic cinematic orchestral music",
+ duration=30,
+ temperature=1.0
+)
+generator.save(audio, "epic_music.wav")
+```
+
+### Workflow 2: Sound design batch processing
+
+```python
+import json
+from pathlib import Path
+from audiocraft.models import AudioGen
+import torchaudio
+
+def batch_generate_sounds(sound_specs, output_dir):
+ """
+ Generate multiple sounds from specifications.
+
+ Args:
+ sound_specs: list of {"name": str, "description": str, "duration": float}
+ output_dir: output directory path
+ """
+ model = AudioGen.get_pretrained('facebook/audiogen-medium')
+ output_dir = Path(output_dir)
+ output_dir.mkdir(exist_ok=True)
+
+ results = []
+
+ for spec in sound_specs:
+ model.set_generation_params(duration=spec.get("duration", 5))
+
+ wav = model.generate([spec["description"]])
+
+ output_path = output_dir / f"{spec['name']}.wav"
+ torchaudio.save(str(output_path), wav[0].cpu(), sample_rate=16000)
+
+ results.append({
+ "name": spec["name"],
+ "path": str(output_path),
+ "description": spec["description"]
+ })
+
+ return results
+
+# Usage
+sounds = [
+ {"name": "explosion", "description": "massive explosion with debris", "duration": 3},
+ {"name": "footsteps", "description": "footsteps on wooden floor", "duration": 5},
+ {"name": "door", "description": "wooden door creaking and closing", "duration": 2}
+]
+
+results = batch_generate_sounds(sounds, "sound_effects/")
+```
+
+### Workflow 3: Gradio demo
+
+```python
+import gradio as gr
+import torch
+import torchaudio
+from audiocraft.models import MusicGen
+
+model = MusicGen.get_pretrained('facebook/musicgen-small')
+
+def generate_music(prompt, duration, temperature, cfg_coef):
+ model.set_generation_params(
+ duration=duration,
+ temperature=temperature,
+ cfg_coef=cfg_coef
+ )
+
+ with torch.no_grad():
+ wav = model.generate([prompt])
+
+ # Save to temp file
+ path = "temp_output.wav"
+ torchaudio.save(path, wav[0].cpu(), sample_rate=32000)
+ return path
+
+demo = gr.Interface(
+ fn=generate_music,
+ inputs=[
+ gr.Textbox(label="Music Description", placeholder="upbeat electronic dance music"),
+ gr.Slider(1, 30, value=8, label="Duration (seconds)"),
+ gr.Slider(0.5, 2.0, value=1.0, label="Temperature"),
+ gr.Slider(1.0, 10.0, value=3.0, label="CFG Coefficient")
+ ],
+ outputs=gr.Audio(label="Generated Music"),
+ title="MusicGen Demo"
+)
+
+demo.launch()
+```
+
+## Performance optimization
+
+### Memory optimization
+
+```python
+# Use smaller model
+model = MusicGen.get_pretrained('facebook/musicgen-small')
+
+# Clear cache between generations
+torch.cuda.empty_cache()
+
+# Generate shorter durations
+model.set_generation_params(duration=10) # Instead of 30
+
+# Use half precision
+model = model.half()
+```
+
+### Batch processing efficiency
+
+```python
+# Process multiple prompts at once (more efficient)
+descriptions = ["prompt1", "prompt2", "prompt3", "prompt4"]
+wav = model.generate(descriptions) # Single batch
+
+# Instead of
+for desc in descriptions:
+ wav = model.generate([desc]) # Multiple batches (slower)
+```
+
+### GPU memory requirements
+
+| Model | FP32 VRAM | FP16 VRAM |
+|-------|-----------|-----------|
+| musicgen-small | ~4GB | ~2GB |
+| musicgen-medium | ~8GB | ~4GB |
+| musicgen-large | ~16GB | ~8GB |
+
+## Common issues
+
+| Issue | Solution |
+|-------|----------|
+| CUDA OOM | Use smaller model, reduce duration |
+| Poor quality | Increase cfg_coef, better prompts |
+| Generation too short | Check max duration setting |
+| Audio artifacts | Try different temperature |
+| Stereo not working | Use stereo model variant |
+
+## References
+
+- **[Advanced Usage](references/advanced-usage.md)** - Training, fine-tuning, deployment
+- **[Troubleshooting](references/troubleshooting.md)** - Common issues and solutions
+
+## Resources
+
+- **GitHub**: https://github.com/facebookresearch/audiocraft
+- **Paper (MusicGen)**: https://arxiv.org/abs/2306.05284
+- **Paper (AudioGen)**: https://arxiv.org/abs/2209.15352
+- **HuggingFace**: https://huggingface.co/facebook/musicgen-small
+- **Demo**: https://huggingface.co/spaces/facebook/MusicGen
diff --git a/baoyu-article-illustrator/SKILL.md b/baoyu-article-illustrator/SKILL.md
new file mode 100644
index 0000000..6adbebf
--- /dev/null
+++ b/baoyu-article-illustrator/SKILL.md
@@ -0,0 +1,207 @@
+---
+name: baoyu-article-illustrator
+description: "Article illustrations: type × style × palette consistency."
+version: 1.57.0
+author: 宝玉 (JimLiu)
+license: MIT
+platforms: [linux, macos, windows]
+metadata:
+ hermes:
+ tags: [article-illustration, creative, image-generation]
+ category: creative
+ homepage: https://github.com/JimLiu/baoyu-skills#baoyu-article-illustrator
+---
+
+# Article Illustrator
+
+Adapted from [baoyu-article-illustrator](https://github.com/JimLiu/baoyu-skills) for Hermes Agent's tool ecosystem.
+
+Analyze articles, identify illustration positions, generate images with **Type × Style × Palette** consistency.
+
+## When to Use
+
+Trigger this skill when the user asks to illustrate an article, add images to an article, generate illustrations for content, or uses phrases like "为文章配图", "illustrate article", or "add images". The user provides an article (file path or pasted content) and optionally specifies type, style, palette, or density.
+
+## Three Dimensions
+
+| Dimension | Controls | Examples |
+|-----------|----------|----------|
+| **Type** | Information structure | infographic, scene, flowchart, comparison, framework, timeline |
+| **Style** | Rendering approach | notion, warm, minimal, blueprint, watercolor, elegant |
+| **Palette** | Color scheme (optional) | macaron, warm, neon — overrides style's default colors |
+
+Combine freely: `type=infographic, style=vector-illustration, palette=macaron`.
+
+Or use presets: `edu-visual` → type + style + palette in one shot. See [style-presets.md](references/style-presets.md).
+
+## Types
+
+| Type | Best For |
+|------|----------|
+| `infographic` | Data, metrics, technical |
+| `scene` | Narratives, emotional |
+| `flowchart` | Processes, workflows |
+| `comparison` | Side-by-side, options |
+| `framework` | Models, architecture |
+| `timeline` | History, evolution |
+
+## Styles
+
+See [references/styles.md](references/styles.md) for Core Styles, the full gallery, and Type × Style compatibility.
+
+## Output Structure
+
+```
+{output-dir}/
+├── source-{slug}.{ext} # Only for pasted content
+├── outline.md
+├── prompts/
+│ └── NN-{type}-{slug}.md
+└── NN-{type}-{slug}.png
+```
+
+**Default output directory**:
+
+| Input | Output Directory | Markdown Insert Path |
+|-------|------------------|----------------------|
+| Article file path | `{article-dir}/imgs/` | `imgs/NN-{type}-{slug}.png` |
+| Pasted content | `illustrations/{topic-slug}/` (cwd) | `illustrations/{topic-slug}/NN-{type}-{slug}.png` |
+
+If the user asks for a different layout (e.g., images alongside the article, or a `illustrations/` subdirectory), honor that.
+
+**Slug**: 2-4 words, kebab-case. **Conflict**: append `-YYYYMMDD-HHMMSS`.
+
+## Core Principles
+
+- **Visualize concepts, not metaphors** — if the article uses a metaphor (e.g., "电锯切西瓜"), illustrate the underlying concept, not the literal image.
+- **Labels use article data** — actual numbers, terms, and quotes from the article, not generic placeholders.
+- **Prompt files are reproducibility records** — every illustration must have a saved prompt file under `prompts/` before any image is generated.
+- **Strip secrets** — scan source content for API keys, tokens, or credentials before writing anything to disk.
+
+## Workflow
+
+```
+- [ ] Step 1: Detect reference images (if provided)
+- [ ] Step 2: Analyze content
+- [ ] Step 3: Confirm settings (clarify tool, one question at a time)
+- [ ] Step 4: Generate outline
+- [ ] Step 5: Generate prompts
+- [ ] Step 6: Generate images (image_generate)
+- [ ] Step 7: Finalize
+```
+
+### Step 1: Detect Reference Images
+
+If the user supplies reference images (paths pasted inline, attachments, or a URL):
+
+1. For each reference, call `vision_analyze` with the path/URL and a question asking for style, palette, composition, and subject. Record the returned description in `{output-dir}/references/NN-ref-{slug}.md` via `write_file`.
+2. **Do not** try to copy the binary via `write_file` / `read_file` — those are text-only. If you want a local copy for the record, use `terminal` (`cp "$src" "{output-dir}/references/NN-ref-{slug}.{ext}"`). The skill itself never needs to read the binary; it works off the vision description.
+3. Since `image_generate` doesn't take image inputs, the vision description is what gets embedded in prompts during Step 5.
+
+Full procedures: [references/workflow.md](references/workflow.md#step-1-detect-reference-images).
+
+### Step 2: Analyze
+
+| Analysis | Output |
+|----------|--------|
+| Content type | Technical / Tutorial / Methodology / Narrative |
+| Purpose | information / visualization / imagination |
+| Core arguments | 2-5 main points |
+| Positions | Where illustrations add value |
+
+Read source (file path → `read_file`, or pasted text) and write the analysis to `{output-dir}/analysis.md` using `write_file`.
+
+Full procedures: [references/workflow.md](references/workflow.md#step-2-analyze).
+
+### Step 3: Confirm Settings
+
+Use the `clarify` tool. Since `clarify` handles one question at a time, ask the most important question first. Skip any question whose answer is already present in the user's request.
+
+| Order | Question | Options |
+|-------|----------|---------|
+| Q1 | **Preset or Type** | [Recommended preset], [alt preset], or manual: infographic, scene, flowchart, comparison, framework, timeline, mixed |
+| Q2 | **Density** | minimal (1-2), balanced (3-5), per-section (Recommended), rich (6+) |
+| Q3 | **Style** *(skip if preset chosen in Q1)* | [Recommended], minimal-flat, sci-fi, hand-drawn, editorial, scene, poster |
+| Q4 | **Palette** *(optional)* | Default (style colors), macaron, warm, neon |
+| Q5 | **Language** *(only if article language is ambiguous)* | article language / user language |
+
+Don't ask more than 2-3 `clarify` questions in a row. If the user already specified these in their request, skip entirely.
+
+Full procedures: [references/workflow.md](references/workflow.md#step-3-confirm-settings).
+
+### Step 4: Generate Outline → `outline.md`
+
+Save `{output-dir}/outline.md` using `write_file` with frontmatter (type, density, style, palette, image_count) and one entry per illustration:
+
+```yaml
+## Illustration 1
+**Position**: [section/paragraph]
+**Purpose**: [why]
+**Visual Content**: [what to show]
+**Filename**: 01-infographic-concept-name.png
+```
+
+Full template: [references/workflow.md](references/workflow.md#step-4-generate-outline).
+
+### Step 5: Generate Prompts
+
+**BLOCKING**: Every illustration must have a saved prompt file before any image is generated — the prompt file is the reproducibility record.
+
+For each illustration:
+
+1. Create a prompt file per [references/prompt-construction.md](references/prompt-construction.md).
+2. Save to `{output-dir}/prompts/NN-{type}-{slug}.md` using `write_file` with YAML frontmatter.
+3. Prompts MUST use type-specific templates with structured sections (ZONES / LABELS / COLORS / STYLE / ASPECT).
+4. LABELS MUST include article-specific data: actual numbers, terms, metrics, quotes.
+5. Process references (`direct`/`style`/`palette`) per prompt frontmatter — for `direct` usage, embed a textual description of the reference in the prompt (since `image_generate` doesn't take reference-image inputs).
+
+### Step 6: Generate Images
+
+For each prompt file:
+
+1. Call `image_generate(prompt=..., aspect_ratio=...)`. `image_generate` returns a JSON result containing an image URL; it does NOT write to disk and does NOT accept an output path.
+2. Map the prompt's `ASPECT` to `image_generate`'s enum: `16:9` → `landscape`, `9:16` → `portrait`, `1:1` → `square`. Custom ratios → nearest named aspect.
+3. Download the returned URL to `{output-dir}/NN-{type}-{slug}.png` via `terminal` (e.g. `curl -sSL -o "{output-dir}/NN-{type}-{slug}.png" "{url}"`).
+4. On generation failure, auto-retry once.
+
+Note: the underlying image-generation backend is user-configured (default: FAL FLUX 2 Klein 9B) and is NOT agent-selectable via `image_generate`. Do not write model names into prompts expecting them to route.
+
+### Step 7: Finalize
+
+Insert `` after the corresponding paragraph. Alt text: concise description in the article's language.
+
+Report:
+
+```
+Article Illustration Complete!
+Article: [path] | Type: [type] | Density: [level] | Style: [style] | Palette: [palette or default]
+Images: X/N generated
+```
+
+## Modification
+
+| Action | Steps |
+|--------|-------|
+| Edit | Update prompt → Regenerate → Update reference |
+| Add | Position → Prompt → Generate → Update outline → Insert |
+| Delete | Delete files → Remove reference → Update outline |
+
+## References
+
+| File | Content |
+|------|---------|
+| [references/workflow.md](references/workflow.md) | Detailed procedures |
+| [references/usage.md](references/usage.md) | Invocation examples |
+| [references/styles.md](references/styles.md) | Style gallery + Palette gallery |
+| [references/style-presets.md](references/style-presets.md) | Preset shortcuts (type + style + palette) |
+| [references/prompt-construction.md](references/prompt-construction.md) | Prompt templates |
+
+## Pitfalls
+
+1. **Data integrity is paramount** — never summarize, paraphrase, or alter source statistics. "73% increase" stays "73% increase".
+2. **Strip secrets** — scan source content for API keys, tokens, or credentials before including in any output file.
+3. **Don't illustrate metaphors literally** — visualize the underlying concept.
+4. **Prompt files are mandatory** — no image generation without a saved prompt file. The file is what lets you regenerate or switch backends later.
+5. **`image_generate` aspect ratios** — the tool supports `landscape`, `portrait`, and `square`. Custom ratios map to the nearest option.
+6. **`image_generate` returns a URL, not a local file** — always download via `terminal` (`curl`) before inserting local image paths into the article.
+7. **No backend selection from the agent** — `image_generate` uses whatever model the user configured (default: FAL FLUX 2 Klein 9B). Don't write `"use to generate this"` into prompts expecting it to route.
diff --git a/baoyu-comic/SKILL.md b/baoyu-comic/SKILL.md
new file mode 100644
index 0000000..6745b55
--- /dev/null
+++ b/baoyu-comic/SKILL.md
@@ -0,0 +1,247 @@
+---
+name: baoyu-comic
+description: "Knowledge comics (知识漫画): educational, biography, tutorial."
+version: 1.56.1
+author: 宝玉 (JimLiu)
+license: MIT
+platforms: [linux, macos, windows]
+metadata:
+ hermes:
+ tags: [comic, knowledge-comic, creative, image-generation]
+ homepage: https://github.com/JimLiu/baoyu-skills#baoyu-comic
+---
+
+# Knowledge Comic Creator
+
+Adapted from [baoyu-comic](https://github.com/JimLiu/baoyu-skills) for Hermes Agent's tool ecosystem.
+
+Create original knowledge comics with flexible art style × tone combinations.
+
+## When to Use
+
+Trigger this skill when the user asks to create a knowledge/educational comic, biography comic, tutorial comic, or uses terms like "知识漫画", "教育漫画", or "Logicomix-style". The user provides content (text, file path, URL, or topic) and optionally specifies art style, tone, layout, aspect ratio, or language.
+
+## Reference Images
+
+Hermes' `image_generate` tool is **prompt-only** — it accepts a text prompt and an aspect ratio, and returns an image URL. It does **NOT** accept reference images. When the user supplies a reference image, use it to **extract traits in text** that get embedded in every page prompt:
+
+**Intake**: Accept file paths when the user provides them (or pastes images in conversation).
+- File path(s) → copy to `refs/NN-ref-{slug}.{ext}` alongside the comic output for provenance
+- Pasted image with no path → ask the user for the path via `clarify`, or extract style traits verbally as a text fallback
+- No reference → skip this section
+
+**Usage modes** (per reference):
+
+| Usage | Effect |
+|-------|--------|
+| `style` | Extract style traits (line treatment, texture, mood) and append to every page's prompt body |
+| `palette` | Extract hex colors and append to every page's prompt body |
+| `scene` | Extract scene composition or subject notes and append to the relevant page(s) |
+
+**Record in each page's prompt frontmatter** when refs exist:
+
+```yaml
+references:
+ - ref_id: 01
+ filename: 01-ref-scene.png
+ usage: style
+ traits: "muted earth tones, soft-edged ink wash, low-contrast backgrounds"
+```
+
+Character consistency is driven by **text descriptions** in `characters/characters.md` (written in Step 3) that get embedded inline in every page prompt (Step 5). The optional PNG character sheet generated in Step 7.1 is a human-facing review artifact, not an input to `image_generate`.
+
+## Options
+
+### Visual Dimensions
+
+| Option | Values | Description |
+|--------|--------|-------------|
+| Art | ligne-claire (default), manga, realistic, ink-brush, chalk, minimalist | Art style / rendering technique |
+| Tone | neutral (default), warm, dramatic, romantic, energetic, vintage, action | Mood / atmosphere |
+| Layout | standard (default), cinematic, dense, splash, mixed, webtoon, four-panel | Panel arrangement |
+| Aspect | 3:4 (default, portrait), 4:3 (landscape), 16:9 (widescreen) | Page aspect ratio |
+| Language | auto (default), zh, en, ja, etc. | Output language |
+| Refs | File paths | Reference images used for style / palette trait extraction (not passed to the image model). See [Reference Images](#reference-images) above. |
+
+### Partial Workflow Options
+
+| Option | Description |
+|--------|-------------|
+| Storyboard only | Generate storyboard only, skip prompts and images |
+| Prompts only | Generate storyboard + prompts, skip images |
+| Images only | Generate images from existing prompts directory |
+| Regenerate N | Regenerate specific page(s) only (e.g., `3` or `2,5,8`) |
+
+Details: [references/partial-workflows.md](references/partial-workflows.md)
+
+### Art, Tone & Preset Catalogue
+
+- **Art styles** (6): `ligne-claire`, `manga`, `realistic`, `ink-brush`, `chalk`, `minimalist`. Full definitions at `references/art-styles/
+
+
+
+
+