{"owner":"eigent-ai","repo":"eigent","hasSkills":true,"totalSkillsCount":10,"totalTokensCount":21088,"categories":["anthropic-skill"],"hasMcp":false,"mcpConfig":null,"found":["resources/example-skills/pptx/SKILL.md","resources/example-skills/skill-creator/references/output-patterns.md","resources/example-skills/skill-security-auditor/SKILL.md","resources/example-skills/pdf/SKILL.md","resources/example-skills/xlsx/SKILL.md","resources/example-skills/docx/SKILL.md","resources/example-skills/skill-creator/SKILL.md","resources/example-skills/skill-creator/references/workflows.md","resources/example-skills/skill-security-auditor/references/secrets-patterns.md","resources/example-skills/skill-security-auditor/references/vulnerability-patterns.md"],"skills":{"resources/example-skills/pptx/SKILL.md":"---\nname: pptx\ndescription: \"Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates, layouts, speaker notes, or comments. Trigger whenever the user mentions \\\"deck,\\\" \\\"slides,\\\" \\\"presentation,\\\" or references a .pptx filename, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# PPTX Skill\n\n## Quick Reference\n\n| Task | Guide |\n|------|-------|\n| Read/analyze content | `python -m markitdown presentation.pptx` |\n| Edit or create from template | Read [editing.md](editing.md) |\n| Create from scratch | Read [pptxgenjs.md](pptxgenjs.md) |\n\n---\n\n## Reading Content\n\n```bash\n# Text extraction\npython -m markitdown presentation.pptx\n\n# Visual overview\npython scripts/thumbnail.py presentation.pptx\n\n# Raw XML\npython scripts/office/unpack.py presentation.pptx unpacked/\n```\n\n---\n\n## Editing Workflow\n\n**Read [editing.md](editing.md) for full details.**\n\n1. Analyze template with `thumbnail.py`\n2. Unpack → manipulate slides → edit content → clean → pack\n\n---\n\n## Creating from Scratch\n\n**Read [pptxgenjs.md](pptxgenjs.md) for full details.**\n\nUse when no template or reference presentation is available.\n\n---\n\n## Design Ideas\n\n**Don't create boring slides.** Plain bullets on a white background won't impress anyone. Consider ideas from this list for each slide.\n\n### Before Starting\n\n- **Pick a bold, content-informed color palette**: The palette should feel designed for THIS topic. If swapping your colors into a completely different presentation would still \"work,\" you haven't made specific enough choices.\n- **Dominance over equality**: One color should dominate (60-70% visual weight), with 1-2 supporting tones and one sharp accent. Never give all colors equal weight.\n- **Dark/light contrast**: Dark backgrounds for title + conclusion slides, light for content (\"sandwich\" structure). Or commit to dark throughout for a premium feel.\n- **Commit to a visual motif**: Pick ONE distinctive element and repeat it — rounded image frames, icons in colored circles, thick single-side borders. Carry it across every slide.\n\n### Color Palettes\n\nChoose colors that match your topic — don't default to generic blue. Use these palettes as inspiration:\n\n| Theme | Primary | Secondary | Accent |\n|-------|---------|-----------|--------|\n| **Midnight Executive** | `1E2761` (navy) | `CADCFC` (ice blue) | `FFFFFF` (white) |\n| **Forest & Moss** | `2C5F2D` (forest) | `97BC62` (moss) | `F5F5F5` (cream) |\n| **Coral Energy** | `F96167` (coral) | `F9E795` (gold) | `2F3C7E` (navy) |\n| **Warm Terracotta** | `B85042` (terracotta) | `E7E8D1` (sand) | `A7BEAE` (sage) |\n| **Ocean Gradient** | `065A82` (deep blue) | `1C7293` (teal) | `21295C` (midnight) |\n| **Charcoal Minimal** | `36454F` (charcoal) | `F2F2F2` (off-white) | `212121` (black) |\n| **Teal Trust** | `028090` (teal) | `00A896` (seafoam) | `02C39A` (mint) |\n| **Berry & Cream** | `6D2E46` (berry) | `A26769` (dusty rose) | `ECE2D0` (cream) |\n| **Sage Calm** | `84B59F` (sage) | `69A297` (eucalyptus) | `50808E` (slate) |\n| **Cherry Bold** | `990011` (cherry) | `FCF6F5` (off-white) | `2F3C7E` (navy) |\n\n### For Each Slide\n\n**Every slide needs a visual element** — image, chart, icon, or shape. Text-only slides are forgettable.\n\n**Layout options:**\n- Two-column (text left, illustration on right)\n- Icon + text rows (icon in colored circle, bold header, description below)\n- 2x2 or 2x3 grid (image on one side, grid of content blocks on other)\n- Half-bleed image (full left or right side) with content overlay\n\n**Data display:**\n- Large stat callouts (big numbers 60-72pt with small labels below)\n- Comparison columns (before/after, pros/cons, side-by-side options)\n- Timeline or process flow (numbered steps, arrows)\n\n**Visual polish:**\n- Icons in small colored circles next to section headers\n- Italic accent text for key stats or taglines\n\n### Typography\n\n**Choose an interesting font pairing** — don't default to Arial. Pick a header font with personality and pair it with a clean body font.\n\n| Header Font | Body Font |\n|-------------|-----------|\n| Georgia | Calibri |\n| Arial Black | Arial |\n| Calibri | Calibri Light |\n| Cambria | Calibri |\n| Trebuchet MS | Calibri |\n| Impact | Arial |\n| Palatino | Garamond |\n| Consolas | Calibri |\n\n| Element | Size |\n|---------|------|\n| Slide title | 36-44pt bold |\n| Section header | 20-24pt bold |\n| Body text | 14-16pt |\n| Captions | 10-12pt muted |\n\n### Spacing\n\n- 0.5\" minimum margins\n- 0.3-0.5\" between content blocks\n- Leave breathing room—don't fill every inch\n\n### Avoid (Common Mistakes)\n\n- **Don't repeat the same layout** — vary columns, cards, and callouts across slides\n- **Don't center body text** — left-align paragraphs and lists; center only titles\n- **Don't skimp on size contrast** — titles need 36pt+ to stand out from 14-16pt body\n- **Don't default to blue** — pick colors that reflect the specific topic\n- **Don't mix spacing randomly** — choose 0.3\" or 0.5\" gaps and use consistently\n- **Don't style one slide and leave the rest plain** — commit fully or keep it simple throughout\n- **Don't create text-only slides** — add images, icons, charts, or visual elements; avoid plain title + bullets\n- **Don't forget text box padding** — when aligning lines or shapes with text edges, set `margin: 0` on the text box or offset the shape to account for padding\n- **Don't use low-contrast elements** — icons AND text need strong contrast against the background; avoid light text on light backgrounds or dark text on dark backgrounds\n- **NEVER use accent lines under titles** — these are a hallmark of AI-generated slides; use whitespace or background color instead\n\n---\n\n## QA (Required)\n\n**Assume there are problems. Your job is to find them.**\n\nYour first render is almost never correct. Approach QA as a bug hunt, not a confirmation step. If you found zero issues on first inspection, you weren't looking hard enough.\n\n### Content QA\n\n```bash\npython -m markitdown output.pptx\n```\n\nCheck for missing content, typos, wrong order.\n\n**When using templates, check for leftover placeholder text:**\n\n```bash\npython -m markitdown output.pptx | grep -iE \"xxxx|lorem|ipsum|this.*(page|slide).*layout\"\n```\n\nIf grep returns results, fix them before declaring success.\n\n### Visual QA\n\n### Verification Loop\n\n1. Generate slides → Convert to images → Inspect\n2. **List issues found** (if none found, look again more critically)\n3. Fix issues\n4. **Re-verify affected slides** — one fix often creates another problem\n5. Repeat until a full pass reveals no new issues\n\n**Do not declare success until you've completed at least one fix-and-verify cycle.**\n\n---\n\n## Converting to Images\n\nConvert presentations to individual slide images for visual inspection:\n\n```bash\npython scripts/office/soffice.py --headless --convert-to pdf output.pptx\npdftoppm -jpeg -r 150 output.pdf slide\n```\n\nThis creates `slide-01.jpg`, `slide-02.jpg`, etc.\n\nTo re-render specific slides after fixes:\n\n```bash\npdftoppm -jpeg -r 150 -f N -l N output.pdf slide-fixed\n```\n\n---\n\n## Dependencies\n\n- `pip install \"markitdown[pptx]\"` - text extraction\n- `pip install Pillow` - thumbnail grids\n- `npm install -g pptxgenjs` - creating from scratch\n- LibreOffice (`soffice`) - PDF conversion (auto-configured for sandboxed environments via `scripts/office/soffice.py`)\n- Poppler (`pdftoppm`) - PDF to images\n","resources/example-skills/skill-creator/references/output-patterns.md":"# Output Patterns\n\nUse these patterns when skills need to produce consistent, high-quality output.\n\n## Template Pattern\n\nProvide templates for output format. Match the level of strictness to your needs.\n\n**For strict requirements (like API responses or data formats):**\n\n```markdown\n## Report structure\n\nALWAYS use this exact template structure:\n\n# [Analysis Title]\n\n## Executive summary\n[One-paragraph overview of key findings]\n\n## Key findings\n- Finding 1 with supporting data\n- Finding 2 with supporting data\n- Finding 3 with supporting data\n\n## Recommendations\n1. Specific actionable recommendation\n2. Specific actionable recommendation\n```\n\n**For flexible guidance (when adaptation is useful):**\n\n```markdown\n## Report structure\n\nHere is a sensible default format, but use your best judgment:\n\n# [Analysis Title]\n\n## Executive summary\n[Overview]\n\n## Key findings\n[Adapt sections based on what you discover]\n\n## Recommendations\n[Tailor to the specific context]\n\nAdjust sections as needed for the specific analysis type.\n```\n\n## Examples Pattern\n\nFor skills where output quality depends on seeing examples, provide input/output pairs:\n\n```markdown\n## Commit message format\n\nGenerate commit messages following these examples:\n\n**Example 1:**\nInput: Added user authentication with JWT tokens\nOutput:\n```\nfeat(auth): implement JWT-based authentication\n\nAdd login endpoint and token validation middleware\n```\n\n**Example 2:**\nInput: Fixed bug where dates displayed incorrectly in reports\nOutput:\n```\nfix(reports): correct date formatting in timezone conversion\n\nUse UTC timestamps consistently across report generation\n```\n\nFollow this style: type(scope): brief description, then detailed explanation.\n```\n\nExamples help the agent understand the desired style and level of detail more clearly than descriptions alone.\n","resources/example-skills/skill-security-auditor/SKILL.md":"---\nname: skill-security-auditor\ndescription: \"Security auditing for code, configs, and infrastructure. Use when the user wants to audit or improve security: scan for vulnerabilities (SQL injection, XSS, command injection, path traversal), detect hardcoded secrets and credentials, review auth and authorization, check dependencies for known CVEs, audit config files for insecure defaults, or generate security reports. Trigger on \\\"security audit\\\", \\\"vulnerability scan\\\", \\\"code review for security\\\", \\\"find secrets\\\", \\\"check for vulnerabilities\\\", \\\"OWASP\\\", \\\"CVE\\\", or questions about code security.\"\nlicense: Complete terms in LICENSE.txt\n---\n\n# Security Auditor Guide\n\n## Overview\n\nThis guide covers security auditing workflows for source code, dependencies, and configurations. For detailed vulnerability patterns and detection rules, see references/vulnerability-patterns.md. For secrets detection patterns, see references/secrets-patterns.md.\n\n## Quick Start\n\nRun the bundled scan script against a project directory:\n\n```bash\npython scripts/scan_project.py /path/to/project\n```\n\nThis performs a lightweight scan for common issues: hardcoded secrets, dangerous function calls, and insecure patterns. For deeper analysis, follow the workflows below.\n\n### Testing the scripts\n\n```bash\npython scripts/scan_project.py /path/to/some/project --format text\npython scripts/scan_secrets.py /path/to/some/project --format text\n```\n\n## Audit Workflow\n\n### 1. Reconnaissance\n\nBefore auditing, understand the project:\n\n```bash\n# Identify languages, frameworks, and entry points\nfind . -type f -name \"*.py\" -o -name \"*.js\" -o -name \"*.ts\" -o -name \"*.go\" -o -name \"*.java\" | head -20\ncat package.json pyproject.toml requirements.txt go.mod pom.xml 2>/dev/null\n```\n\nKey questions:\n- What frameworks are used? (Express, Django, Flask, Spring, etc.)\n- Where are the entry points? (routes, controllers, API handlers)\n- How is authentication handled?\n- What external services are called?\n- Is user input accepted? Where?\n\n### 2. Secrets Detection\n\nScan for hardcoded credentials, API keys, and tokens. See references/secrets-patterns.md for the full pattern list.\n\n```bash\npython scripts/scan_secrets.py /path/to/project\n```\n\nCommon patterns to check:\n- API keys and tokens in source files\n- Database connection strings with embedded passwords\n- Private keys or certificates committed to the repo\n- `.env` files or config files with plaintext secrets\n- Secrets in CI/CD configuration files\n\n### 3. Vulnerability Scanning\n\n#### OWASP Top 10 Checklist\n\n| # | Category | What to Look For |\n|---|----------|-----------------|\n| A01 | Broken Access Control | Missing auth checks, IDOR, privilege escalation |\n| A02 | Cryptographic Failures | Weak algorithms, plaintext storage, missing TLS |\n| A03 | Injection | SQL, NoSQL, OS command, LDAP, XSS |\n| A04 | Insecure Design | Missing rate limits, business logic flaws |\n| A05 | Security Misconfiguration | Debug mode, default credentials, verbose errors |\n| A06 | Vulnerable Components | Outdated dependencies with known CVEs |\n| A07 | Auth Failures | Weak passwords, missing MFA, session issues |\n| A08 | Data Integrity Failures | Insecure deserialization, unsigned updates |\n| A09 | Logging Failures | Missing audit logs, sensitive data in logs |\n| A10 | SSRF | Unvalidated URLs in server-side requests |\n\n#### Language-Specific Checks\n\n**Python**\n```python\n# Dangerous: SQL injection\ncursor.execute(f\"SELECT * FROM users WHERE id = {user_id}\")\n# Safe: Parameterized query\ncursor.execute(\"SELECT * FROM users WHERE id = %s\", (user_id,))\n\n# Dangerous: Command injection\nos.system(f\"ping {hostname}\")\n# Safe: Use subprocess with list args\nsubprocess.run([\"ping\", hostname], capture_output=True)\n\n# Dangerous: Path traversal\nopen(f\"/data/{user_input}\")\n# Safe: Validate and resolve path\npath = pathlib.Path(\"/data\") / user_input\npath.resolve().relative_to(pathlib.Path(\"/data\").resolve())\n```\n\n**JavaScript/TypeScript**\n```javascript\n// Dangerous: XSS via innerHTML\nelement.innerHTML = userInput;\n// Safe: Use textContent or sanitize\nelement.textContent = userInput;\n\n// Dangerous: Prototype pollution\nObject.assign(target, JSON.parse(userInput));\n// Safe: Validate input structure\nconst parsed = JSON.parse(userInput);\nif (typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error();\nconst sanitized = Object.fromEntries(\n  Object.entries(parsed).filter(([k]) => !k.startsWith('__'))\n);\n\n// Dangerous: eval or Function constructor\neval(userInput);\n// Safe: Never use eval with user input\n```\n\n**Go**\n```go\n// Dangerous: SQL injection\ndb.Query(\"SELECT * FROM users WHERE id = \" + id)\n// Safe: Parameterized query\ndb.Query(\"SELECT * FROM users WHERE id = $1\", id)\n\n// Dangerous: Path traversal\nhttp.ServeFile(w, r, filepath.Join(baseDir, r.URL.Path))\n// Safe: Clean and validate path\ncleaned := filepath.Clean(r.URL.Path)\nfull := filepath.Join(baseDir, cleaned)\nif !strings.HasPrefix(full, baseDir) { http.Error(...) }\n```\n\n### 4. Dependency Audit\n\nCheck for known vulnerabilities in project dependencies:\n\n```bash\n# Python\npip audit\nsafety check -r requirements.txt\n\n# Node.js\nnpm audit\nnpx auditjs ossi\n\n# Go\ngovulncheck ./...\n\n# General (if Trivy is available)\ntrivy fs --scanners vuln /path/to/project\n```\n\nReview the output and categorize by severity (critical, high, medium, low). Critical and high severity findings should be addressed before deployment.\n\n### 5. Configuration Review\n\nCheck for insecure defaults in configuration files:\n\n```yaml\n# Common misconfigurations to flag:\nDEBUG: true                    # Debug mode in production\nALLOWED_HOSTS: [\"*\"]          # Unrestricted host access\nCORS_ALLOW_ALL_ORIGINS: true  # Open CORS policy\nSECRET_KEY: \"default\"         # Default or weak secret key\nSSL_VERIFY: false             # Disabled TLS verification\n```\n\nCheck infrastructure configs:\n- Dockerfiles: Running as root, exposing unnecessary ports\n- CI/CD: Secrets in plaintext, overly permissive permissions\n- Cloud configs: Public S3 buckets, open security groups\n\n### 6. Authentication and Authorization Review\n\nKey areas to verify:\n- Password hashing uses strong algorithms (bcrypt, argon2, scrypt)\n- Sessions have appropriate timeouts and rotation\n- JWT tokens are validated properly (algorithm, expiry, signature)\n- API endpoints enforce authorization checks\n- Role-based access control is consistently applied\n- Rate limiting is in place for login and sensitive endpoints\n\n## Report Format\n\nWhen generating a security audit report, use this structure:\n\n```markdown\n# Security Audit Report\n\n## Summary\n- **Project**: [name]\n- **Date**: [date]\n- **Scope**: [what was audited]\n- **Risk Level**: [Critical/High/Medium/Low]\n\n## Findings\n\n### [SEVERITY] Finding Title\n- **Category**: [OWASP category]\n- **Location**: [file:line]\n- **Description**: [what the issue is]\n- **Impact**: [what could happen if exploited]\n- **Recommendation**: [how to fix]\n\n## Statistics\n- Total findings: [count]\n- Critical: [count] | High: [count] | Medium: [count] | Low: [count]\n```\n\n## Next Steps\n\n- For detailed vulnerability patterns and code examples, see references/vulnerability-patterns.md\n- For secrets detection regex patterns, see references/secrets-patterns.md\n","resources/example-skills/pdf/SKILL.md":"---\nname: pdf\ndescription: Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill.\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# PDF Processing Guide\n\n## Overview\n\nThis guide covers essential PDF processing operations using Python libraries and command-line tools. For advanced features, JavaScript libraries, and detailed examples, see REFERENCE.md. If you need to fill out a PDF form, read FORMS.md and follow its instructions.\n\n## Quick Start\n\n```python\nfrom pypdf import PdfReader, PdfWriter\n\n# Read a PDF\nreader = PdfReader(\"document.pdf\")\nprint(f\"Pages: {len(reader.pages)}\")\n\n# Extract text\ntext = \"\"\nfor page in reader.pages:\n    text += page.extract_text()\n```\n\n## Python Libraries\n\n### pypdf - Basic Operations\n\n#### Merge PDFs\n```python\nfrom pypdf import PdfWriter, PdfReader\n\nwriter = PdfWriter()\nfor pdf_file in [\"doc1.pdf\", \"doc2.pdf\", \"doc3.pdf\"]:\n    reader = PdfReader(pdf_file)\n    for page in reader.pages:\n        writer.add_page(page)\n\nwith open(\"merged.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n#### Split PDF\n```python\nreader = PdfReader(\"input.pdf\")\nfor i, page in enumerate(reader.pages):\n    writer = PdfWriter()\n    writer.add_page(page)\n    with open(f\"page_{i+1}.pdf\", \"wb\") as output:\n        writer.write(output)\n```\n\n#### Extract Metadata\n```python\nreader = PdfReader(\"document.pdf\")\nmeta = reader.metadata\nprint(f\"Title: {meta.title}\")\nprint(f\"Author: {meta.author}\")\nprint(f\"Subject: {meta.subject}\")\nprint(f\"Creator: {meta.creator}\")\n```\n\n#### Rotate Pages\n```python\nreader = PdfReader(\"input.pdf\")\nwriter = PdfWriter()\n\npage = reader.pages[0]\npage.rotate(90)  # Rotate 90 degrees clockwise\nwriter.add_page(page)\n\nwith open(\"rotated.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n### pdfplumber - Text and Table Extraction\n\n#### Extract Text with Layout\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    for page in pdf.pages:\n        text = page.extract_text()\n        print(text)\n```\n\n#### Extract Tables\n```python\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    for i, page in enumerate(pdf.pages):\n        tables = page.extract_tables()\n        for j, table in enumerate(tables):\n            print(f\"Table {j+1} on page {i+1}:\")\n            for row in table:\n                print(row)\n```\n\n#### Advanced Table Extraction\n```python\nimport pandas as pd\n\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    all_tables = []\n    for page in pdf.pages:\n        tables = page.extract_tables()\n        for table in tables:\n            if table:  # Check if table is not empty\n                df = pd.DataFrame(table[1:], columns=table[0])\n                all_tables.append(df)\n\n# Combine all tables\nif all_tables:\n    combined_df = pd.concat(all_tables, ignore_index=True)\n    combined_df.to_excel(\"extracted_tables.xlsx\", index=False)\n```\n\n### reportlab - Create PDFs\n\n#### Basic PDF Creation\n```python\nfrom reportlab.lib.pagesizes import letter\nfrom reportlab.pdfgen import canvas\n\nc = canvas.Canvas(\"hello.pdf\", pagesize=letter)\nwidth, height = letter\n\n# Add text\nc.drawString(100, height - 100, \"Hello World!\")\nc.drawString(100, height - 120, \"This is a PDF created with reportlab\")\n\n# Add a line\nc.line(100, height - 140, 400, height - 140)\n\n# Save\nc.save()\n```\n\n#### Create PDF with Multiple Pages\n```python\nfrom reportlab.lib.pagesizes import letter\nfrom reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak\nfrom reportlab.lib.styles import getSampleStyleSheet\n\ndoc = SimpleDocTemplate(\"report.pdf\", pagesize=letter)\nstyles = getSampleStyleSheet()\nstory = []\n\n# Add content\ntitle = Paragraph(\"Report Title\", styles['Title'])\nstory.append(title)\nstory.append(Spacer(1, 12))\n\nbody = Paragraph(\"This is the body of the report. \" * 20, styles['Normal'])\nstory.append(body)\nstory.append(PageBreak())\n\n# Page 2\nstory.append(Paragraph(\"Page 2\", styles['Heading1']))\nstory.append(Paragraph(\"Content for page 2\", styles['Normal']))\n\n# Build PDF\ndoc.build(story)\n```\n\n#### Subscripts and Superscripts\n\n**IMPORTANT**: Never use Unicode subscript/superscript characters (₀₁₂₃₄₅₆₇₈₉, ⁰¹²³⁴⁵⁶⁷⁸⁹) in ReportLab PDFs. The built-in fonts do not include these glyphs, causing them to render as solid black boxes.\n\nInstead, use ReportLab's XML markup tags in Paragraph objects:\n```python\nfrom reportlab.platypus import Paragraph\nfrom reportlab.lib.styles import getSampleStyleSheet\n\nstyles = getSampleStyleSheet()\n\n# Subscripts: use <sub> tag\nchemical = Paragraph(\"H<sub>2</sub>O\", styles['Normal'])\n\n# Superscripts: use <super> tag\nsquared = Paragraph(\"x<super>2</super> + y<super>2</super>\", styles['Normal'])\n```\n\nFor canvas-drawn text (not Paragraph objects), manually adjust font the size and position rather than using Unicode subscripts/superscripts.\n\n## Command-Line Tools\n\n### pdftotext (poppler-utils)\n```bash\n# Extract text\npdftotext input.pdf output.txt\n\n# Extract text preserving layout\npdftotext -layout input.pdf output.txt\n\n# Extract specific pages\npdftotext -f 1 -l 5 input.pdf output.txt  # Pages 1-5\n```\n\n### qpdf\n```bash\n# Merge PDFs\nqpdf --empty --pages file1.pdf file2.pdf -- merged.pdf\n\n# Split pages\nqpdf input.pdf --pages . 1-5 -- pages1-5.pdf\nqpdf input.pdf --pages . 6-10 -- pages6-10.pdf\n\n# Rotate pages\nqpdf input.pdf output.pdf --rotate=+90:1  # Rotate page 1 by 90 degrees\n\n# Remove password\nqpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf\n```\n\n### pdftk (if available)\n```bash\n# Merge\npdftk file1.pdf file2.pdf cat output merged.pdf\n\n# Split\npdftk input.pdf burst\n\n# Rotate\npdftk input.pdf rotate 1east output rotated.pdf\n```\n\n## Common Tasks\n\n### Extract Text from Scanned PDFs\n```python\n# Requires: pip install pytesseract pdf2image\nimport pytesseract\nfrom pdf2image import convert_from_path\n\n# Convert PDF to images\nimages = convert_from_path('scanned.pdf')\n\n# OCR each page\ntext = \"\"\nfor i, image in enumerate(images):\n    text += f\"Page {i+1}:\\n\"\n    text += pytesseract.image_to_string(image)\n    text += \"\\n\\n\"\n\nprint(text)\n```\n\n### Add Watermark\n```python\nfrom pypdf import PdfReader, PdfWriter\n\n# Create watermark (or load existing)\nwatermark = PdfReader(\"watermark.pdf\").pages[0]\n\n# Apply to all pages\nreader = PdfReader(\"document.pdf\")\nwriter = PdfWriter()\n\nfor page in reader.pages:\n    page.merge_page(watermark)\n    writer.add_page(page)\n\nwith open(\"watermarked.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n### Extract Images\n```bash\n# Using pdfimages (poppler-utils)\npdfimages -j input.pdf output_prefix\n\n# This extracts all images as output_prefix-000.jpg, output_prefix-001.jpg, etc.\n```\n\n### Password Protection\n```python\nfrom pypdf import PdfReader, PdfWriter\n\nreader = PdfReader(\"input.pdf\")\nwriter = PdfWriter()\n\nfor page in reader.pages:\n    writer.add_page(page)\n\n# Add password\nwriter.encrypt(\"userpassword\", \"ownerpassword\")\n\nwith open(\"encrypted.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n## Quick Reference\n\n| Task | Best Tool | Command/Code |\n|------|-----------|--------------|\n| Merge PDFs | pypdf | `writer.add_page(page)` |\n| Split PDFs | pypdf | One page per file |\n| Extract text | pdfplumber | `page.extract_text()` |\n| Extract tables | pdfplumber | `page.extract_tables()` |\n| Create PDFs | reportlab | Canvas or Platypus |\n| Command line merge | qpdf | `qpdf --empty --pages ...` |\n| OCR scanned PDFs | pytesseract | Convert to image first |\n| Fill PDF forms | pdf-lib or pypdf (see FORMS.md) | See FORMS.md |\n\n## Next Steps\n\n- For advanced pypdfium2 usage, see REFERENCE.md\n- For JavaScript libraries (pdf-lib), see REFERENCE.md\n- If you need to fill out a PDF form, follow the instructions in FORMS.md\n- For troubleshooting guides, see REFERENCE.md\n","resources/example-skills/xlsx/SKILL.md":"---\nname: xlsx\ndescription: \"Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like \\\"the xlsx in my downloads\\\") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# Requirements for Outputs\n\n## All Excel files\n\n### Professional Font\n- Use a consistent, professional font (e.g., Arial, Times New Roman) for all deliverables unless otherwise instructed by the user\n\n### Zero Formula Errors\n- Every Excel model MUST be delivered with ZERO formula errors (#REF!, #DIV/0!, #VALUE!, #N/A, #NAME?)\n\n### Preserve Existing Templates (when updating templates)\n- Study and EXACTLY match existing format, style, and conventions when modifying files\n- Never impose standardized formatting on files with established patterns\n- Existing template conventions ALWAYS override these guidelines\n\n## Financial models\n\n### Color Coding Standards\nUnless otherwise stated by the user or existing template\n\n#### Industry-Standard Color Conventions\n- **Blue text (RGB: 0,0,255)**: Hardcoded inputs, and numbers users will change for scenarios\n- **Black text (RGB: 0,0,0)**: ALL formulas and calculations\n- **Green text (RGB: 0,128,0)**: Links pulling from other worksheets within same workbook\n- **Red text (RGB: 255,0,0)**: External links to other files\n- **Yellow background (RGB: 255,255,0)**: Key assumptions needing attention or cells that need to be updated\n\n### Number Formatting Standards\n\n#### Required Format Rules\n- **Years**: Format as text strings (e.g., \"2024\" not \"2,024\")\n- **Currency**: Use $#,##0 format; ALWAYS specify units in headers (\"Revenue ($mm)\")\n- **Zeros**: Use number formatting to make all zeros \"-\", including percentages (e.g., \"$#,##0;($#,##0);-\")\n- **Percentages**: Default to 0.0% format (one decimal)\n- **Multiples**: Format as 0.0x for valuation multiples (EV/EBITDA, P/E)\n- **Negative numbers**: Use parentheses (123) not minus -123\n\n### Formula Construction Rules\n\n#### Assumptions Placement\n- Place ALL assumptions (growth rates, margins, multiples, etc.) in separate assumption cells\n- Use cell references instead of hardcoded values in formulas\n- Example: Use =B5*(1+$B$6) instead of =B5*1.05\n\n#### Formula Error Prevention\n- Verify all cell references are correct\n- Check for off-by-one errors in ranges\n- Ensure consistent formulas across all projection periods\n- Test with edge cases (zero values, negative numbers)\n- Verify no unintended circular references\n\n#### Documentation Requirements for Hardcodes\n- Comment or in cells beside (if end of table). Format: \"Source: [System/Document], [Date], [Specific Reference], [URL if applicable]\"\n- Examples:\n  - \"Source: Company 10-K, FY2024, Page 45, Revenue Note, [SEC EDGAR URL]\"\n  - \"Source: Company 10-Q, Q2 2025, Exhibit 99.1, [SEC EDGAR URL]\"\n  - \"Source: Bloomberg Terminal, 8/15/2025, AAPL US Equity\"\n  - \"Source: FactSet, 8/20/2025, Consensus Estimates Screen\"\n\n# XLSX creation, editing, and analysis\n\n## Overview\n\nA user may ask you to create, edit, or analyze the contents of an .xlsx file. You have different tools and workflows available for different tasks.\n\n## Important Requirements\n\n**LibreOffice Required for Formula Recalculation**: You can assume LibreOffice is installed for recalculating formula values using the `scripts/recalc.py` script. The script automatically configures LibreOffice on first run, including in sandboxed environments where Unix sockets are restricted (handled by `scripts/office/soffice.py`)\n\n## Reading and analyzing data\n\n### Data analysis with pandas\nFor data analysis, visualization, and basic operations, use **pandas** which provides powerful data manipulation capabilities:\n\n```python\nimport pandas as pd\n\n# Read Excel\ndf = pd.read_excel('file.xlsx')  # Default: first sheet\nall_sheets = pd.read_excel('file.xlsx', sheet_name=None)  # All sheets as dict\n\n# Analyze\ndf.head()      # Preview data\ndf.info()      # Column info\ndf.describe()  # Statistics\n\n# Write Excel\ndf.to_excel('output.xlsx', index=False)\n```\n\n## Excel File Workflows\n\n## CRITICAL: Use Formulas, Not Hardcoded Values\n\n**Always use Excel formulas instead of calculating values in Python and hardcoding them.** This ensures the spreadsheet remains dynamic and updateable.\n\n### ❌ WRONG - Hardcoding Calculated Values\n```python\n# Bad: Calculating in Python and hardcoding result\ntotal = df['Sales'].sum()\nsheet['B10'] = total  # Hardcodes 5000\n\n# Bad: Computing growth rate in Python\ngrowth = (df.iloc[-1]['Revenue'] - df.iloc[0]['Revenue']) / df.iloc[0]['Revenue']\nsheet['C5'] = growth  # Hardcodes 0.15\n\n# Bad: Python calculation for average\navg = sum(values) / len(values)\nsheet['D20'] = avg  # Hardcodes 42.5\n```\n\n### ✅ CORRECT - Using Excel Formulas\n```python\n# Good: Let Excel calculate the sum\nsheet['B10'] = '=SUM(B2:B9)'\n\n# Good: Growth rate as Excel formula\nsheet['C5'] = '=(C4-C2)/C2'\n\n# Good: Average using Excel function\nsheet['D20'] = '=AVERAGE(D2:D19)'\n```\n\nThis applies to ALL calculations - totals, percentages, ratios, differences, etc. The spreadsheet should be able to recalculate when source data changes.\n\n## Common Workflow\n1. **Choose tool**: pandas for data, openpyxl for formulas/formatting\n2. **Create/Load**: Create new workbook or load existing file\n3. **Modify**: Add/edit data, formulas, and formatting\n4. **Save**: Write to file\n5. **Recalculate formulas (MANDATORY IF USING FORMULAS)**: Use the scripts/recalc.py script\n   ```bash\n   python scripts/recalc.py output.xlsx\n   ```\n6. **Verify and fix any errors**: \n   - The script returns JSON with error details\n   - If `status` is `errors_found`, check `error_summary` for specific error types and locations\n   - Fix the identified errors and recalculate again\n   - Common errors to fix:\n     - `#REF!`: Invalid cell references\n     - `#DIV/0!`: Division by zero\n     - `#VALUE!`: Wrong data type in formula\n     - `#NAME?`: Unrecognized formula name\n\n### Creating new Excel files\n\n```python\n# Using openpyxl for formulas and formatting\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font, PatternFill, Alignment\n\nwb = Workbook()\nsheet = wb.active\n\n# Add data\nsheet['A1'] = 'Hello'\nsheet['B1'] = 'World'\nsheet.append(['Row', 'of', 'data'])\n\n# Add formula\nsheet['B2'] = '=SUM(A1:A10)'\n\n# Formatting\nsheet['A1'].font = Font(bold=True, color='FF0000')\nsheet['A1'].fill = PatternFill('solid', start_color='FFFF00')\nsheet['A1'].alignment = Alignment(horizontal='center')\n\n# Column width\nsheet.column_dimensions['A'].width = 20\n\nwb.save('output.xlsx')\n```\n\n### Editing existing Excel files\n\n```python\n# Using openpyxl to preserve formulas and formatting\nfrom openpyxl import load_workbook\n\n# Load existing file\nwb = load_workbook('existing.xlsx')\nsheet = wb.active  # or wb['SheetName'] for specific sheet\n\n# Working with multiple sheets\nfor sheet_name in wb.sheetnames:\n    sheet = wb[sheet_name]\n    print(f\"Sheet: {sheet_name}\")\n\n# Modify cells\nsheet['A1'] = 'New Value'\nsheet.insert_rows(2)  # Insert row at position 2\nsheet.delete_cols(3)  # Delete column 3\n\n# Add new sheet\nnew_sheet = wb.create_sheet('NewSheet')\nnew_sheet['A1'] = 'Data'\n\nwb.save('modified.xlsx')\n```\n\n## Recalculating formulas\n\nExcel files created or modified by openpyxl contain formulas as strings but not calculated values. Use the provided `scripts/recalc.py` script to recalculate formulas:\n\n```bash\npython scripts/recalc.py <excel_file> [timeout_seconds]\n```\n\nExample:\n```bash\npython scripts/recalc.py output.xlsx 30\n```\n\nThe script:\n- Automatically sets up LibreOffice macro on first run\n- Recalculates all formulas in all sheets\n- Scans ALL cells for Excel errors (#REF!, #DIV/0!, etc.)\n- Returns JSON with detailed error locations and counts\n- Works on both Linux and macOS\n\n## Formula Verification Checklist\n\nQuick checks to ensure formulas work correctly:\n\n### Essential Verification\n- [ ] **Test 2-3 sample references**: Verify they pull correct values before building full model\n- [ ] **Column mapping**: Confirm Excel columns match (e.g., column 64 = BL, not BK)\n- [ ] **Row offset**: Remember Excel rows are 1-indexed (DataFrame row 5 = Excel row 6)\n\n### Common Pitfalls\n- [ ] **NaN handling**: Check for null values with `pd.notna()`\n- [ ] **Far-right columns**: FY data often in columns 50+ \n- [ ] **Multiple matches**: Search all occurrences, not just first\n- [ ] **Division by zero**: Check denominators before using `/` in formulas (#DIV/0!)\n- [ ] **Wrong references**: Verify all cell references point to intended cells (#REF!)\n- [ ] **Cross-sheet references**: Use correct format (Sheet1!A1) for linking sheets\n\n### Formula Testing Strategy\n- [ ] **Start small**: Test formulas on 2-3 cells before applying broadly\n- [ ] **Verify dependencies**: Check all cells referenced in formulas exist\n- [ ] **Test edge cases**: Include zero, negative, and very large values\n\n### Interpreting scripts/recalc.py Output\nThe script returns JSON with error details:\n```json\n{\n  \"status\": \"success\",           // or \"errors_found\"\n  \"total_errors\": 0,              // Total error count\n  \"total_formulas\": 42,           // Number of formulas in file\n  \"error_summary\": {              // Only present if errors found\n    \"#REF!\": {\n      \"count\": 2,\n      \"locations\": [\"Sheet1!B5\", \"Sheet1!C10\"]\n    }\n  }\n}\n```\n\n## Best Practices\n\n### Library Selection\n- **pandas**: Best for data analysis, bulk operations, and simple data export\n- **openpyxl**: Best for complex formatting, formulas, and Excel-specific features\n\n### Working with openpyxl\n- Cell indices are 1-based (row=1, column=1 refers to cell A1)\n- Use `data_only=True` to read calculated values: `load_workbook('file.xlsx', data_only=True)`\n- **Warning**: If opened with `data_only=True` and saved, formulas are replaced with values and permanently lost\n- For large files: Use `read_only=True` for reading or `write_only=True` for writing\n- Formulas are preserved but not evaluated - use scripts/recalc.py to update values\n\n### Working with pandas\n- Specify data types to avoid inference issues: `pd.read_excel('file.xlsx', dtype={'id': str})`\n- For large files, read specific columns: `pd.read_excel('file.xlsx', usecols=['A', 'C', 'E'])`\n- Handle dates properly: `pd.read_excel('file.xlsx', parse_dates=['date_column'])`\n\n## Code Style Guidelines\n**IMPORTANT**: When generating Python code for Excel operations:\n- Write minimal, concise Python code without unnecessary comments\n- Avoid verbose variable names and redundant operations\n- Avoid unnecessary print statements\n\n**For Excel files themselves**:\n- Add comments to cells with complex formulas or important assumptions\n- Document data sources for hardcoded values\n- Include notes for key calculations and model sections","resources/example-skills/docx/SKILL.md":"---\nname: docx\ndescription: \"Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files). Triggers include: any mention of \\\"Word doc\\\", \\\"word document\\\", \\\".docx\\\", or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a \\\"report\\\", \\\"memo\\\", \\\"letter\\\", \\\"template\\\", or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# DOCX creation, editing, and analysis\n\n## Overview\n\nA .docx file is a ZIP archive containing XML files.\n\n## Quick Reference\n\n| Task | Approach |\n|------|----------|\n| Read/analyze content | `pandoc` or unpack for raw XML |\n| Create new document | Use `docx-js` - see Creating New Documents below |\n| Edit existing document | Unpack → edit XML → repack - see Editing Existing Documents below |\n\n### Converting .doc to .docx\n\nLegacy `.doc` files must be converted before editing:\n\n```bash\npython scripts/office/soffice.py --headless --convert-to docx document.doc\n```\n\n### Reading Content\n\n```bash\n# Text extraction with tracked changes\npandoc --track-changes=all document.docx -o output.md\n\n# Raw XML access\npython scripts/office/unpack.py document.docx unpacked/\n```\n\n### Converting to Images\n\n```bash\npython scripts/office/soffice.py --headless --convert-to pdf document.docx\npdftoppm -jpeg -r 150 document.pdf page\n```\n\n### Accepting Tracked Changes\n\nTo produce a clean document with all tracked changes accepted (requires LibreOffice):\n\n```bash\npython scripts/accept_changes.py input.docx output.docx\n```\n\n---\n\n## Creating New Documents\n\nGenerate .docx files with JavaScript, then validate. Install: `npm install -g docx`\n\n### Setup\n```javascript\nconst { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun,\n        Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink,\n        TableOfContents, HeadingLevel, BorderStyle, WidthType, ShadingType,\n        VerticalAlign, PageNumber, PageBreak } = require('docx');\n\nconst doc = new Document({ sections: [{ children: [/* content */] }] });\nPacker.toBuffer(doc).then(buffer => fs.writeFileSync(\"doc.docx\", buffer));\n```\n\n### Validation\nAfter creating the file, validate it. If validation fails, unpack, fix the XML, and repack.\n```bash\npython scripts/office/validate.py doc.docx\n```\n\n### Page Size\n\n```javascript\n// CRITICAL: docx-js defaults to A4, not US Letter\n// Always set page size explicitly for consistent results\nsections: [{\n  properties: {\n    page: {\n      size: {\n        width: 12240,   // 8.5 inches in DXA\n        height: 15840   // 11 inches in DXA\n      },\n      margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } // 1 inch margins\n    }\n  },\n  children: [/* content */]\n}]\n```\n\n**Common page sizes (DXA units, 1440 DXA = 1 inch):**\n\n| Paper | Width | Height | Content Width (1\" margins) |\n|-------|-------|--------|---------------------------|\n| US Letter | 12,240 | 15,840 | 9,360 |\n| A4 (default) | 11,906 | 16,838 | 9,026 |\n\n**Landscape orientation:** docx-js swaps width/height internally, so pass portrait dimensions and let it handle the swap:\n```javascript\nsize: {\n  width: 12240,   // Pass SHORT edge as width\n  height: 15840,  // Pass LONG edge as height\n  orientation: PageOrientation.LANDSCAPE  // docx-js swaps them in the XML\n},\n// Content width = 15840 - left margin - right margin (uses the long edge)\n```\n\n### Styles (Override Built-in Headings)\n\nUse Arial as the default font (universally supported). Keep titles black for readability.\n\n```javascript\nconst doc = new Document({\n  styles: {\n    default: { document: { run: { font: \"Arial\", size: 24 } } }, // 12pt default\n    paragraphStyles: [\n      // IMPORTANT: Use exact IDs to override built-in styles\n      { id: \"Heading1\", name: \"Heading 1\", basedOn: \"Normal\", next: \"Normal\", quickFormat: true,\n        run: { size: 32, bold: true, font: \"Arial\" },\n        paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } }, // outlineLevel required for TOC\n      { id: \"Heading2\", name: \"Heading 2\", basedOn: \"Normal\", next: \"Normal\", quickFormat: true,\n        run: { size: 28, bold: true, font: \"Arial\" },\n        paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 } },\n    ]\n  },\n  sections: [{\n    children: [\n      new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun(\"Title\")] }),\n    ]\n  }]\n});\n```\n\n### Lists (NEVER use unicode bullets)\n\n```javascript\n// ❌ WRONG - never manually insert bullet characters\nnew Paragraph({ children: [new TextRun(\"• Item\")] })  // BAD\nnew Paragraph({ children: [new TextRun(\"\\u2022 Item\")] })  // BAD\n\n// ✅ CORRECT - use numbering config with LevelFormat.BULLET\nconst doc = new Document({\n  numbering: {\n    config: [\n      { reference: \"bullets\",\n        levels: [{ level: 0, format: LevelFormat.BULLET, text: \"•\", alignment: AlignmentType.LEFT,\n          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },\n      { reference: \"numbers\",\n        levels: [{ level: 0, format: LevelFormat.DECIMAL, text: \"%1.\", alignment: AlignmentType.LEFT,\n          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },\n    ]\n  },\n  sections: [{\n    children: [\n      new Paragraph({ numbering: { reference: \"bullets\", level: 0 },\n        children: [new TextRun(\"Bullet item\")] }),\n      new Paragraph({ numbering: { reference: \"numbers\", level: 0 },\n        children: [new TextRun(\"Numbered item\")] }),\n    ]\n  }]\n});\n\n// ⚠️ Each reference creates INDEPENDENT numbering\n// Same reference = continues (1,2,3 then 4,5,6)\n// Different reference = restarts (1,2,3 then 1,2,3)\n```\n\n### Tables\n\n**CRITICAL: Tables need dual widths** - set both `columnWidths` on the table AND `width` on each cell. Without both, tables render incorrectly on some platforms.\n\n```javascript\n// CRITICAL: Always set table width for consistent rendering\n// CRITICAL: Use ShadingType.CLEAR (not SOLID) to prevent black backgrounds\nconst border = { style: BorderStyle.SINGLE, size: 1, color: \"CCCCCC\" };\nconst borders = { top: border, bottom: border, left: border, right: border };\n\nnew Table({\n  width: { size: 9360, type: WidthType.DXA }, // Always use DXA (percentages break in Google Docs)\n  columnWidths: [4680, 4680], // Must sum to table width (DXA: 1440 = 1 inch)\n  rows: [\n    new TableRow({\n      children: [\n        new TableCell({\n          borders,\n          width: { size: 4680, type: WidthType.DXA }, // Also set on each cell\n          shading: { fill: \"D5E8F0\", type: ShadingType.CLEAR }, // CLEAR not SOLID\n          margins: { top: 80, bottom: 80, left: 120, right: 120 }, // Cell padding (internal, not added to width)\n          children: [new Paragraph({ children: [new TextRun(\"Cell\")] })]\n        })\n      ]\n    })\n  ]\n})\n```\n\n**Table width calculation:**\n\nAlways use `WidthType.DXA` — `WidthType.PERCENTAGE` breaks in Google Docs.\n\n```javascript\n// Table width = sum of columnWidths = content width\n// US Letter with 1\" margins: 12240 - 2880 = 9360 DXA\nwidth: { size: 9360, type: WidthType.DXA },\ncolumnWidths: [7000, 2360]  // Must sum to table width\n```\n\n**Width rules:**\n- **Always use `WidthType.DXA`** — never `WidthType.PERCENTAGE` (incompatible with Google Docs)\n- Table width must equal the sum of `columnWidths`\n- Cell `width` must match corresponding `columnWidth`\n- Cell `margins` are internal padding - they reduce content area, not add to cell width\n- For full-width tables: use content width (page width minus left and right margins)\n\n### Images\n\n```javascript\n// CRITICAL: type parameter is REQUIRED\nnew Paragraph({\n  children: [new ImageRun({\n    type: \"png\", // Required: png, jpg, jpeg, gif, bmp, svg\n    data: fs.readFileSync(\"image.png\"),\n    transformation: { width: 200, height: 150 },\n    altText: { title: \"Title\", description: \"Desc\", name: \"Name\" } // All three required\n  })]\n})\n```\n\n### Page Breaks\n\n```javascript\n// CRITICAL: PageBreak must be inside a Paragraph\nnew Paragraph({ children: [new PageBreak()] })\n\n// Or use pageBreakBefore\nnew Paragraph({ pageBreakBefore: true, children: [new TextRun(\"New page\")] })\n```\n\n### Table of Contents\n\n```javascript\n// CRITICAL: Headings must use HeadingLevel ONLY - no custom styles\nnew TableOfContents(\"Table of Contents\", { hyperlink: true, headingStyleRange: \"1-3\" })\n```\n\n### Headers/Footers\n\n```javascript\nsections: [{\n  properties: {\n    page: { margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } } // 1440 = 1 inch\n  },\n  headers: {\n    default: new Header({ children: [new Paragraph({ children: [new TextRun(\"Header\")] })] })\n  },\n  footers: {\n    default: new Footer({ children: [new Paragraph({\n      children: [new TextRun(\"Page \"), new TextRun({ children: [PageNumber.CURRENT] })]\n    })] })\n  },\n  children: [/* content */]\n}]\n```\n\n### Critical Rules for docx-js\n\n- **Set page size explicitly** - docx-js defaults to A4; use US Letter (12240 x 15840 DXA) for US documents\n- **Landscape: pass portrait dimensions** - docx-js swaps width/height internally; pass short edge as `width`, long edge as `height`, and set `orientation: PageOrientation.LANDSCAPE`\n- **Never use `\\n`** - use separate Paragraph elements\n- **Never use unicode bullets** - use `LevelFormat.BULLET` with numbering config\n- **PageBreak must be in Paragraph** - standalone creates invalid XML\n- **ImageRun requires `type`** - always specify png/jpg/etc\n- **Always set table `width` with DXA** - never use `WidthType.PERCENTAGE` (breaks in Google Docs)\n- **Tables need dual widths** - `columnWidths` array AND cell `width`, both must match\n- **Table width = sum of columnWidths** - for DXA, ensure they add up exactly\n- **Always add cell margins** - use `margins: { top: 80, bottom: 80, left: 120, right: 120 }` for readable padding\n- **Use `ShadingType.CLEAR`** - never SOLID for table shading\n- **TOC requires HeadingLevel only** - no custom styles on heading paragraphs\n- **Override built-in styles** - use exact IDs: \"Heading1\", \"Heading2\", etc.\n- **Include `outlineLevel`** - required for TOC (0 for H1, 1 for H2, etc.)\n\n---\n\n## Editing Existing Documents\n\n**Follow all 3 steps in order.**\n\n### Step 1: Unpack\n```bash\npython scripts/office/unpack.py document.docx unpacked/\n```\nExtracts XML, pretty-prints, merges adjacent runs, and converts smart quotes to XML entities (`&#x201C;` etc.) so they survive editing. Use `--merge-runs false` to skip run merging.\n\n### Step 2: Edit XML\n\nEdit files in `unpacked/word/`. See XML Reference below for patterns.\n\n**Use \"Claude\" as the author** for tracked changes and comments, unless the user explicitly requests use of a different name.\n\n**Use the Edit tool directly for string replacement. Do not write Python scripts.** Scripts introduce unnecessary complexity. The Edit tool shows exactly what is being replaced.\n\n**CRITICAL: Use smart quotes for new content.** When adding text with apostrophes or quotes, use XML entities to produce smart quotes:\n```xml\n<!-- Use these entities for professional typography -->\n<w:t>Here&#x2019;s a quote: &#x201C;Hello&#x201D;</w:t>\n```\n| Entity | Character |\n|--------|-----------|\n| `&#x2018;` | ‘ (left single) |\n| `&#x2019;` | ’ (right single / apostrophe) |\n| `&#x201C;` | “ (left double) |\n| `&#x201D;` | ” (right double) |\n\n**Adding comments:** Use `comment.py` to handle boilerplate across multiple XML files (text must be pre-escaped XML):\n```bash\npython scripts/comment.py unpacked/ 0 \"Comment text with &amp; and &#x2019;\"\npython scripts/comment.py unpacked/ 1 \"Reply text\" --parent 0  # reply to comment 0\npython scripts/comment.py unpacked/ 0 \"Text\" --author \"Custom Author\"  # custom author name\n```\nThen add markers to document.xml (see Comments in XML Reference).\n\n### Step 3: Pack\n```bash\npython scripts/office/pack.py unpacked/ output.docx --original document.docx\n```\nValidates with auto-repair, condenses XML, and creates DOCX. Use `--validate false` to skip.\n\n**Auto-repair will fix:**\n- `durableId` >= 0x7FFFFFFF (regenerates valid ID)\n- Missing `xml:space=\"preserve\"` on `<w:t>` with whitespace\n\n**Auto-repair won't fix:**\n- Malformed XML, invalid element nesting, missing relationships, schema violations\n\n### Common Pitfalls\n\n- **Replace entire `<w:r>` elements**: When adding tracked changes, replace the whole `<w:r>...</w:r>` block with `<w:del>...<w:ins>...` as siblings. Don't inject tracked change tags inside a run.\n- **Preserve `<w:rPr>` formatting**: Copy the original run's `<w:rPr>` block into your tracked change runs to maintain bold, font size, etc.\n\n---\n\n## XML Reference\n\n### Schema Compliance\n\n- **Element order in `<w:pPr>`**: `<w:pStyle>`, `<w:numPr>`, `<w:spacing>`, `<w:ind>`, `<w:jc>`, `<w:rPr>` last\n- **Whitespace**: Add `xml:space=\"preserve\"` to `<w:t>` with leading/trailing spaces\n- **RSIDs**: Must be 8-digit hex (e.g., `00AB1234`)\n\n### Tracked Changes\n\n**Insertion:**\n```xml\n<w:ins w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:t>inserted text</w:t></w:r>\n</w:ins>\n```\n\n**Deletion:**\n```xml\n<w:del w:id=\"2\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:delText>deleted text</w:delText></w:r>\n</w:del>\n```\n\n**Inside `<w:del>`**: Use `<w:delText>` instead of `<w:t>`, and `<w:delInstrText>` instead of `<w:instrText>`.\n\n**Minimal edits** - only mark what changes:\n```xml\n<!-- Change \"30 days\" to \"60 days\" -->\n<w:r><w:t>The term is </w:t></w:r>\n<w:del w:id=\"1\" w:author=\"Claude\" w:date=\"...\">\n  <w:r><w:delText>30</w:delText></w:r>\n</w:del>\n<w:ins w:id=\"2\" w:author=\"Claude\" w:date=\"...\">\n  <w:r><w:t>60</w:t></w:r>\n</w:ins>\n<w:r><w:t> days.</w:t></w:r>\n```\n\n**Deleting entire paragraphs/list items** - when removing ALL content from a paragraph, also mark the paragraph mark as deleted so it merges with the next paragraph. Add `<w:del/>` inside `<w:pPr><w:rPr>`:\n```xml\n<w:p>\n  <w:pPr>\n    <w:numPr>...</w:numPr>  <!-- list numbering if present -->\n    <w:rPr>\n      <w:del w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\"/>\n    </w:rPr>\n  </w:pPr>\n  <w:del w:id=\"2\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n    <w:r><w:delText>Entire paragraph content being deleted...</w:delText></w:r>\n  </w:del>\n</w:p>\n```\nWithout the `<w:del/>` in `<w:pPr><w:rPr>`, accepting changes leaves an empty paragraph/list item.\n\n**Rejecting another author's insertion** - nest deletion inside their insertion:\n```xml\n<w:ins w:author=\"Jane\" w:id=\"5\">\n  <w:del w:author=\"Claude\" w:id=\"10\">\n    <w:r><w:delText>their inserted text</w:delText></w:r>\n  </w:del>\n</w:ins>\n```\n\n**Restoring another author's deletion** - add insertion after (don't modify their deletion):\n```xml\n<w:del w:author=\"Jane\" w:id=\"5\">\n  <w:r><w:delText>deleted text</w:delText></w:r>\n</w:del>\n<w:ins w:author=\"Claude\" w:id=\"10\">\n  <w:r><w:t>deleted text</w:t></w:r>\n</w:ins>\n```\n\n### Comments\n\nAfter running `comment.py` (see Step 2), add markers to document.xml. For replies, use `--parent` flag and nest markers inside the parent's.\n\n**CRITICAL: `<w:commentRangeStart>` and `<w:commentRangeEnd>` are siblings of `<w:r>`, never inside `<w:r>`.**\n\n```xml\n<!-- Comment markers are direct children of w:p, never inside w:r -->\n<w:commentRangeStart w:id=\"0\"/>\n<w:del w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:delText>deleted</w:delText></w:r>\n</w:del>\n<w:r><w:t> more text</w:t></w:r>\n<w:commentRangeEnd w:id=\"0\"/>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"0\"/></w:r>\n\n<!-- Comment 0 with reply 1 nested inside -->\n<w:commentRangeStart w:id=\"0\"/>\n  <w:commentRangeStart w:id=\"1\"/>\n  <w:r><w:t>text</w:t></w:r>\n  <w:commentRangeEnd w:id=\"1\"/>\n<w:commentRangeEnd w:id=\"0\"/>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"0\"/></w:r>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"1\"/></w:r>\n```\n\n### Images\n\n1. Add image file to `word/media/`\n2. Add relationship to `word/_rels/document.xml.rels`:\n```xml\n<Relationship Id=\"rId5\" Type=\".../image\" Target=\"media/image1.png\"/>\n```\n3. Add content type to `[Content_Types].xml`:\n```xml\n<Default Extension=\"png\" ContentType=\"image/png\"/>\n```\n4. Reference in document.xml:\n```xml\n<w:drawing>\n  <wp:inline>\n    <wp:extent cx=\"914400\" cy=\"914400\"/>  <!-- EMUs: 914400 = 1 inch -->\n    <a:graphic>\n      <a:graphicData uri=\".../picture\">\n        <pic:pic>\n          <pic:blipFill><a:blip r:embed=\"rId5\"/></pic:blipFill>\n        </pic:pic>\n      </a:graphicData>\n    </a:graphic>\n  </wp:inline>\n</w:drawing>\n```\n\n---\n\n## Dependencies\n\n- **pandoc**: Text extraction\n- **docx**: `npm install -g docx` (new documents)\n- **LibreOffice**: PDF conversion (auto-configured for sandboxed environments via `scripts/office/soffice.py`)\n- **Poppler**: `pdftoppm` for images\n","resources/example-skills/skill-creator/SKILL.md":"---\nname: skill-creator\ndescription: Guide for creating effective skills. Use when creating a new skill or updating an existing skill that extends agent capabilities with specialized knowledge, workflows, or tool integrations.\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills.\n\n## About Skills\n\nSkills are modular, self-contained packages that extend agent capabilities by providing\nspecialized knowledge, workflows, and tools. Think of them as \"onboarding guides\" for specific\ndomains or tasks—they transform a general-purpose agent into a specialized agent\nequipped with procedural knowledge that no model can fully possess.\n\n### What Skills Provide\n\n1. Specialized workflows - Multi-step procedures for specific domains\n2. Tool integrations - Instructions for working with specific file formats or APIs\n3. Domain expertise - Company-specific knowledge, schemas, business logic\n4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks\n\n## Core Principles\n\n### Concise is Key\n\nThe context window is a public good. Skills share the context window with everything else the agent needs: system prompt, conversation history, other Skills' metadata, and the actual user request.\n\n**Default assumption: The agent is already very capable.** Only add context the agent doesn't already have. Challenge each piece of information: \"Does the agent really need this explanation?\" and \"Does this paragraph justify its token cost?\"\n\nPrefer concise examples over verbose explanations.\n\n### Set Appropriate Degrees of Freedom\n\nMatch the level of specificity to the task's fragility and variability:\n\n**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.\n\n**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.\n\n**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.\n\nThink of the agent exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).\n\n### Anatomy of a Skill\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   ├── description: (required)\n│   │   └── compatibility: (optional, rarely needed)\n│   └── Markdown instructions (required)\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n#### SKILL.md (required)\n\nEvery SKILL.md consists of:\n\n- **Frontmatter** (YAML): Contains `name` and `description` fields (required), plus optional fields like `license`, `metadata`, and `compatibility`. Only `name` and `description` are read by the agent to determine when the skill triggers, so be clear and comprehensive about what the skill is and when it should be used. The `compatibility` field is for noting environment requirements (target product, system packages, etc.) but most skills don't need it.\n- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).\n\n#### Bundled Resources (optional)\n\n##### Scripts (`scripts/`)\n\nExecutable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.\n\n- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed\n- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks\n- **Benefits**: Token efficient, deterministic, may be executed without loading into context\n- **Note**: Scripts may still need to be read by the agent for patching or environment-specific adjustments\n\n##### References (`references/`)\n\nDocumentation and reference material intended to be loaded as needed into context to inform the agent's process and thinking.\n\n- **When to include**: For documentation that the agent should reference while working\n- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications\n- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides\n- **Benefits**: Keeps SKILL.md lean, loaded only when the agent determines it's needed\n- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md\n- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.\n\n##### Assets (`assets/`)\n\nFiles not intended to be loaded into context, but rather used within the output the agent produces.\n\n- **When to include**: When the skill needs files that will be used in the final output\n- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography\n- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified\n- **Benefits**: Separates output resources from documentation, enables the agent to use files without loading them into context\n\n#### What to Not Include in a Skill\n\nA skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:\n\n- README.md\n- INSTALLATION_GUIDE.md\n- QUICK_REFERENCE.md\n- CHANGELOG.md\n- etc.\n\nThe skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxilary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.\n\n### Progressive Disclosure Design Principle\n\nSkills use a three-level loading system to manage context efficiently:\n\n1. **Metadata (name + description)** - Always in context (~100 words)\n2. **SKILL.md body** - When skill triggers (<5k words)\n3. **Bundled resources** - As needed by the agent (Unlimited because scripts can be executed without reading into context window)\n\n#### Progressive Disclosure Patterns\n\nKeep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.\n\n**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.\n\n**Pattern 1: High-level guide with references**\n\n```markdown\n# PDF Processing\n\n## Quick start\n\nExtract text with pdfplumber:\n[code example]\n\n## Advanced features\n\n- **Form filling**: See [FORMS.md](FORMS.md) for complete guide\n- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods\n- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns\n```\n\nThe agent loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.\n\n**Pattern 2: Domain-specific organization**\n\nFor Skills with multiple domains, organize content by domain to avoid loading irrelevant context:\n\n```\nbigquery-skill/\n├── SKILL.md (overview and navigation)\n└── reference/\n    ├── finance.md (revenue, billing metrics)\n    ├── sales.md (opportunities, pipeline)\n    ├── product.md (API usage, features)\n    └── marketing.md (campaigns, attribution)\n```\n\nWhen a user asks about sales metrics, the agent only reads sales.md.\n\nSimilarly, for skills supporting multiple frameworks or variants, organize by variant:\n\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md (AWS deployment patterns)\n    ├── gcp.md (GCP deployment patterns)\n    └── azure.md (Azure deployment patterns)\n```\n\nWhen the user chooses AWS, the agent only reads aws.md.\n\n**Pattern 3: Conditional details**\n\nShow basic content, link to advanced content:\n\n```markdown\n# DOCX Processing\n\n## Creating documents\n\nUse docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).\n\n## Editing documents\n\nFor simple edits, modify the XML directly.\n\n**For tracked changes**: See [REDLINING.md](REDLINING.md)\n**For OOXML details**: See [OOXML.md](OOXML.md)\n```\n\nThe agent reads REDLINING.md or OOXML.md only when the user needs those features.\n\n**Important guidelines:**\n\n- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.\n- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so the agent can see the full scope when previewing.\n\n## Skill Creation Process\n\nSkill creation involves these steps:\n\n1. Understand the skill with concrete examples\n2. Plan reusable skill contents (scripts, references, assets)\n3. Initialize the skill (run init_skill.py)\n4. Edit the skill (implement resources and write SKILL.md)\n5. Package the skill (run package_skill.py)\n6. Iterate based on real usage\n\nFollow these steps in order, skipping only if there is a clear reason why they are not applicable.\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.\n\n### Step 3: Initializing the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists, and iteration or packaging is needed. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage (run from the skill-creator skill directory):\n\n```bash\npython scripts/init_skill.py <skill-name> --path <output-directory>\n```\n\nNote: The scripts are located in this skill's `scripts/` directory. Use the full path if running from a different directory.\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Creates example resource directories: `scripts/`, `references/`, and `assets/`\n- Adds example files in each directory that can be customized or deleted\n\nAfter initialization, customize or remove the generated SKILL.md and example files as needed.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for an agent to use. Include information that would be beneficial and non-obvious to the agent. Consider what procedural knowledge, domain-specific details, or reusable assets would help the agent execute these tasks more effectively.\n\n#### Learn Proven Design Patterns\n\nConsult these helpful guides based on your skill's needs:\n\n- **Multi-step processes**: See references/workflows.md for sequential workflows and conditional logic\n- **Specific output formats or quality standards**: See references/output-patterns.md for template and example patterns\n\nThese files contain established best practices for effective skill design.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nAny example files and directories not needed for the skill should be deleted. The initialization script creates example files in `scripts/`, `references/`, and `assets/` to demonstrate structure, but most skills won't need all of them.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name` and `description`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps the agent understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to the agent.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when the agent needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n\nDo not include any other fields in YAML frontmatter.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n### Step 5: Packaging a Skill\n\nOnce development of the skill is complete, it must be packaged into a distributable .skill file that gets shared with the user. The packaging process automatically validates the skill first to ensure it meets all requirements.\n\nUsage (run from the skill-creator skill directory):\n\n```bash\npython scripts/package_skill.py <path/to/skill-folder>\n```\n\nOptional output directory specification:\n\n```bash\npython scripts/package_skill.py <path/to/skill-folder> ./dist\n```\n\nNote: The scripts are located in this skill's `scripts/` directory. Use the full path if running from a different directory.\n\nThe packaging script will:\n\n1. **Validate** the skill automatically, checking:\n   - YAML frontmatter format and required fields\n   - Skill naming conventions and directory structure\n   - Description completeness and quality\n   - File organization and resource references\n\n2. **Package** the skill if validation passes, creating a .skill file named after the skill (e.g., `my-skill.skill`) that includes all files and maintains the proper directory structure for distribution. The .skill file is a zip file with a .skill extension.\n\nIf validation fails, the script will report the errors and exit without creating a package. Fix any validation errors and run the packaging command again.\n\n### Step 6: Iterate\n\nAfter testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.\n\n**Iteration workflow:**\n\n1. Use the skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify how SKILL.md or bundled resources should be updated\n4. Implement changes and test again\n","resources/example-skills/skill-creator/references/workflows.md":"# Workflow Patterns\n\n## Sequential Workflows\n\nFor complex tasks, break operations into clear, sequential steps. It is often helpful to give the agent an overview of the process towards the beginning of SKILL.md:\n\n```markdown\nFilling a PDF form involves these steps:\n\n1. Analyze the form (run analyze_form.py)\n2. Create field mapping (edit fields.json)\n3. Validate mapping (run validate_fields.py)\n4. Fill the form (run fill_form.py)\n5. Verify output (run verify_output.py)\n```\n\n## Conditional Workflows\n\nFor tasks with branching logic, guide the agent through decision points:\n\n```markdown\n1. Determine the modification type:\n   **Creating new content?** → Follow \"Creation workflow\" below\n   **Editing existing content?** → Follow \"Editing workflow\" below\n\n2. Creation workflow: [steps]\n3. Editing workflow: [steps]\n```","resources/example-skills/skill-security-auditor/references/secrets-patterns.md":"# Secrets Detection Patterns\n\nRegex patterns and rules for detecting hardcoded secrets, credentials, and sensitive data in source code.\n\n## Table of Contents\n\n- [API Keys and Tokens](#api-keys-and-tokens)\n- [Cloud Provider Credentials](#cloud-provider-credentials)\n- [Database Connection Strings](#database-connection-strings)\n- [Private Keys and Certificates](#private-keys-and-certificates)\n- [Generic Patterns](#generic-patterns)\n- [Files to Always Check](#files-to-always-check)\n- [False Positive Reduction](#false-positive-reduction)\n\n## API Keys and Tokens\n\n| Service | Pattern | Example |\n|---------|---------|---------|\n| AWS Access Key | `AKIA[0-9A-Z]{16}` | AKIAIOSFODNN7EXAMPLE |\n| AWS Secret Key | `(?i)aws_secret_access_key\\s*=\\s*\\S{40}` | |\n| GitHub Token | `gh[ps]_[A-Za-z0-9_]{36,}` | ghp_xxxxxxxxxxxx |\n| GitHub Fine-grained | `github_pat_[A-Za-z0-9_]{22,}` | |\n| GitLab Token | `glpat-[A-Za-z0-9\\-]{20,}` | |\n| Slack Token | `xox[baprs]-[A-Za-z0-9\\-]{10,}` | |\n| Slack Webhook | `https://hooks\\.slack\\.com/services/T[A-Z0-9]+/B[A-Z0-9]+/[A-Za-z0-9]+` | |\n| Stripe Secret | `sk_live_[A-Za-z0-9]{24,}` | |\n| Stripe Publishable | `pk_live_[A-Za-z0-9]{24,}` | |\n| Twilio | `SK[0-9a-fA-F]{32}` | |\n| SendGrid | `SG\\.[A-Za-z0-9\\-_]{22}\\.[A-Za-z0-9\\-_]{43}` | |\n| Mailgun | `key-[0-9a-zA-Z]{32}` | |\n| Google API Key | `AIza[0-9A-Za-z\\-_]{35}` | |\n| Google OAuth | `[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com` | |\n| Heroku API Key | `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}` | |\n| npm Token | `npm_[A-Za-z0-9]{36}` | |\n| PyPI Token | `pypi-[A-Za-z0-9\\-_]{50,}` | |\n\n## Cloud Provider Credentials\n\n### AWS\n```\n# Access Key ID\nAKIA[0-9A-Z]{16}\n\n# Secret Access Key (in config context)\n(?i)(aws_secret_access_key|aws_secret_key)\\s*[=:]\\s*[A-Za-z0-9/+=]{40}\n\n# Session Token\n(?i)aws_session_token\\s*[=:]\\s*\\S+\n```\n\n### GCP\n```\n# Service account key file indicators\n\"type\"\\s*:\\s*\"service_account\"\n\"private_key\"\\s*:\\s*\"-----BEGIN\n\n# OAuth client secret\n(?i)client_secret\\s*[=:]\\s*\\S+\n```\n\n### Azure\n```\n# Storage account key\n(?i)(AccountKey|account_key)\\s*[=:]\\s*[A-Za-z0-9+/=]{86,}\n\n# Connection strings\n(?i)(DefaultEndpointsProtocol|AccountName|AccountKey)=[^;\\s]+\n```\n\n## Database Connection Strings\n\n```\n# Generic with embedded password\n(?i)(mysql|postgres|postgresql|mongodb|redis|mssql|sqlserver)://[^:]+:[^@]+@\n\n# Django DATABASE_URL\n(?i)DATABASE_URL\\s*=\\s*\\S+://\\S+:\\S+@\n\n# JDBC with password\n(?i)jdbc:[a-z]+://[^;]+password=[^;\\s]+\n```\n\n## Private Keys and Certificates\n\n```\n# RSA private key\n-----BEGIN RSA PRIVATE KEY-----\n\n# Generic private key\n-----BEGIN PRIVATE KEY-----\n\n# EC private key\n-----BEGIN EC PRIVATE KEY-----\n\n# OpenSSH private key\n-----BEGIN OPENSSH PRIVATE KEY-----\n\n# PGP private key\n-----BEGIN PGP PRIVATE KEY BLOCK-----\n\n# Certificate (not a secret, but may indicate key nearby)\n-----BEGIN CERTIFICATE-----\n```\n\n## Generic Patterns\n\nThese catch secrets not covered by service-specific patterns:\n\n```\n# Assignment patterns with secret-like variable names\n(?i)(password|passwd|pwd|secret|token|api_key|apikey|api_secret|access_key|auth_token|credentials)\\s*[=:]\\s*['\"][^'\"]{8,}['\"]\n\n# Bearer tokens in code\n(?i)bearer\\s+[A-Za-z0-9\\-._~+/]+=*\n\n# Base64 encoded secrets (high entropy, 20+ chars)\n(?i)(secret|key|token|password)\\s*[=:]\\s*['\"][A-Za-z0-9+/]{20,}={0,2}['\"]\n\n# Hex-encoded secrets (32+ chars)\n(?i)(secret|key|token)\\s*[=:]\\s*['\"][0-9a-fA-F]{32,}['\"]\n```\n\n## Files to Always Check\n\n**High priority** (most likely to contain secrets):\n```\n.env, .env.*, .env.local, .env.production\nconfig.json, config.yaml, config.yml, config.toml\nsettings.py, settings.json\napplication.properties, application.yml\ndocker-compose.yml, docker-compose.*.yml\n.aws/credentials, .boto\n.netrc, .npmrc, .pypirc\nid_rsa, id_ecdsa, id_ed25519, *.pem, *.key\n```\n\n**Check .gitignore coverage**: Ensure these files are listed in `.gitignore`. If they are tracked by git, flag as a finding.\n\n**Git history**: Secrets may have been committed and later removed. Check with:\n```bash\ngit log --all --diff-filter=D -- \"*.env\" \"*.pem\" \"*.key\"\ngit log --all -p -S \"AKIA\" -- . # Search for AWS keys in history\n```\n\n## False Positive Reduction\n\nSkip matches that are likely not real secrets:\n- Values containing only placeholder text: `example`, `changeme`, `TODO`, `xxx`, `your_`, `placeholder`, `dummy`, `test`, `sample`\n- Values from documentation or comments on the same line as `example`, `e.g.`, `doc`, `TODO`\n- Values in test files matching `*_test.*`, `test_*.*`, `*.spec.*`, `**/test/**`, `**/tests/**`, `**/__tests__/**`\n- Environment variable references: `${VAR}`, `$VAR`, `%VAR%`, `os.environ`, `process.env`\n- Empty or whitespace-only values\n","resources/example-skills/skill-security-auditor/references/vulnerability-patterns.md":"# Vulnerability Patterns Reference\n\nDetailed patterns for identifying security vulnerabilities across languages and frameworks.\n\n## Table of Contents\n\n- [Injection Vulnerabilities](#injection-vulnerabilities)\n- [Authentication and Session Issues](#authentication-and-session-issues)\n- [Cryptographic Weaknesses](#cryptographic-weaknesses)\n- [Insecure Deserialization](#insecure-deserialization)\n- [Server-Side Request Forgery](#server-side-request-forgery)\n- [File Operations](#file-operations)\n- [Framework-Specific Patterns](#framework-specific-patterns)\n\n## Injection Vulnerabilities\n\n### SQL Injection\n\n**Vulnerable patterns** (string concatenation or f-strings in queries):\n```\n# Python\nexecute(f\"...{var}...\")\nexecute(\"...\" + var + \"...\")\nexecute(\"...%s...\" % var)\n\n# JavaScript\nquery(`...${var}...`)\nquery(\"...\" + var + \"...\")\n\n# Go\ndb.Query(\"...\" + var + \"...\")\nfmt.Sprintf(\"SELECT ... %s\", var) passed to Query()\n\n# Java\nstatement.execute(\"...\" + var + \"...\")\n```\n\n**Safe alternatives**: Parameterized queries, prepared statements, ORM query builders.\n\n### NoSQL Injection\n\n**Vulnerable patterns**:\n```javascript\n// MongoDB: user input directly in query object\ndb.collection.find({ user: req.body.user, pass: req.body.pass })\n// Attacker sends: { \"pass\": { \"$gt\": \"\" } }\n```\n\n**Safe alternative**: Validate input types, use `$eq` explicitly, sanitize with libraries like `mongo-sanitize`.\n\n### Command Injection\n\n**Vulnerable functions by language**:\n```\nPython:  os.system(), os.popen(), subprocess.call(shell=True), subprocess.Popen(shell=True)\nNode.js: child_process.exec(), child_process.execSync()\nGo:      exec.Command(\"sh\", \"-c\", userInput)\nJava:    Runtime.exec(userInput)\nPHP:     exec(), system(), passthru(), shell_exec(), backticks\nRuby:    system(), exec(), backticks, %x{}\n```\n\n**Safe alternative**: Use subprocess with list arguments (no shell), validate and allowlist input values.\n\n### LDAP Injection\n\n**Vulnerable pattern**:\n```python\nldap.search_s(base, scope, f\"(uid={username})\")\n```\n\n**Safe alternative**: Escape special characters `()*\\` and null bytes in user input.\n\n### XSS (Cross-Site Scripting)\n\n**Vulnerable sinks**:\n```\nJavaScript: innerHTML, outerHTML, document.write(), eval(), v-html, dangerouslySetInnerHTML\nTemplate:   |safe, {% autoescape off %}, !=, !{}, {!! !!}\n```\n\n**Safe alternatives**: Use `textContent`, template auto-escaping, CSP headers, DOMPurify for required HTML.\n\n## Authentication and Session Issues\n\n### Weak Password Storage\n\n**Vulnerable**:\n```python\n# Plaintext or weak hashing\nhashlib.md5(password.encode()).hexdigest()\nhashlib.sha256(password.encode()).hexdigest()\n```\n\n**Safe**:\n```python\n# Use adaptive hashing with salt\nimport bcrypt\nhashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))\n```\n\n### JWT Vulnerabilities\n\n**Common issues**:\n- Accepting `alg: \"none\"`\n- Using symmetric algorithms (HS256) with public keys\n- Not validating expiry (`exp`) or issuer (`iss`)\n- Storing sensitive data in payload (JWT is base64, not encrypted)\n\n**Verification checklist**:\n```python\n# Ensure algorithm is explicitly specified\njwt.decode(token, key, algorithms=[\"RS256\"])  # explicit algorithm\njwt.decode(token, key)  # VULNERABLE: accepts any algorithm\n```\n\n### Session Management\n\n**Issues to flag**:\n- Session IDs in URLs\n- Missing `HttpOnly`, `Secure`, `SameSite` flags on session cookies\n- No session timeout or rotation after authentication\n- Predictable session identifiers\n\n## Cryptographic Weaknesses\n\n### Insecure Algorithms\n\n**Deprecated/broken** (flag if found):\n```\nHash:    MD5, SHA1 (for security purposes)\nCipher:  DES, 3DES, RC4, Blowfish\nMode:    ECB mode for any block cipher\nRSA:     Key size < 2048 bits\n```\n\n**Acceptable**:\n```\nHash:    SHA-256, SHA-384, SHA-512, BLAKE2\nCipher:  AES-128/256-GCM, ChaCha20-Poly1305\nRSA:     2048+ bits with OAEP padding\nECDSA:   P-256 or P-384 curves\n```\n\n### Hardcoded Cryptographic Material\n\n**Flag if found in source**:\n- Encryption keys, IV/nonce values\n- Private keys (RSA, ECDSA, Ed25519)\n- Salt values for password hashing\n\n## Insecure Deserialization\n\n**Vulnerable functions by language**:\n```\nPython:  pickle.loads(), yaml.load() (without SafeLoader), marshal.loads()\nJava:    ObjectInputStream.readObject(), XMLDecoder\nPHP:     unserialize()\nRuby:    Marshal.load(), YAML.load()\nNode.js: node-serialize, js-yaml.load() (with dangerous schema)\n```\n\n**Safe alternatives**: Use JSON for data exchange, use safe loaders (`yaml.safe_load()`), validate and type-check deserialized data.\n\n## Server-Side Request Forgery\n\n**Vulnerable pattern**:\n```python\n# User controls the URL\nrequests.get(user_provided_url)\nurllib.request.urlopen(user_provided_url)\n```\n\n**Mitigations**:\n- Validate URLs against an allowlist of domains/IPs\n- Block requests to internal/private IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, 169.254.x)\n- Disable redirects or validate redirect targets\n- Use a network-level firewall for outbound requests\n\n## File Operations\n\n### Path Traversal\n\n**Vulnerable pattern**:\n```python\n# User controls filename\nopen(os.path.join(base_dir, user_filename))\n```\n\n**Safe pattern**:\n```python\nimport pathlib\nbase = pathlib.Path(base_dir).resolve()\ntarget = (base / user_filename).resolve()\nif not str(target).startswith(str(base)):\n    raise ValueError(\"Path traversal detected\")\n```\n\n### Unrestricted File Upload\n\n**Checklist**:\n- Validate file type by content (magic bytes), not just extension\n- Enforce maximum file size limits\n- Store uploads outside the web root\n- Generate random filenames, do not use user-supplied names\n- Scan uploads for malware when possible\n\n## Framework-Specific Patterns\n\n### Django\n\n```python\n# Dangerous: raw SQL\nModel.objects.raw(f\"SELECT * FROM t WHERE id = {user_id}\")\n# Safe: ORM or parameterized raw\nModel.objects.filter(id=user_id)\nModel.objects.raw(\"SELECT * FROM t WHERE id = %s\", [user_id])\n\n# Check settings.py\nDEBUG = True                      # Must be False in production\nALLOWED_HOSTS = ['*']            # Must be restricted\nCSRF_COOKIE_SECURE = False       # Must be True with HTTPS\nSESSION_COOKIE_SECURE = False    # Must be True with HTTPS\n```\n\n### Flask\n\n```python\n# Dangerous: XSS via Markup\nfrom markupsafe import Markup\nreturn Markup(f\"<p>{user_input}</p>\")\n# Safe: Use templates with auto-escaping\nreturn render_template(\"page.html\", data=user_input)\n\n# Check for debug mode\napp.run(debug=True)  # Must be False in production\n```\n\n### Express.js\n\n```javascript\n// Missing security headers - use helmet\nconst helmet = require('helmet');\napp.use(helmet());\n\n// Missing CSRF protection on state-changing routes\n// Missing rate limiting on auth endpoints\n// Missing input validation (use express-validator or zod)\n```\n\n### Spring Boot\n\n```java\n// Dangerous: SpEL injection\nparser.parseExpression(userInput).getValue();\n\n// Check application.properties\nserver.error.include-stacktrace=always  // Leaks internals\nmanagement.endpoints.web.exposure.include=*  // Exposes actuator\n```\n"},"files":{"resources/example-skills/pptx/SKILL.md":"---\nname: pptx\ndescription: \"Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates, layouts, speaker notes, or comments. Trigger whenever the user mentions \\\"deck,\\\" \\\"slides,\\\" \\\"presentation,\\\" or references a .pptx filename, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# PPTX Skill\n\n## Quick Reference\n\n| Task | Guide |\n|------|-------|\n| Read/analyze content | `python -m markitdown presentation.pptx` |\n| Edit or create from template | Read [editing.md](editing.md) |\n| Create from scratch | Read [pptxgenjs.md](pptxgenjs.md) |\n\n---\n\n## Reading Content\n\n```bash\n# Text extraction\npython -m markitdown presentation.pptx\n\n# Visual overview\npython scripts/thumbnail.py presentation.pptx\n\n# Raw XML\npython scripts/office/unpack.py presentation.pptx unpacked/\n```\n\n---\n\n## Editing Workflow\n\n**Read [editing.md](editing.md) for full details.**\n\n1. Analyze template with `thumbnail.py`\n2. Unpack → manipulate slides → edit content → clean → pack\n\n---\n\n## Creating from Scratch\n\n**Read [pptxgenjs.md](pptxgenjs.md) for full details.**\n\nUse when no template or reference presentation is available.\n\n---\n\n## Design Ideas\n\n**Don't create boring slides.** Plain bullets on a white background won't impress anyone. Consider ideas from this list for each slide.\n\n### Before Starting\n\n- **Pick a bold, content-informed color palette**: The palette should feel designed for THIS topic. If swapping your colors into a completely different presentation would still \"work,\" you haven't made specific enough choices.\n- **Dominance over equality**: One color should dominate (60-70% visual weight), with 1-2 supporting tones and one sharp accent. Never give all colors equal weight.\n- **Dark/light contrast**: Dark backgrounds for title + conclusion slides, light for content (\"sandwich\" structure). Or commit to dark throughout for a premium feel.\n- **Commit to a visual motif**: Pick ONE distinctive element and repeat it — rounded image frames, icons in colored circles, thick single-side borders. Carry it across every slide.\n\n### Color Palettes\n\nChoose colors that match your topic — don't default to generic blue. Use these palettes as inspiration:\n\n| Theme | Primary | Secondary | Accent |\n|-------|---------|-----------|--------|\n| **Midnight Executive** | `1E2761` (navy) | `CADCFC` (ice blue) | `FFFFFF` (white) |\n| **Forest & Moss** | `2C5F2D` (forest) | `97BC62` (moss) | `F5F5F5` (cream) |\n| **Coral Energy** | `F96167` (coral) | `F9E795` (gold) | `2F3C7E` (navy) |\n| **Warm Terracotta** | `B85042` (terracotta) | `E7E8D1` (sand) | `A7BEAE` (sage) |\n| **Ocean Gradient** | `065A82` (deep blue) | `1C7293` (teal) | `21295C` (midnight) |\n| **Charcoal Minimal** | `36454F` (charcoal) | `F2F2F2` (off-white) | `212121` (black) |\n| **Teal Trust** | `028090` (teal) | `00A896` (seafoam) | `02C39A` (mint) |\n| **Berry & Cream** | `6D2E46` (berry) | `A26769` (dusty rose) | `ECE2D0` (cream) |\n| **Sage Calm** | `84B59F` (sage) | `69A297` (eucalyptus) | `50808E` (slate) |\n| **Cherry Bold** | `990011` (cherry) | `FCF6F5` (off-white) | `2F3C7E` (navy) |\n\n### For Each Slide\n\n**Every slide needs a visual element** — image, chart, icon, or shape. Text-only slides are forgettable.\n\n**Layout options:**\n- Two-column (text left, illustration on right)\n- Icon + text rows (icon in colored circle, bold header, description below)\n- 2x2 or 2x3 grid (image on one side, grid of content blocks on other)\n- Half-bleed image (full left or right side) with content overlay\n\n**Data display:**\n- Large stat callouts (big numbers 60-72pt with small labels below)\n- Comparison columns (before/after, pros/cons, side-by-side options)\n- Timeline or process flow (numbered steps, arrows)\n\n**Visual polish:**\n- Icons in small colored circles next to section headers\n- Italic accent text for key stats or taglines\n\n### Typography\n\n**Choose an interesting font pairing** — don't default to Arial. Pick a header font with personality and pair it with a clean body font.\n\n| Header Font | Body Font |\n|-------------|-----------|\n| Georgia | Calibri |\n| Arial Black | Arial |\n| Calibri | Calibri Light |\n| Cambria | Calibri |\n| Trebuchet MS | Calibri |\n| Impact | Arial |\n| Palatino | Garamond |\n| Consolas | Calibri |\n\n| Element | Size |\n|---------|------|\n| Slide title | 36-44pt bold |\n| Section header | 20-24pt bold |\n| Body text | 14-16pt |\n| Captions | 10-12pt muted |\n\n### Spacing\n\n- 0.5\" minimum margins\n- 0.3-0.5\" between content blocks\n- Leave breathing room—don't fill every inch\n\n### Avoid (Common Mistakes)\n\n- **Don't repeat the same layout** — vary columns, cards, and callouts across slides\n- **Don't center body text** — left-align paragraphs and lists; center only titles\n- **Don't skimp on size contrast** — titles need 36pt+ to stand out from 14-16pt body\n- **Don't default to blue** — pick colors that reflect the specific topic\n- **Don't mix spacing randomly** — choose 0.3\" or 0.5\" gaps and use consistently\n- **Don't style one slide and leave the rest plain** — commit fully or keep it simple throughout\n- **Don't create text-only slides** — add images, icons, charts, or visual elements; avoid plain title + bullets\n- **Don't forget text box padding** — when aligning lines or shapes with text edges, set `margin: 0` on the text box or offset the shape to account for padding\n- **Don't use low-contrast elements** — icons AND text need strong contrast against the background; avoid light text on light backgrounds or dark text on dark backgrounds\n- **NEVER use accent lines under titles** — these are a hallmark of AI-generated slides; use whitespace or background color instead\n\n---\n\n## QA (Required)\n\n**Assume there are problems. Your job is to find them.**\n\nYour first render is almost never correct. Approach QA as a bug hunt, not a confirmation step. If you found zero issues on first inspection, you weren't looking hard enough.\n\n### Content QA\n\n```bash\npython -m markitdown output.pptx\n```\n\nCheck for missing content, typos, wrong order.\n\n**When using templates, check for leftover placeholder text:**\n\n```bash\npython -m markitdown output.pptx | grep -iE \"xxxx|lorem|ipsum|this.*(page|slide).*layout\"\n```\n\nIf grep returns results, fix them before declaring success.\n\n### Visual QA\n\n### Verification Loop\n\n1. Generate slides → Convert to images → Inspect\n2. **List issues found** (if none found, look again more critically)\n3. Fix issues\n4. **Re-verify affected slides** — one fix often creates another problem\n5. Repeat until a full pass reveals no new issues\n\n**Do not declare success until you've completed at least one fix-and-verify cycle.**\n\n---\n\n## Converting to Images\n\nConvert presentations to individual slide images for visual inspection:\n\n```bash\npython scripts/office/soffice.py --headless --convert-to pdf output.pptx\npdftoppm -jpeg -r 150 output.pdf slide\n```\n\nThis creates `slide-01.jpg`, `slide-02.jpg`, etc.\n\nTo re-render specific slides after fixes:\n\n```bash\npdftoppm -jpeg -r 150 -f N -l N output.pdf slide-fixed\n```\n\n---\n\n## Dependencies\n\n- `pip install \"markitdown[pptx]\"` - text extraction\n- `pip install Pillow` - thumbnail grids\n- `npm install -g pptxgenjs` - creating from scratch\n- LibreOffice (`soffice`) - PDF conversion (auto-configured for sandboxed environments via `scripts/office/soffice.py`)\n- Poppler (`pdftoppm`) - PDF to images\n","resources/example-skills/skill-creator/references/output-patterns.md":"# Output Patterns\n\nUse these patterns when skills need to produce consistent, high-quality output.\n\n## Template Pattern\n\nProvide templates for output format. Match the level of strictness to your needs.\n\n**For strict requirements (like API responses or data formats):**\n\n```markdown\n## Report structure\n\nALWAYS use this exact template structure:\n\n# [Analysis Title]\n\n## Executive summary\n[One-paragraph overview of key findings]\n\n## Key findings\n- Finding 1 with supporting data\n- Finding 2 with supporting data\n- Finding 3 with supporting data\n\n## Recommendations\n1. Specific actionable recommendation\n2. Specific actionable recommendation\n```\n\n**For flexible guidance (when adaptation is useful):**\n\n```markdown\n## Report structure\n\nHere is a sensible default format, but use your best judgment:\n\n# [Analysis Title]\n\n## Executive summary\n[Overview]\n\n## Key findings\n[Adapt sections based on what you discover]\n\n## Recommendations\n[Tailor to the specific context]\n\nAdjust sections as needed for the specific analysis type.\n```\n\n## Examples Pattern\n\nFor skills where output quality depends on seeing examples, provide input/output pairs:\n\n```markdown\n## Commit message format\n\nGenerate commit messages following these examples:\n\n**Example 1:**\nInput: Added user authentication with JWT tokens\nOutput:\n```\nfeat(auth): implement JWT-based authentication\n\nAdd login endpoint and token validation middleware\n```\n\n**Example 2:**\nInput: Fixed bug where dates displayed incorrectly in reports\nOutput:\n```\nfix(reports): correct date formatting in timezone conversion\n\nUse UTC timestamps consistently across report generation\n```\n\nFollow this style: type(scope): brief description, then detailed explanation.\n```\n\nExamples help the agent understand the desired style and level of detail more clearly than descriptions alone.\n","resources/example-skills/skill-security-auditor/SKILL.md":"---\nname: skill-security-auditor\ndescription: \"Security auditing for code, configs, and infrastructure. Use when the user wants to audit or improve security: scan for vulnerabilities (SQL injection, XSS, command injection, path traversal), detect hardcoded secrets and credentials, review auth and authorization, check dependencies for known CVEs, audit config files for insecure defaults, or generate security reports. Trigger on \\\"security audit\\\", \\\"vulnerability scan\\\", \\\"code review for security\\\", \\\"find secrets\\\", \\\"check for vulnerabilities\\\", \\\"OWASP\\\", \\\"CVE\\\", or questions about code security.\"\nlicense: Complete terms in LICENSE.txt\n---\n\n# Security Auditor Guide\n\n## Overview\n\nThis guide covers security auditing workflows for source code, dependencies, and configurations. For detailed vulnerability patterns and detection rules, see references/vulnerability-patterns.md. For secrets detection patterns, see references/secrets-patterns.md.\n\n## Quick Start\n\nRun the bundled scan script against a project directory:\n\n```bash\npython scripts/scan_project.py /path/to/project\n```\n\nThis performs a lightweight scan for common issues: hardcoded secrets, dangerous function calls, and insecure patterns. For deeper analysis, follow the workflows below.\n\n### Testing the scripts\n\n```bash\npython scripts/scan_project.py /path/to/some/project --format text\npython scripts/scan_secrets.py /path/to/some/project --format text\n```\n\n## Audit Workflow\n\n### 1. Reconnaissance\n\nBefore auditing, understand the project:\n\n```bash\n# Identify languages, frameworks, and entry points\nfind . -type f -name \"*.py\" -o -name \"*.js\" -o -name \"*.ts\" -o -name \"*.go\" -o -name \"*.java\" | head -20\ncat package.json pyproject.toml requirements.txt go.mod pom.xml 2>/dev/null\n```\n\nKey questions:\n- What frameworks are used? (Express, Django, Flask, Spring, etc.)\n- Where are the entry points? (routes, controllers, API handlers)\n- How is authentication handled?\n- What external services are called?\n- Is user input accepted? Where?\n\n### 2. Secrets Detection\n\nScan for hardcoded credentials, API keys, and tokens. See references/secrets-patterns.md for the full pattern list.\n\n```bash\npython scripts/scan_secrets.py /path/to/project\n```\n\nCommon patterns to check:\n- API keys and tokens in source files\n- Database connection strings with embedded passwords\n- Private keys or certificates committed to the repo\n- `.env` files or config files with plaintext secrets\n- Secrets in CI/CD configuration files\n\n### 3. Vulnerability Scanning\n\n#### OWASP Top 10 Checklist\n\n| # | Category | What to Look For |\n|---|----------|-----------------|\n| A01 | Broken Access Control | Missing auth checks, IDOR, privilege escalation |\n| A02 | Cryptographic Failures | Weak algorithms, plaintext storage, missing TLS |\n| A03 | Injection | SQL, NoSQL, OS command, LDAP, XSS |\n| A04 | Insecure Design | Missing rate limits, business logic flaws |\n| A05 | Security Misconfiguration | Debug mode, default credentials, verbose errors |\n| A06 | Vulnerable Components | Outdated dependencies with known CVEs |\n| A07 | Auth Failures | Weak passwords, missing MFA, session issues |\n| A08 | Data Integrity Failures | Insecure deserialization, unsigned updates |\n| A09 | Logging Failures | Missing audit logs, sensitive data in logs |\n| A10 | SSRF | Unvalidated URLs in server-side requests |\n\n#### Language-Specific Checks\n\n**Python**\n```python\n# Dangerous: SQL injection\ncursor.execute(f\"SELECT * FROM users WHERE id = {user_id}\")\n# Safe: Parameterized query\ncursor.execute(\"SELECT * FROM users WHERE id = %s\", (user_id,))\n\n# Dangerous: Command injection\nos.system(f\"ping {hostname}\")\n# Safe: Use subprocess with list args\nsubprocess.run([\"ping\", hostname], capture_output=True)\n\n# Dangerous: Path traversal\nopen(f\"/data/{user_input}\")\n# Safe: Validate and resolve path\npath = pathlib.Path(\"/data\") / user_input\npath.resolve().relative_to(pathlib.Path(\"/data\").resolve())\n```\n\n**JavaScript/TypeScript**\n```javascript\n// Dangerous: XSS via innerHTML\nelement.innerHTML = userInput;\n// Safe: Use textContent or sanitize\nelement.textContent = userInput;\n\n// Dangerous: Prototype pollution\nObject.assign(target, JSON.parse(userInput));\n// Safe: Validate input structure\nconst parsed = JSON.parse(userInput);\nif (typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error();\nconst sanitized = Object.fromEntries(\n  Object.entries(parsed).filter(([k]) => !k.startsWith('__'))\n);\n\n// Dangerous: eval or Function constructor\neval(userInput);\n// Safe: Never use eval with user input\n```\n\n**Go**\n```go\n// Dangerous: SQL injection\ndb.Query(\"SELECT * FROM users WHERE id = \" + id)\n// Safe: Parameterized query\ndb.Query(\"SELECT * FROM users WHERE id = $1\", id)\n\n// Dangerous: Path traversal\nhttp.ServeFile(w, r, filepath.Join(baseDir, r.URL.Path))\n// Safe: Clean and validate path\ncleaned := filepath.Clean(r.URL.Path)\nfull := filepath.Join(baseDir, cleaned)\nif !strings.HasPrefix(full, baseDir) { http.Error(...) }\n```\n\n### 4. Dependency Audit\n\nCheck for known vulnerabilities in project dependencies:\n\n```bash\n# Python\npip audit\nsafety check -r requirements.txt\n\n# Node.js\nnpm audit\nnpx auditjs ossi\n\n# Go\ngovulncheck ./...\n\n# General (if Trivy is available)\ntrivy fs --scanners vuln /path/to/project\n```\n\nReview the output and categorize by severity (critical, high, medium, low). Critical and high severity findings should be addressed before deployment.\n\n### 5. Configuration Review\n\nCheck for insecure defaults in configuration files:\n\n```yaml\n# Common misconfigurations to flag:\nDEBUG: true                    # Debug mode in production\nALLOWED_HOSTS: [\"*\"]          # Unrestricted host access\nCORS_ALLOW_ALL_ORIGINS: true  # Open CORS policy\nSECRET_KEY: \"default\"         # Default or weak secret key\nSSL_VERIFY: false             # Disabled TLS verification\n```\n\nCheck infrastructure configs:\n- Dockerfiles: Running as root, exposing unnecessary ports\n- CI/CD: Secrets in plaintext, overly permissive permissions\n- Cloud configs: Public S3 buckets, open security groups\n\n### 6. Authentication and Authorization Review\n\nKey areas to verify:\n- Password hashing uses strong algorithms (bcrypt, argon2, scrypt)\n- Sessions have appropriate timeouts and rotation\n- JWT tokens are validated properly (algorithm, expiry, signature)\n- API endpoints enforce authorization checks\n- Role-based access control is consistently applied\n- Rate limiting is in place for login and sensitive endpoints\n\n## Report Format\n\nWhen generating a security audit report, use this structure:\n\n```markdown\n# Security Audit Report\n\n## Summary\n- **Project**: [name]\n- **Date**: [date]\n- **Scope**: [what was audited]\n- **Risk Level**: [Critical/High/Medium/Low]\n\n## Findings\n\n### [SEVERITY] Finding Title\n- **Category**: [OWASP category]\n- **Location**: [file:line]\n- **Description**: [what the issue is]\n- **Impact**: [what could happen if exploited]\n- **Recommendation**: [how to fix]\n\n## Statistics\n- Total findings: [count]\n- Critical: [count] | High: [count] | Medium: [count] | Low: [count]\n```\n\n## Next Steps\n\n- For detailed vulnerability patterns and code examples, see references/vulnerability-patterns.md\n- For secrets detection regex patterns, see references/secrets-patterns.md\n","resources/example-skills/pdf/SKILL.md":"---\nname: pdf\ndescription: Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill.\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# PDF Processing Guide\n\n## Overview\n\nThis guide covers essential PDF processing operations using Python libraries and command-line tools. For advanced features, JavaScript libraries, and detailed examples, see REFERENCE.md. If you need to fill out a PDF form, read FORMS.md and follow its instructions.\n\n## Quick Start\n\n```python\nfrom pypdf import PdfReader, PdfWriter\n\n# Read a PDF\nreader = PdfReader(\"document.pdf\")\nprint(f\"Pages: {len(reader.pages)}\")\n\n# Extract text\ntext = \"\"\nfor page in reader.pages:\n    text += page.extract_text()\n```\n\n## Python Libraries\n\n### pypdf - Basic Operations\n\n#### Merge PDFs\n```python\nfrom pypdf import PdfWriter, PdfReader\n\nwriter = PdfWriter()\nfor pdf_file in [\"doc1.pdf\", \"doc2.pdf\", \"doc3.pdf\"]:\n    reader = PdfReader(pdf_file)\n    for page in reader.pages:\n        writer.add_page(page)\n\nwith open(\"merged.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n#### Split PDF\n```python\nreader = PdfReader(\"input.pdf\")\nfor i, page in enumerate(reader.pages):\n    writer = PdfWriter()\n    writer.add_page(page)\n    with open(f\"page_{i+1}.pdf\", \"wb\") as output:\n        writer.write(output)\n```\n\n#### Extract Metadata\n```python\nreader = PdfReader(\"document.pdf\")\nmeta = reader.metadata\nprint(f\"Title: {meta.title}\")\nprint(f\"Author: {meta.author}\")\nprint(f\"Subject: {meta.subject}\")\nprint(f\"Creator: {meta.creator}\")\n```\n\n#### Rotate Pages\n```python\nreader = PdfReader(\"input.pdf\")\nwriter = PdfWriter()\n\npage = reader.pages[0]\npage.rotate(90)  # Rotate 90 degrees clockwise\nwriter.add_page(page)\n\nwith open(\"rotated.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n### pdfplumber - Text and Table Extraction\n\n#### Extract Text with Layout\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    for page in pdf.pages:\n        text = page.extract_text()\n        print(text)\n```\n\n#### Extract Tables\n```python\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    for i, page in enumerate(pdf.pages):\n        tables = page.extract_tables()\n        for j, table in enumerate(tables):\n            print(f\"Table {j+1} on page {i+1}:\")\n            for row in table:\n                print(row)\n```\n\n#### Advanced Table Extraction\n```python\nimport pandas as pd\n\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    all_tables = []\n    for page in pdf.pages:\n        tables = page.extract_tables()\n        for table in tables:\n            if table:  # Check if table is not empty\n                df = pd.DataFrame(table[1:], columns=table[0])\n                all_tables.append(df)\n\n# Combine all tables\nif all_tables:\n    combined_df = pd.concat(all_tables, ignore_index=True)\n    combined_df.to_excel(\"extracted_tables.xlsx\", index=False)\n```\n\n### reportlab - Create PDFs\n\n#### Basic PDF Creation\n```python\nfrom reportlab.lib.pagesizes import letter\nfrom reportlab.pdfgen import canvas\n\nc = canvas.Canvas(\"hello.pdf\", pagesize=letter)\nwidth, height = letter\n\n# Add text\nc.drawString(100, height - 100, \"Hello World!\")\nc.drawString(100, height - 120, \"This is a PDF created with reportlab\")\n\n# Add a line\nc.line(100, height - 140, 400, height - 140)\n\n# Save\nc.save()\n```\n\n#### Create PDF with Multiple Pages\n```python\nfrom reportlab.lib.pagesizes import letter\nfrom reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak\nfrom reportlab.lib.styles import getSampleStyleSheet\n\ndoc = SimpleDocTemplate(\"report.pdf\", pagesize=letter)\nstyles = getSampleStyleSheet()\nstory = []\n\n# Add content\ntitle = Paragraph(\"Report Title\", styles['Title'])\nstory.append(title)\nstory.append(Spacer(1, 12))\n\nbody = Paragraph(\"This is the body of the report. \" * 20, styles['Normal'])\nstory.append(body)\nstory.append(PageBreak())\n\n# Page 2\nstory.append(Paragraph(\"Page 2\", styles['Heading1']))\nstory.append(Paragraph(\"Content for page 2\", styles['Normal']))\n\n# Build PDF\ndoc.build(story)\n```\n\n#### Subscripts and Superscripts\n\n**IMPORTANT**: Never use Unicode subscript/superscript characters (₀₁₂₃₄₅₆₇₈₉, ⁰¹²³⁴⁵⁶⁷⁸⁹) in ReportLab PDFs. The built-in fonts do not include these glyphs, causing them to render as solid black boxes.\n\nInstead, use ReportLab's XML markup tags in Paragraph objects:\n```python\nfrom reportlab.platypus import Paragraph\nfrom reportlab.lib.styles import getSampleStyleSheet\n\nstyles = getSampleStyleSheet()\n\n# Subscripts: use <sub> tag\nchemical = Paragraph(\"H<sub>2</sub>O\", styles['Normal'])\n\n# Superscripts: use <super> tag\nsquared = Paragraph(\"x<super>2</super> + y<super>2</super>\", styles['Normal'])\n```\n\nFor canvas-drawn text (not Paragraph objects), manually adjust font the size and position rather than using Unicode subscripts/superscripts.\n\n## Command-Line Tools\n\n### pdftotext (poppler-utils)\n```bash\n# Extract text\npdftotext input.pdf output.txt\n\n# Extract text preserving layout\npdftotext -layout input.pdf output.txt\n\n# Extract specific pages\npdftotext -f 1 -l 5 input.pdf output.txt  # Pages 1-5\n```\n\n### qpdf\n```bash\n# Merge PDFs\nqpdf --empty --pages file1.pdf file2.pdf -- merged.pdf\n\n# Split pages\nqpdf input.pdf --pages . 1-5 -- pages1-5.pdf\nqpdf input.pdf --pages . 6-10 -- pages6-10.pdf\n\n# Rotate pages\nqpdf input.pdf output.pdf --rotate=+90:1  # Rotate page 1 by 90 degrees\n\n# Remove password\nqpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf\n```\n\n### pdftk (if available)\n```bash\n# Merge\npdftk file1.pdf file2.pdf cat output merged.pdf\n\n# Split\npdftk input.pdf burst\n\n# Rotate\npdftk input.pdf rotate 1east output rotated.pdf\n```\n\n## Common Tasks\n\n### Extract Text from Scanned PDFs\n```python\n# Requires: pip install pytesseract pdf2image\nimport pytesseract\nfrom pdf2image import convert_from_path\n\n# Convert PDF to images\nimages = convert_from_path('scanned.pdf')\n\n# OCR each page\ntext = \"\"\nfor i, image in enumerate(images):\n    text += f\"Page {i+1}:\\n\"\n    text += pytesseract.image_to_string(image)\n    text += \"\\n\\n\"\n\nprint(text)\n```\n\n### Add Watermark\n```python\nfrom pypdf import PdfReader, PdfWriter\n\n# Create watermark (or load existing)\nwatermark = PdfReader(\"watermark.pdf\").pages[0]\n\n# Apply to all pages\nreader = PdfReader(\"document.pdf\")\nwriter = PdfWriter()\n\nfor page in reader.pages:\n    page.merge_page(watermark)\n    writer.add_page(page)\n\nwith open(\"watermarked.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n### Extract Images\n```bash\n# Using pdfimages (poppler-utils)\npdfimages -j input.pdf output_prefix\n\n# This extracts all images as output_prefix-000.jpg, output_prefix-001.jpg, etc.\n```\n\n### Password Protection\n```python\nfrom pypdf import PdfReader, PdfWriter\n\nreader = PdfReader(\"input.pdf\")\nwriter = PdfWriter()\n\nfor page in reader.pages:\n    writer.add_page(page)\n\n# Add password\nwriter.encrypt(\"userpassword\", \"ownerpassword\")\n\nwith open(\"encrypted.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n## Quick Reference\n\n| Task | Best Tool | Command/Code |\n|------|-----------|--------------|\n| Merge PDFs | pypdf | `writer.add_page(page)` |\n| Split PDFs | pypdf | One page per file |\n| Extract text | pdfplumber | `page.extract_text()` |\n| Extract tables | pdfplumber | `page.extract_tables()` |\n| Create PDFs | reportlab | Canvas or Platypus |\n| Command line merge | qpdf | `qpdf --empty --pages ...` |\n| OCR scanned PDFs | pytesseract | Convert to image first |\n| Fill PDF forms | pdf-lib or pypdf (see FORMS.md) | See FORMS.md |\n\n## Next Steps\n\n- For advanced pypdfium2 usage, see REFERENCE.md\n- For JavaScript libraries (pdf-lib), see REFERENCE.md\n- If you need to fill out a PDF form, follow the instructions in FORMS.md\n- For troubleshooting guides, see REFERENCE.md\n","resources/example-skills/xlsx/SKILL.md":"---\nname: xlsx\ndescription: \"Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like \\\"the xlsx in my downloads\\\") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# Requirements for Outputs\n\n## All Excel files\n\n### Professional Font\n- Use a consistent, professional font (e.g., Arial, Times New Roman) for all deliverables unless otherwise instructed by the user\n\n### Zero Formula Errors\n- Every Excel model MUST be delivered with ZERO formula errors (#REF!, #DIV/0!, #VALUE!, #N/A, #NAME?)\n\n### Preserve Existing Templates (when updating templates)\n- Study and EXACTLY match existing format, style, and conventions when modifying files\n- Never impose standardized formatting on files with established patterns\n- Existing template conventions ALWAYS override these guidelines\n\n## Financial models\n\n### Color Coding Standards\nUnless otherwise stated by the user or existing template\n\n#### Industry-Standard Color Conventions\n- **Blue text (RGB: 0,0,255)**: Hardcoded inputs, and numbers users will change for scenarios\n- **Black text (RGB: 0,0,0)**: ALL formulas and calculations\n- **Green text (RGB: 0,128,0)**: Links pulling from other worksheets within same workbook\n- **Red text (RGB: 255,0,0)**: External links to other files\n- **Yellow background (RGB: 255,255,0)**: Key assumptions needing attention or cells that need to be updated\n\n### Number Formatting Standards\n\n#### Required Format Rules\n- **Years**: Format as text strings (e.g., \"2024\" not \"2,024\")\n- **Currency**: Use $#,##0 format; ALWAYS specify units in headers (\"Revenue ($mm)\")\n- **Zeros**: Use number formatting to make all zeros \"-\", including percentages (e.g., \"$#,##0;($#,##0);-\")\n- **Percentages**: Default to 0.0% format (one decimal)\n- **Multiples**: Format as 0.0x for valuation multiples (EV/EBITDA, P/E)\n- **Negative numbers**: Use parentheses (123) not minus -123\n\n### Formula Construction Rules\n\n#### Assumptions Placement\n- Place ALL assumptions (growth rates, margins, multiples, etc.) in separate assumption cells\n- Use cell references instead of hardcoded values in formulas\n- Example: Use =B5*(1+$B$6) instead of =B5*1.05\n\n#### Formula Error Prevention\n- Verify all cell references are correct\n- Check for off-by-one errors in ranges\n- Ensure consistent formulas across all projection periods\n- Test with edge cases (zero values, negative numbers)\n- Verify no unintended circular references\n\n#### Documentation Requirements for Hardcodes\n- Comment or in cells beside (if end of table). Format: \"Source: [System/Document], [Date], [Specific Reference], [URL if applicable]\"\n- Examples:\n  - \"Source: Company 10-K, FY2024, Page 45, Revenue Note, [SEC EDGAR URL]\"\n  - \"Source: Company 10-Q, Q2 2025, Exhibit 99.1, [SEC EDGAR URL]\"\n  - \"Source: Bloomberg Terminal, 8/15/2025, AAPL US Equity\"\n  - \"Source: FactSet, 8/20/2025, Consensus Estimates Screen\"\n\n# XLSX creation, editing, and analysis\n\n## Overview\n\nA user may ask you to create, edit, or analyze the contents of an .xlsx file. You have different tools and workflows available for different tasks.\n\n## Important Requirements\n\n**LibreOffice Required for Formula Recalculation**: You can assume LibreOffice is installed for recalculating formula values using the `scripts/recalc.py` script. The script automatically configures LibreOffice on first run, including in sandboxed environments where Unix sockets are restricted (handled by `scripts/office/soffice.py`)\n\n## Reading and analyzing data\n\n### Data analysis with pandas\nFor data analysis, visualization, and basic operations, use **pandas** which provides powerful data manipulation capabilities:\n\n```python\nimport pandas as pd\n\n# Read Excel\ndf = pd.read_excel('file.xlsx')  # Default: first sheet\nall_sheets = pd.read_excel('file.xlsx', sheet_name=None)  # All sheets as dict\n\n# Analyze\ndf.head()      # Preview data\ndf.info()      # Column info\ndf.describe()  # Statistics\n\n# Write Excel\ndf.to_excel('output.xlsx', index=False)\n```\n\n## Excel File Workflows\n\n## CRITICAL: Use Formulas, Not Hardcoded Values\n\n**Always use Excel formulas instead of calculating values in Python and hardcoding them.** This ensures the spreadsheet remains dynamic and updateable.\n\n### ❌ WRONG - Hardcoding Calculated Values\n```python\n# Bad: Calculating in Python and hardcoding result\ntotal = df['Sales'].sum()\nsheet['B10'] = total  # Hardcodes 5000\n\n# Bad: Computing growth rate in Python\ngrowth = (df.iloc[-1]['Revenue'] - df.iloc[0]['Revenue']) / df.iloc[0]['Revenue']\nsheet['C5'] = growth  # Hardcodes 0.15\n\n# Bad: Python calculation for average\navg = sum(values) / len(values)\nsheet['D20'] = avg  # Hardcodes 42.5\n```\n\n### ✅ CORRECT - Using Excel Formulas\n```python\n# Good: Let Excel calculate the sum\nsheet['B10'] = '=SUM(B2:B9)'\n\n# Good: Growth rate as Excel formula\nsheet['C5'] = '=(C4-C2)/C2'\n\n# Good: Average using Excel function\nsheet['D20'] = '=AVERAGE(D2:D19)'\n```\n\nThis applies to ALL calculations - totals, percentages, ratios, differences, etc. The spreadsheet should be able to recalculate when source data changes.\n\n## Common Workflow\n1. **Choose tool**: pandas for data, openpyxl for formulas/formatting\n2. **Create/Load**: Create new workbook or load existing file\n3. **Modify**: Add/edit data, formulas, and formatting\n4. **Save**: Write to file\n5. **Recalculate formulas (MANDATORY IF USING FORMULAS)**: Use the scripts/recalc.py script\n   ```bash\n   python scripts/recalc.py output.xlsx\n   ```\n6. **Verify and fix any errors**: \n   - The script returns JSON with error details\n   - If `status` is `errors_found`, check `error_summary` for specific error types and locations\n   - Fix the identified errors and recalculate again\n   - Common errors to fix:\n     - `#REF!`: Invalid cell references\n     - `#DIV/0!`: Division by zero\n     - `#VALUE!`: Wrong data type in formula\n     - `#NAME?`: Unrecognized formula name\n\n### Creating new Excel files\n\n```python\n# Using openpyxl for formulas and formatting\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font, PatternFill, Alignment\n\nwb = Workbook()\nsheet = wb.active\n\n# Add data\nsheet['A1'] = 'Hello'\nsheet['B1'] = 'World'\nsheet.append(['Row', 'of', 'data'])\n\n# Add formula\nsheet['B2'] = '=SUM(A1:A10)'\n\n# Formatting\nsheet['A1'].font = Font(bold=True, color='FF0000')\nsheet['A1'].fill = PatternFill('solid', start_color='FFFF00')\nsheet['A1'].alignment = Alignment(horizontal='center')\n\n# Column width\nsheet.column_dimensions['A'].width = 20\n\nwb.save('output.xlsx')\n```\n\n### Editing existing Excel files\n\n```python\n# Using openpyxl to preserve formulas and formatting\nfrom openpyxl import load_workbook\n\n# Load existing file\nwb = load_workbook('existing.xlsx')\nsheet = wb.active  # or wb['SheetName'] for specific sheet\n\n# Working with multiple sheets\nfor sheet_name in wb.sheetnames:\n    sheet = wb[sheet_name]\n    print(f\"Sheet: {sheet_name}\")\n\n# Modify cells\nsheet['A1'] = 'New Value'\nsheet.insert_rows(2)  # Insert row at position 2\nsheet.delete_cols(3)  # Delete column 3\n\n# Add new sheet\nnew_sheet = wb.create_sheet('NewSheet')\nnew_sheet['A1'] = 'Data'\n\nwb.save('modified.xlsx')\n```\n\n## Recalculating formulas\n\nExcel files created or modified by openpyxl contain formulas as strings but not calculated values. Use the provided `scripts/recalc.py` script to recalculate formulas:\n\n```bash\npython scripts/recalc.py <excel_file> [timeout_seconds]\n```\n\nExample:\n```bash\npython scripts/recalc.py output.xlsx 30\n```\n\nThe script:\n- Automatically sets up LibreOffice macro on first run\n- Recalculates all formulas in all sheets\n- Scans ALL cells for Excel errors (#REF!, #DIV/0!, etc.)\n- Returns JSON with detailed error locations and counts\n- Works on both Linux and macOS\n\n## Formula Verification Checklist\n\nQuick checks to ensure formulas work correctly:\n\n### Essential Verification\n- [ ] **Test 2-3 sample references**: Verify they pull correct values before building full model\n- [ ] **Column mapping**: Confirm Excel columns match (e.g., column 64 = BL, not BK)\n- [ ] **Row offset**: Remember Excel rows are 1-indexed (DataFrame row 5 = Excel row 6)\n\n### Common Pitfalls\n- [ ] **NaN handling**: Check for null values with `pd.notna()`\n- [ ] **Far-right columns**: FY data often in columns 50+ \n- [ ] **Multiple matches**: Search all occurrences, not just first\n- [ ] **Division by zero**: Check denominators before using `/` in formulas (#DIV/0!)\n- [ ] **Wrong references**: Verify all cell references point to intended cells (#REF!)\n- [ ] **Cross-sheet references**: Use correct format (Sheet1!A1) for linking sheets\n\n### Formula Testing Strategy\n- [ ] **Start small**: Test formulas on 2-3 cells before applying broadly\n- [ ] **Verify dependencies**: Check all cells referenced in formulas exist\n- [ ] **Test edge cases**: Include zero, negative, and very large values\n\n### Interpreting scripts/recalc.py Output\nThe script returns JSON with error details:\n```json\n{\n  \"status\": \"success\",           // or \"errors_found\"\n  \"total_errors\": 0,              // Total error count\n  \"total_formulas\": 42,           // Number of formulas in file\n  \"error_summary\": {              // Only present if errors found\n    \"#REF!\": {\n      \"count\": 2,\n      \"locations\": [\"Sheet1!B5\", \"Sheet1!C10\"]\n    }\n  }\n}\n```\n\n## Best Practices\n\n### Library Selection\n- **pandas**: Best for data analysis, bulk operations, and simple data export\n- **openpyxl**: Best for complex formatting, formulas, and Excel-specific features\n\n### Working with openpyxl\n- Cell indices are 1-based (row=1, column=1 refers to cell A1)\n- Use `data_only=True` to read calculated values: `load_workbook('file.xlsx', data_only=True)`\n- **Warning**: If opened with `data_only=True` and saved, formulas are replaced with values and permanently lost\n- For large files: Use `read_only=True` for reading or `write_only=True` for writing\n- Formulas are preserved but not evaluated - use scripts/recalc.py to update values\n\n### Working with pandas\n- Specify data types to avoid inference issues: `pd.read_excel('file.xlsx', dtype={'id': str})`\n- For large files, read specific columns: `pd.read_excel('file.xlsx', usecols=['A', 'C', 'E'])`\n- Handle dates properly: `pd.read_excel('file.xlsx', parse_dates=['date_column'])`\n\n## Code Style Guidelines\n**IMPORTANT**: When generating Python code for Excel operations:\n- Write minimal, concise Python code without unnecessary comments\n- Avoid verbose variable names and redundant operations\n- Avoid unnecessary print statements\n\n**For Excel files themselves**:\n- Add comments to cells with complex formulas or important assumptions\n- Document data sources for hardcoded values\n- Include notes for key calculations and model sections","resources/example-skills/docx/SKILL.md":"---\nname: docx\ndescription: \"Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files). Triggers include: any mention of \\\"Word doc\\\", \\\"word document\\\", \\\".docx\\\", or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a \\\"report\\\", \\\"memo\\\", \\\"letter\\\", \\\"template\\\", or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# DOCX creation, editing, and analysis\n\n## Overview\n\nA .docx file is a ZIP archive containing XML files.\n\n## Quick Reference\n\n| Task | Approach |\n|------|----------|\n| Read/analyze content | `pandoc` or unpack for raw XML |\n| Create new document | Use `docx-js` - see Creating New Documents below |\n| Edit existing document | Unpack → edit XML → repack - see Editing Existing Documents below |\n\n### Converting .doc to .docx\n\nLegacy `.doc` files must be converted before editing:\n\n```bash\npython scripts/office/soffice.py --headless --convert-to docx document.doc\n```\n\n### Reading Content\n\n```bash\n# Text extraction with tracked changes\npandoc --track-changes=all document.docx -o output.md\n\n# Raw XML access\npython scripts/office/unpack.py document.docx unpacked/\n```\n\n### Converting to Images\n\n```bash\npython scripts/office/soffice.py --headless --convert-to pdf document.docx\npdftoppm -jpeg -r 150 document.pdf page\n```\n\n### Accepting Tracked Changes\n\nTo produce a clean document with all tracked changes accepted (requires LibreOffice):\n\n```bash\npython scripts/accept_changes.py input.docx output.docx\n```\n\n---\n\n## Creating New Documents\n\nGenerate .docx files with JavaScript, then validate. Install: `npm install -g docx`\n\n### Setup\n```javascript\nconst { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun,\n        Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink,\n        TableOfContents, HeadingLevel, BorderStyle, WidthType, ShadingType,\n        VerticalAlign, PageNumber, PageBreak } = require('docx');\n\nconst doc = new Document({ sections: [{ children: [/* content */] }] });\nPacker.toBuffer(doc).then(buffer => fs.writeFileSync(\"doc.docx\", buffer));\n```\n\n### Validation\nAfter creating the file, validate it. If validation fails, unpack, fix the XML, and repack.\n```bash\npython scripts/office/validate.py doc.docx\n```\n\n### Page Size\n\n```javascript\n// CRITICAL: docx-js defaults to A4, not US Letter\n// Always set page size explicitly for consistent results\nsections: [{\n  properties: {\n    page: {\n      size: {\n        width: 12240,   // 8.5 inches in DXA\n        height: 15840   // 11 inches in DXA\n      },\n      margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } // 1 inch margins\n    }\n  },\n  children: [/* content */]\n}]\n```\n\n**Common page sizes (DXA units, 1440 DXA = 1 inch):**\n\n| Paper | Width | Height | Content Width (1\" margins) |\n|-------|-------|--------|---------------------------|\n| US Letter | 12,240 | 15,840 | 9,360 |\n| A4 (default) | 11,906 | 16,838 | 9,026 |\n\n**Landscape orientation:** docx-js swaps width/height internally, so pass portrait dimensions and let it handle the swap:\n```javascript\nsize: {\n  width: 12240,   // Pass SHORT edge as width\n  height: 15840,  // Pass LONG edge as height\n  orientation: PageOrientation.LANDSCAPE  // docx-js swaps them in the XML\n},\n// Content width = 15840 - left margin - right margin (uses the long edge)\n```\n\n### Styles (Override Built-in Headings)\n\nUse Arial as the default font (universally supported). Keep titles black for readability.\n\n```javascript\nconst doc = new Document({\n  styles: {\n    default: { document: { run: { font: \"Arial\", size: 24 } } }, // 12pt default\n    paragraphStyles: [\n      // IMPORTANT: Use exact IDs to override built-in styles\n      { id: \"Heading1\", name: \"Heading 1\", basedOn: \"Normal\", next: \"Normal\", quickFormat: true,\n        run: { size: 32, bold: true, font: \"Arial\" },\n        paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } }, // outlineLevel required for TOC\n      { id: \"Heading2\", name: \"Heading 2\", basedOn: \"Normal\", next: \"Normal\", quickFormat: true,\n        run: { size: 28, bold: true, font: \"Arial\" },\n        paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 } },\n    ]\n  },\n  sections: [{\n    children: [\n      new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun(\"Title\")] }),\n    ]\n  }]\n});\n```\n\n### Lists (NEVER use unicode bullets)\n\n```javascript\n// ❌ WRONG - never manually insert bullet characters\nnew Paragraph({ children: [new TextRun(\"• Item\")] })  // BAD\nnew Paragraph({ children: [new TextRun(\"\\u2022 Item\")] })  // BAD\n\n// ✅ CORRECT - use numbering config with LevelFormat.BULLET\nconst doc = new Document({\n  numbering: {\n    config: [\n      { reference: \"bullets\",\n        levels: [{ level: 0, format: LevelFormat.BULLET, text: \"•\", alignment: AlignmentType.LEFT,\n          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },\n      { reference: \"numbers\",\n        levels: [{ level: 0, format: LevelFormat.DECIMAL, text: \"%1.\", alignment: AlignmentType.LEFT,\n          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },\n    ]\n  },\n  sections: [{\n    children: [\n      new Paragraph({ numbering: { reference: \"bullets\", level: 0 },\n        children: [new TextRun(\"Bullet item\")] }),\n      new Paragraph({ numbering: { reference: \"numbers\", level: 0 },\n        children: [new TextRun(\"Numbered item\")] }),\n    ]\n  }]\n});\n\n// ⚠️ Each reference creates INDEPENDENT numbering\n// Same reference = continues (1,2,3 then 4,5,6)\n// Different reference = restarts (1,2,3 then 1,2,3)\n```\n\n### Tables\n\n**CRITICAL: Tables need dual widths** - set both `columnWidths` on the table AND `width` on each cell. Without both, tables render incorrectly on some platforms.\n\n```javascript\n// CRITICAL: Always set table width for consistent rendering\n// CRITICAL: Use ShadingType.CLEAR (not SOLID) to prevent black backgrounds\nconst border = { style: BorderStyle.SINGLE, size: 1, color: \"CCCCCC\" };\nconst borders = { top: border, bottom: border, left: border, right: border };\n\nnew Table({\n  width: { size: 9360, type: WidthType.DXA }, // Always use DXA (percentages break in Google Docs)\n  columnWidths: [4680, 4680], // Must sum to table width (DXA: 1440 = 1 inch)\n  rows: [\n    new TableRow({\n      children: [\n        new TableCell({\n          borders,\n          width: { size: 4680, type: WidthType.DXA }, // Also set on each cell\n          shading: { fill: \"D5E8F0\", type: ShadingType.CLEAR }, // CLEAR not SOLID\n          margins: { top: 80, bottom: 80, left: 120, right: 120 }, // Cell padding (internal, not added to width)\n          children: [new Paragraph({ children: [new TextRun(\"Cell\")] })]\n        })\n      ]\n    })\n  ]\n})\n```\n\n**Table width calculation:**\n\nAlways use `WidthType.DXA` — `WidthType.PERCENTAGE` breaks in Google Docs.\n\n```javascript\n// Table width = sum of columnWidths = content width\n// US Letter with 1\" margins: 12240 - 2880 = 9360 DXA\nwidth: { size: 9360, type: WidthType.DXA },\ncolumnWidths: [7000, 2360]  // Must sum to table width\n```\n\n**Width rules:**\n- **Always use `WidthType.DXA`** — never `WidthType.PERCENTAGE` (incompatible with Google Docs)\n- Table width must equal the sum of `columnWidths`\n- Cell `width` must match corresponding `columnWidth`\n- Cell `margins` are internal padding - they reduce content area, not add to cell width\n- For full-width tables: use content width (page width minus left and right margins)\n\n### Images\n\n```javascript\n// CRITICAL: type parameter is REQUIRED\nnew Paragraph({\n  children: [new ImageRun({\n    type: \"png\", // Required: png, jpg, jpeg, gif, bmp, svg\n    data: fs.readFileSync(\"image.png\"),\n    transformation: { width: 200, height: 150 },\n    altText: { title: \"Title\", description: \"Desc\", name: \"Name\" } // All three required\n  })]\n})\n```\n\n### Page Breaks\n\n```javascript\n// CRITICAL: PageBreak must be inside a Paragraph\nnew Paragraph({ children: [new PageBreak()] })\n\n// Or use pageBreakBefore\nnew Paragraph({ pageBreakBefore: true, children: [new TextRun(\"New page\")] })\n```\n\n### Table of Contents\n\n```javascript\n// CRITICAL: Headings must use HeadingLevel ONLY - no custom styles\nnew TableOfContents(\"Table of Contents\", { hyperlink: true, headingStyleRange: \"1-3\" })\n```\n\n### Headers/Footers\n\n```javascript\nsections: [{\n  properties: {\n    page: { margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } } // 1440 = 1 inch\n  },\n  headers: {\n    default: new Header({ children: [new Paragraph({ children: [new TextRun(\"Header\")] })] })\n  },\n  footers: {\n    default: new Footer({ children: [new Paragraph({\n      children: [new TextRun(\"Page \"), new TextRun({ children: [PageNumber.CURRENT] })]\n    })] })\n  },\n  children: [/* content */]\n}]\n```\n\n### Critical Rules for docx-js\n\n- **Set page size explicitly** - docx-js defaults to A4; use US Letter (12240 x 15840 DXA) for US documents\n- **Landscape: pass portrait dimensions** - docx-js swaps width/height internally; pass short edge as `width`, long edge as `height`, and set `orientation: PageOrientation.LANDSCAPE`\n- **Never use `\\n`** - use separate Paragraph elements\n- **Never use unicode bullets** - use `LevelFormat.BULLET` with numbering config\n- **PageBreak must be in Paragraph** - standalone creates invalid XML\n- **ImageRun requires `type`** - always specify png/jpg/etc\n- **Always set table `width` with DXA** - never use `WidthType.PERCENTAGE` (breaks in Google Docs)\n- **Tables need dual widths** - `columnWidths` array AND cell `width`, both must match\n- **Table width = sum of columnWidths** - for DXA, ensure they add up exactly\n- **Always add cell margins** - use `margins: { top: 80, bottom: 80, left: 120, right: 120 }` for readable padding\n- **Use `ShadingType.CLEAR`** - never SOLID for table shading\n- **TOC requires HeadingLevel only** - no custom styles on heading paragraphs\n- **Override built-in styles** - use exact IDs: \"Heading1\", \"Heading2\", etc.\n- **Include `outlineLevel`** - required for TOC (0 for H1, 1 for H2, etc.)\n\n---\n\n## Editing Existing Documents\n\n**Follow all 3 steps in order.**\n\n### Step 1: Unpack\n```bash\npython scripts/office/unpack.py document.docx unpacked/\n```\nExtracts XML, pretty-prints, merges adjacent runs, and converts smart quotes to XML entities (`&#x201C;` etc.) so they survive editing. Use `--merge-runs false` to skip run merging.\n\n### Step 2: Edit XML\n\nEdit files in `unpacked/word/`. See XML Reference below for patterns.\n\n**Use \"Claude\" as the author** for tracked changes and comments, unless the user explicitly requests use of a different name.\n\n**Use the Edit tool directly for string replacement. Do not write Python scripts.** Scripts introduce unnecessary complexity. The Edit tool shows exactly what is being replaced.\n\n**CRITICAL: Use smart quotes for new content.** When adding text with apostrophes or quotes, use XML entities to produce smart quotes:\n```xml\n<!-- Use these entities for professional typography -->\n<w:t>Here&#x2019;s a quote: &#x201C;Hello&#x201D;</w:t>\n```\n| Entity | Character |\n|--------|-----------|\n| `&#x2018;` | ‘ (left single) |\n| `&#x2019;` | ’ (right single / apostrophe) |\n| `&#x201C;` | “ (left double) |\n| `&#x201D;` | ” (right double) |\n\n**Adding comments:** Use `comment.py` to handle boilerplate across multiple XML files (text must be pre-escaped XML):\n```bash\npython scripts/comment.py unpacked/ 0 \"Comment text with &amp; and &#x2019;\"\npython scripts/comment.py unpacked/ 1 \"Reply text\" --parent 0  # reply to comment 0\npython scripts/comment.py unpacked/ 0 \"Text\" --author \"Custom Author\"  # custom author name\n```\nThen add markers to document.xml (see Comments in XML Reference).\n\n### Step 3: Pack\n```bash\npython scripts/office/pack.py unpacked/ output.docx --original document.docx\n```\nValidates with auto-repair, condenses XML, and creates DOCX. Use `--validate false` to skip.\n\n**Auto-repair will fix:**\n- `durableId` >= 0x7FFFFFFF (regenerates valid ID)\n- Missing `xml:space=\"preserve\"` on `<w:t>` with whitespace\n\n**Auto-repair won't fix:**\n- Malformed XML, invalid element nesting, missing relationships, schema violations\n\n### Common Pitfalls\n\n- **Replace entire `<w:r>` elements**: When adding tracked changes, replace the whole `<w:r>...</w:r>` block with `<w:del>...<w:ins>...` as siblings. Don't inject tracked change tags inside a run.\n- **Preserve `<w:rPr>` formatting**: Copy the original run's `<w:rPr>` block into your tracked change runs to maintain bold, font size, etc.\n\n---\n\n## XML Reference\n\n### Schema Compliance\n\n- **Element order in `<w:pPr>`**: `<w:pStyle>`, `<w:numPr>`, `<w:spacing>`, `<w:ind>`, `<w:jc>`, `<w:rPr>` last\n- **Whitespace**: Add `xml:space=\"preserve\"` to `<w:t>` with leading/trailing spaces\n- **RSIDs**: Must be 8-digit hex (e.g., `00AB1234`)\n\n### Tracked Changes\n\n**Insertion:**\n```xml\n<w:ins w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:t>inserted text</w:t></w:r>\n</w:ins>\n```\n\n**Deletion:**\n```xml\n<w:del w:id=\"2\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:delText>deleted text</w:delText></w:r>\n</w:del>\n```\n\n**Inside `<w:del>`**: Use `<w:delText>` instead of `<w:t>`, and `<w:delInstrText>` instead of `<w:instrText>`.\n\n**Minimal edits** - only mark what changes:\n```xml\n<!-- Change \"30 days\" to \"60 days\" -->\n<w:r><w:t>The term is </w:t></w:r>\n<w:del w:id=\"1\" w:author=\"Claude\" w:date=\"...\">\n  <w:r><w:delText>30</w:delText></w:r>\n</w:del>\n<w:ins w:id=\"2\" w:author=\"Claude\" w:date=\"...\">\n  <w:r><w:t>60</w:t></w:r>\n</w:ins>\n<w:r><w:t> days.</w:t></w:r>\n```\n\n**Deleting entire paragraphs/list items** - when removing ALL content from a paragraph, also mark the paragraph mark as deleted so it merges with the next paragraph. Add `<w:del/>` inside `<w:pPr><w:rPr>`:\n```xml\n<w:p>\n  <w:pPr>\n    <w:numPr>...</w:numPr>  <!-- list numbering if present -->\n    <w:rPr>\n      <w:del w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\"/>\n    </w:rPr>\n  </w:pPr>\n  <w:del w:id=\"2\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n    <w:r><w:delText>Entire paragraph content being deleted...</w:delText></w:r>\n  </w:del>\n</w:p>\n```\nWithout the `<w:del/>` in `<w:pPr><w:rPr>`, accepting changes leaves an empty paragraph/list item.\n\n**Rejecting another author's insertion** - nest deletion inside their insertion:\n```xml\n<w:ins w:author=\"Jane\" w:id=\"5\">\n  <w:del w:author=\"Claude\" w:id=\"10\">\n    <w:r><w:delText>their inserted text</w:delText></w:r>\n  </w:del>\n</w:ins>\n```\n\n**Restoring another author's deletion** - add insertion after (don't modify their deletion):\n```xml\n<w:del w:author=\"Jane\" w:id=\"5\">\n  <w:r><w:delText>deleted text</w:delText></w:r>\n</w:del>\n<w:ins w:author=\"Claude\" w:id=\"10\">\n  <w:r><w:t>deleted text</w:t></w:r>\n</w:ins>\n```\n\n### Comments\n\nAfter running `comment.py` (see Step 2), add markers to document.xml. For replies, use `--parent` flag and nest markers inside the parent's.\n\n**CRITICAL: `<w:commentRangeStart>` and `<w:commentRangeEnd>` are siblings of `<w:r>`, never inside `<w:r>`.**\n\n```xml\n<!-- Comment markers are direct children of w:p, never inside w:r -->\n<w:commentRangeStart w:id=\"0\"/>\n<w:del w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:delText>deleted</w:delText></w:r>\n</w:del>\n<w:r><w:t> more text</w:t></w:r>\n<w:commentRangeEnd w:id=\"0\"/>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"0\"/></w:r>\n\n<!-- Comment 0 with reply 1 nested inside -->\n<w:commentRangeStart w:id=\"0\"/>\n  <w:commentRangeStart w:id=\"1\"/>\n  <w:r><w:t>text</w:t></w:r>\n  <w:commentRangeEnd w:id=\"1\"/>\n<w:commentRangeEnd w:id=\"0\"/>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"0\"/></w:r>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"1\"/></w:r>\n```\n\n### Images\n\n1. Add image file to `word/media/`\n2. Add relationship to `word/_rels/document.xml.rels`:\n```xml\n<Relationship Id=\"rId5\" Type=\".../image\" Target=\"media/image1.png\"/>\n```\n3. Add content type to `[Content_Types].xml`:\n```xml\n<Default Extension=\"png\" ContentType=\"image/png\"/>\n```\n4. Reference in document.xml:\n```xml\n<w:drawing>\n  <wp:inline>\n    <wp:extent cx=\"914400\" cy=\"914400\"/>  <!-- EMUs: 914400 = 1 inch -->\n    <a:graphic>\n      <a:graphicData uri=\".../picture\">\n        <pic:pic>\n          <pic:blipFill><a:blip r:embed=\"rId5\"/></pic:blipFill>\n        </pic:pic>\n      </a:graphicData>\n    </a:graphic>\n  </wp:inline>\n</w:drawing>\n```\n\n---\n\n## Dependencies\n\n- **pandoc**: Text extraction\n- **docx**: `npm install -g docx` (new documents)\n- **LibreOffice**: PDF conversion (auto-configured for sandboxed environments via `scripts/office/soffice.py`)\n- **Poppler**: `pdftoppm` for images\n","resources/example-skills/skill-creator/SKILL.md":"---\nname: skill-creator\ndescription: Guide for creating effective skills. Use when creating a new skill or updating an existing skill that extends agent capabilities with specialized knowledge, workflows, or tool integrations.\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills.\n\n## About Skills\n\nSkills are modular, self-contained packages that extend agent capabilities by providing\nspecialized knowledge, workflows, and tools. Think of them as \"onboarding guides\" for specific\ndomains or tasks—they transform a general-purpose agent into a specialized agent\nequipped with procedural knowledge that no model can fully possess.\n\n### What Skills Provide\n\n1. Specialized workflows - Multi-step procedures for specific domains\n2. Tool integrations - Instructions for working with specific file formats or APIs\n3. Domain expertise - Company-specific knowledge, schemas, business logic\n4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks\n\n## Core Principles\n\n### Concise is Key\n\nThe context window is a public good. Skills share the context window with everything else the agent needs: system prompt, conversation history, other Skills' metadata, and the actual user request.\n\n**Default assumption: The agent is already very capable.** Only add context the agent doesn't already have. Challenge each piece of information: \"Does the agent really need this explanation?\" and \"Does this paragraph justify its token cost?\"\n\nPrefer concise examples over verbose explanations.\n\n### Set Appropriate Degrees of Freedom\n\nMatch the level of specificity to the task's fragility and variability:\n\n**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.\n\n**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.\n\n**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.\n\nThink of the agent exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).\n\n### Anatomy of a Skill\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   ├── description: (required)\n│   │   └── compatibility: (optional, rarely needed)\n│   └── Markdown instructions (required)\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n#### SKILL.md (required)\n\nEvery SKILL.md consists of:\n\n- **Frontmatter** (YAML): Contains `name` and `description` fields (required), plus optional fields like `license`, `metadata`, and `compatibility`. Only `name` and `description` are read by the agent to determine when the skill triggers, so be clear and comprehensive about what the skill is and when it should be used. The `compatibility` field is for noting environment requirements (target product, system packages, etc.) but most skills don't need it.\n- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).\n\n#### Bundled Resources (optional)\n\n##### Scripts (`scripts/`)\n\nExecutable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.\n\n- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed\n- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks\n- **Benefits**: Token efficient, deterministic, may be executed without loading into context\n- **Note**: Scripts may still need to be read by the agent for patching or environment-specific adjustments\n\n##### References (`references/`)\n\nDocumentation and reference material intended to be loaded as needed into context to inform the agent's process and thinking.\n\n- **When to include**: For documentation that the agent should reference while working\n- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications\n- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides\n- **Benefits**: Keeps SKILL.md lean, loaded only when the agent determines it's needed\n- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md\n- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.\n\n##### Assets (`assets/`)\n\nFiles not intended to be loaded into context, but rather used within the output the agent produces.\n\n- **When to include**: When the skill needs files that will be used in the final output\n- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography\n- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified\n- **Benefits**: Separates output resources from documentation, enables the agent to use files without loading them into context\n\n#### What to Not Include in a Skill\n\nA skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:\n\n- README.md\n- INSTALLATION_GUIDE.md\n- QUICK_REFERENCE.md\n- CHANGELOG.md\n- etc.\n\nThe skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxilary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.\n\n### Progressive Disclosure Design Principle\n\nSkills use a three-level loading system to manage context efficiently:\n\n1. **Metadata (name + description)** - Always in context (~100 words)\n2. **SKILL.md body** - When skill triggers (<5k words)\n3. **Bundled resources** - As needed by the agent (Unlimited because scripts can be executed without reading into context window)\n\n#### Progressive Disclosure Patterns\n\nKeep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.\n\n**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.\n\n**Pattern 1: High-level guide with references**\n\n```markdown\n# PDF Processing\n\n## Quick start\n\nExtract text with pdfplumber:\n[code example]\n\n## Advanced features\n\n- **Form filling**: See [FORMS.md](FORMS.md) for complete guide\n- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods\n- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns\n```\n\nThe agent loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.\n\n**Pattern 2: Domain-specific organization**\n\nFor Skills with multiple domains, organize content by domain to avoid loading irrelevant context:\n\n```\nbigquery-skill/\n├── SKILL.md (overview and navigation)\n└── reference/\n    ├── finance.md (revenue, billing metrics)\n    ├── sales.md (opportunities, pipeline)\n    ├── product.md (API usage, features)\n    └── marketing.md (campaigns, attribution)\n```\n\nWhen a user asks about sales metrics, the agent only reads sales.md.\n\nSimilarly, for skills supporting multiple frameworks or variants, organize by variant:\n\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md (AWS deployment patterns)\n    ├── gcp.md (GCP deployment patterns)\n    └── azure.md (Azure deployment patterns)\n```\n\nWhen the user chooses AWS, the agent only reads aws.md.\n\n**Pattern 3: Conditional details**\n\nShow basic content, link to advanced content:\n\n```markdown\n# DOCX Processing\n\n## Creating documents\n\nUse docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).\n\n## Editing documents\n\nFor simple edits, modify the XML directly.\n\n**For tracked changes**: See [REDLINING.md](REDLINING.md)\n**For OOXML details**: See [OOXML.md](OOXML.md)\n```\n\nThe agent reads REDLINING.md or OOXML.md only when the user needs those features.\n\n**Important guidelines:**\n\n- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.\n- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so the agent can see the full scope when previewing.\n\n## Skill Creation Process\n\nSkill creation involves these steps:\n\n1. Understand the skill with concrete examples\n2. Plan reusable skill contents (scripts, references, assets)\n3. Initialize the skill (run init_skill.py)\n4. Edit the skill (implement resources and write SKILL.md)\n5. Package the skill (run package_skill.py)\n6. Iterate based on real usage\n\nFollow these steps in order, skipping only if there is a clear reason why they are not applicable.\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.\n\n### Step 3: Initializing the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists, and iteration or packaging is needed. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage (run from the skill-creator skill directory):\n\n```bash\npython scripts/init_skill.py <skill-name> --path <output-directory>\n```\n\nNote: The scripts are located in this skill's `scripts/` directory. Use the full path if running from a different directory.\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Creates example resource directories: `scripts/`, `references/`, and `assets/`\n- Adds example files in each directory that can be customized or deleted\n\nAfter initialization, customize or remove the generated SKILL.md and example files as needed.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for an agent to use. Include information that would be beneficial and non-obvious to the agent. Consider what procedural knowledge, domain-specific details, or reusable assets would help the agent execute these tasks more effectively.\n\n#### Learn Proven Design Patterns\n\nConsult these helpful guides based on your skill's needs:\n\n- **Multi-step processes**: See references/workflows.md for sequential workflows and conditional logic\n- **Specific output formats or quality standards**: See references/output-patterns.md for template and example patterns\n\nThese files contain established best practices for effective skill design.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nAny example files and directories not needed for the skill should be deleted. The initialization script creates example files in `scripts/`, `references/`, and `assets/` to demonstrate structure, but most skills won't need all of them.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name` and `description`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps the agent understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to the agent.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when the agent needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n\nDo not include any other fields in YAML frontmatter.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n### Step 5: Packaging a Skill\n\nOnce development of the skill is complete, it must be packaged into a distributable .skill file that gets shared with the user. The packaging process automatically validates the skill first to ensure it meets all requirements.\n\nUsage (run from the skill-creator skill directory):\n\n```bash\npython scripts/package_skill.py <path/to/skill-folder>\n```\n\nOptional output directory specification:\n\n```bash\npython scripts/package_skill.py <path/to/skill-folder> ./dist\n```\n\nNote: The scripts are located in this skill's `scripts/` directory. Use the full path if running from a different directory.\n\nThe packaging script will:\n\n1. **Validate** the skill automatically, checking:\n   - YAML frontmatter format and required fields\n   - Skill naming conventions and directory structure\n   - Description completeness and quality\n   - File organization and resource references\n\n2. **Package** the skill if validation passes, creating a .skill file named after the skill (e.g., `my-skill.skill`) that includes all files and maintains the proper directory structure for distribution. The .skill file is a zip file with a .skill extension.\n\nIf validation fails, the script will report the errors and exit without creating a package. Fix any validation errors and run the packaging command again.\n\n### Step 6: Iterate\n\nAfter testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.\n\n**Iteration workflow:**\n\n1. Use the skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify how SKILL.md or bundled resources should be updated\n4. Implement changes and test again\n","resources/example-skills/skill-creator/references/workflows.md":"# Workflow Patterns\n\n## Sequential Workflows\n\nFor complex tasks, break operations into clear, sequential steps. It is often helpful to give the agent an overview of the process towards the beginning of SKILL.md:\n\n```markdown\nFilling a PDF form involves these steps:\n\n1. Analyze the form (run analyze_form.py)\n2. Create field mapping (edit fields.json)\n3. Validate mapping (run validate_fields.py)\n4. Fill the form (run fill_form.py)\n5. Verify output (run verify_output.py)\n```\n\n## Conditional Workflows\n\nFor tasks with branching logic, guide the agent through decision points:\n\n```markdown\n1. Determine the modification type:\n   **Creating new content?** → Follow \"Creation workflow\" below\n   **Editing existing content?** → Follow \"Editing workflow\" below\n\n2. Creation workflow: [steps]\n3. Editing workflow: [steps]\n```","resources/example-skills/skill-security-auditor/references/secrets-patterns.md":"# Secrets Detection Patterns\n\nRegex patterns and rules for detecting hardcoded secrets, credentials, and sensitive data in source code.\n\n## Table of Contents\n\n- [API Keys and Tokens](#api-keys-and-tokens)\n- [Cloud Provider Credentials](#cloud-provider-credentials)\n- [Database Connection Strings](#database-connection-strings)\n- [Private Keys and Certificates](#private-keys-and-certificates)\n- [Generic Patterns](#generic-patterns)\n- [Files to Always Check](#files-to-always-check)\n- [False Positive Reduction](#false-positive-reduction)\n\n## API Keys and Tokens\n\n| Service | Pattern | Example |\n|---------|---------|---------|\n| AWS Access Key | `AKIA[0-9A-Z]{16}` | AKIAIOSFODNN7EXAMPLE |\n| AWS Secret Key | `(?i)aws_secret_access_key\\s*=\\s*\\S{40}` | |\n| GitHub Token | `gh[ps]_[A-Za-z0-9_]{36,}` | ghp_xxxxxxxxxxxx |\n| GitHub Fine-grained | `github_pat_[A-Za-z0-9_]{22,}` | |\n| GitLab Token | `glpat-[A-Za-z0-9\\-]{20,}` | |\n| Slack Token | `xox[baprs]-[A-Za-z0-9\\-]{10,}` | |\n| Slack Webhook | `https://hooks\\.slack\\.com/services/T[A-Z0-9]+/B[A-Z0-9]+/[A-Za-z0-9]+` | |\n| Stripe Secret | `sk_live_[A-Za-z0-9]{24,}` | |\n| Stripe Publishable | `pk_live_[A-Za-z0-9]{24,}` | |\n| Twilio | `SK[0-9a-fA-F]{32}` | |\n| SendGrid | `SG\\.[A-Za-z0-9\\-_]{22}\\.[A-Za-z0-9\\-_]{43}` | |\n| Mailgun | `key-[0-9a-zA-Z]{32}` | |\n| Google API Key | `AIza[0-9A-Za-z\\-_]{35}` | |\n| Google OAuth | `[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com` | |\n| Heroku API Key | `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}` | |\n| npm Token | `npm_[A-Za-z0-9]{36}` | |\n| PyPI Token | `pypi-[A-Za-z0-9\\-_]{50,}` | |\n\n## Cloud Provider Credentials\n\n### AWS\n```\n# Access Key ID\nAKIA[0-9A-Z]{16}\n\n# Secret Access Key (in config context)\n(?i)(aws_secret_access_key|aws_secret_key)\\s*[=:]\\s*[A-Za-z0-9/+=]{40}\n\n# Session Token\n(?i)aws_session_token\\s*[=:]\\s*\\S+\n```\n\n### GCP\n```\n# Service account key file indicators\n\"type\"\\s*:\\s*\"service_account\"\n\"private_key\"\\s*:\\s*\"-----BEGIN\n\n# OAuth client secret\n(?i)client_secret\\s*[=:]\\s*\\S+\n```\n\n### Azure\n```\n# Storage account key\n(?i)(AccountKey|account_key)\\s*[=:]\\s*[A-Za-z0-9+/=]{86,}\n\n# Connection strings\n(?i)(DefaultEndpointsProtocol|AccountName|AccountKey)=[^;\\s]+\n```\n\n## Database Connection Strings\n\n```\n# Generic with embedded password\n(?i)(mysql|postgres|postgresql|mongodb|redis|mssql|sqlserver)://[^:]+:[^@]+@\n\n# Django DATABASE_URL\n(?i)DATABASE_URL\\s*=\\s*\\S+://\\S+:\\S+@\n\n# JDBC with password\n(?i)jdbc:[a-z]+://[^;]+password=[^;\\s]+\n```\n\n## Private Keys and Certificates\n\n```\n# RSA private key\n-----BEGIN RSA PRIVATE KEY-----\n\n# Generic private key\n-----BEGIN PRIVATE KEY-----\n\n# EC private key\n-----BEGIN EC PRIVATE KEY-----\n\n# OpenSSH private key\n-----BEGIN OPENSSH PRIVATE KEY-----\n\n# PGP private key\n-----BEGIN PGP PRIVATE KEY BLOCK-----\n\n# Certificate (not a secret, but may indicate key nearby)\n-----BEGIN CERTIFICATE-----\n```\n\n## Generic Patterns\n\nThese catch secrets not covered by service-specific patterns:\n\n```\n# Assignment patterns with secret-like variable names\n(?i)(password|passwd|pwd|secret|token|api_key|apikey|api_secret|access_key|auth_token|credentials)\\s*[=:]\\s*['\"][^'\"]{8,}['\"]\n\n# Bearer tokens in code\n(?i)bearer\\s+[A-Za-z0-9\\-._~+/]+=*\n\n# Base64 encoded secrets (high entropy, 20+ chars)\n(?i)(secret|key|token|password)\\s*[=:]\\s*['\"][A-Za-z0-9+/]{20,}={0,2}['\"]\n\n# Hex-encoded secrets (32+ chars)\n(?i)(secret|key|token)\\s*[=:]\\s*['\"][0-9a-fA-F]{32,}['\"]\n```\n\n## Files to Always Check\n\n**High priority** (most likely to contain secrets):\n```\n.env, .env.*, .env.local, .env.production\nconfig.json, config.yaml, config.yml, config.toml\nsettings.py, settings.json\napplication.properties, application.yml\ndocker-compose.yml, docker-compose.*.yml\n.aws/credentials, .boto\n.netrc, .npmrc, .pypirc\nid_rsa, id_ecdsa, id_ed25519, *.pem, *.key\n```\n\n**Check .gitignore coverage**: Ensure these files are listed in `.gitignore`. If they are tracked by git, flag as a finding.\n\n**Git history**: Secrets may have been committed and later removed. Check with:\n```bash\ngit log --all --diff-filter=D -- \"*.env\" \"*.pem\" \"*.key\"\ngit log --all -p -S \"AKIA\" -- . # Search for AWS keys in history\n```\n\n## False Positive Reduction\n\nSkip matches that are likely not real secrets:\n- Values containing only placeholder text: `example`, `changeme`, `TODO`, `xxx`, `your_`, `placeholder`, `dummy`, `test`, `sample`\n- Values from documentation or comments on the same line as `example`, `e.g.`, `doc`, `TODO`\n- Values in test files matching `*_test.*`, `test_*.*`, `*.spec.*`, `**/test/**`, `**/tests/**`, `**/__tests__/**`\n- Environment variable references: `${VAR}`, `$VAR`, `%VAR%`, `os.environ`, `process.env`\n- Empty or whitespace-only values\n","resources/example-skills/skill-security-auditor/references/vulnerability-patterns.md":"# Vulnerability Patterns Reference\n\nDetailed patterns for identifying security vulnerabilities across languages and frameworks.\n\n## Table of Contents\n\n- [Injection Vulnerabilities](#injection-vulnerabilities)\n- [Authentication and Session Issues](#authentication-and-session-issues)\n- [Cryptographic Weaknesses](#cryptographic-weaknesses)\n- [Insecure Deserialization](#insecure-deserialization)\n- [Server-Side Request Forgery](#server-side-request-forgery)\n- [File Operations](#file-operations)\n- [Framework-Specific Patterns](#framework-specific-patterns)\n\n## Injection Vulnerabilities\n\n### SQL Injection\n\n**Vulnerable patterns** (string concatenation or f-strings in queries):\n```\n# Python\nexecute(f\"...{var}...\")\nexecute(\"...\" + var + \"...\")\nexecute(\"...%s...\" % var)\n\n# JavaScript\nquery(`...${var}...`)\nquery(\"...\" + var + \"...\")\n\n# Go\ndb.Query(\"...\" + var + \"...\")\nfmt.Sprintf(\"SELECT ... %s\", var) passed to Query()\n\n# Java\nstatement.execute(\"...\" + var + \"...\")\n```\n\n**Safe alternatives**: Parameterized queries, prepared statements, ORM query builders.\n\n### NoSQL Injection\n\n**Vulnerable patterns**:\n```javascript\n// MongoDB: user input directly in query object\ndb.collection.find({ user: req.body.user, pass: req.body.pass })\n// Attacker sends: { \"pass\": { \"$gt\": \"\" } }\n```\n\n**Safe alternative**: Validate input types, use `$eq` explicitly, sanitize with libraries like `mongo-sanitize`.\n\n### Command Injection\n\n**Vulnerable functions by language**:\n```\nPython:  os.system(), os.popen(), subprocess.call(shell=True), subprocess.Popen(shell=True)\nNode.js: child_process.exec(), child_process.execSync()\nGo:      exec.Command(\"sh\", \"-c\", userInput)\nJava:    Runtime.exec(userInput)\nPHP:     exec(), system(), passthru(), shell_exec(), backticks\nRuby:    system(), exec(), backticks, %x{}\n```\n\n**Safe alternative**: Use subprocess with list arguments (no shell), validate and allowlist input values.\n\n### LDAP Injection\n\n**Vulnerable pattern**:\n```python\nldap.search_s(base, scope, f\"(uid={username})\")\n```\n\n**Safe alternative**: Escape special characters `()*\\` and null bytes in user input.\n\n### XSS (Cross-Site Scripting)\n\n**Vulnerable sinks**:\n```\nJavaScript: innerHTML, outerHTML, document.write(), eval(), v-html, dangerouslySetInnerHTML\nTemplate:   |safe, {% autoescape off %}, !=, !{}, {!! !!}\n```\n\n**Safe alternatives**: Use `textContent`, template auto-escaping, CSP headers, DOMPurify for required HTML.\n\n## Authentication and Session Issues\n\n### Weak Password Storage\n\n**Vulnerable**:\n```python\n# Plaintext or weak hashing\nhashlib.md5(password.encode()).hexdigest()\nhashlib.sha256(password.encode()).hexdigest()\n```\n\n**Safe**:\n```python\n# Use adaptive hashing with salt\nimport bcrypt\nhashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))\n```\n\n### JWT Vulnerabilities\n\n**Common issues**:\n- Accepting `alg: \"none\"`\n- Using symmetric algorithms (HS256) with public keys\n- Not validating expiry (`exp`) or issuer (`iss`)\n- Storing sensitive data in payload (JWT is base64, not encrypted)\n\n**Verification checklist**:\n```python\n# Ensure algorithm is explicitly specified\njwt.decode(token, key, algorithms=[\"RS256\"])  # explicit algorithm\njwt.decode(token, key)  # VULNERABLE: accepts any algorithm\n```\n\n### Session Management\n\n**Issues to flag**:\n- Session IDs in URLs\n- Missing `HttpOnly`, `Secure`, `SameSite` flags on session cookies\n- No session timeout or rotation after authentication\n- Predictable session identifiers\n\n## Cryptographic Weaknesses\n\n### Insecure Algorithms\n\n**Deprecated/broken** (flag if found):\n```\nHash:    MD5, SHA1 (for security purposes)\nCipher:  DES, 3DES, RC4, Blowfish\nMode:    ECB mode for any block cipher\nRSA:     Key size < 2048 bits\n```\n\n**Acceptable**:\n```\nHash:    SHA-256, SHA-384, SHA-512, BLAKE2\nCipher:  AES-128/256-GCM, ChaCha20-Poly1305\nRSA:     2048+ bits with OAEP padding\nECDSA:   P-256 or P-384 curves\n```\n\n### Hardcoded Cryptographic Material\n\n**Flag if found in source**:\n- Encryption keys, IV/nonce values\n- Private keys (RSA, ECDSA, Ed25519)\n- Salt values for password hashing\n\n## Insecure Deserialization\n\n**Vulnerable functions by language**:\n```\nPython:  pickle.loads(), yaml.load() (without SafeLoader), marshal.loads()\nJava:    ObjectInputStream.readObject(), XMLDecoder\nPHP:     unserialize()\nRuby:    Marshal.load(), YAML.load()\nNode.js: node-serialize, js-yaml.load() (with dangerous schema)\n```\n\n**Safe alternatives**: Use JSON for data exchange, use safe loaders (`yaml.safe_load()`), validate and type-check deserialized data.\n\n## Server-Side Request Forgery\n\n**Vulnerable pattern**:\n```python\n# User controls the URL\nrequests.get(user_provided_url)\nurllib.request.urlopen(user_provided_url)\n```\n\n**Mitigations**:\n- Validate URLs against an allowlist of domains/IPs\n- Block requests to internal/private IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, 169.254.x)\n- Disable redirects or validate redirect targets\n- Use a network-level firewall for outbound requests\n\n## File Operations\n\n### Path Traversal\n\n**Vulnerable pattern**:\n```python\n# User controls filename\nopen(os.path.join(base_dir, user_filename))\n```\n\n**Safe pattern**:\n```python\nimport pathlib\nbase = pathlib.Path(base_dir).resolve()\ntarget = (base / user_filename).resolve()\nif not str(target).startswith(str(base)):\n    raise ValueError(\"Path traversal detected\")\n```\n\n### Unrestricted File Upload\n\n**Checklist**:\n- Validate file type by content (magic bytes), not just extension\n- Enforce maximum file size limits\n- Store uploads outside the web root\n- Generate random filenames, do not use user-supplied names\n- Scan uploads for malware when possible\n\n## Framework-Specific Patterns\n\n### Django\n\n```python\n# Dangerous: raw SQL\nModel.objects.raw(f\"SELECT * FROM t WHERE id = {user_id}\")\n# Safe: ORM or parameterized raw\nModel.objects.filter(id=user_id)\nModel.objects.raw(\"SELECT * FROM t WHERE id = %s\", [user_id])\n\n# Check settings.py\nDEBUG = True                      # Must be False in production\nALLOWED_HOSTS = ['*']            # Must be restricted\nCSRF_COOKIE_SECURE = False       # Must be True with HTTPS\nSESSION_COOKIE_SECURE = False    # Must be True with HTTPS\n```\n\n### Flask\n\n```python\n# Dangerous: XSS via Markup\nfrom markupsafe import Markup\nreturn Markup(f\"<p>{user_input}</p>\")\n# Safe: Use templates with auto-escaping\nreturn render_template(\"page.html\", data=user_input)\n\n# Check for debug mode\napp.run(debug=True)  # Must be False in production\n```\n\n### Express.js\n\n```javascript\n// Missing security headers - use helmet\nconst helmet = require('helmet');\napp.use(helmet());\n\n// Missing CSRF protection on state-changing routes\n// Missing rate limiting on auth endpoints\n// Missing input validation (use express-validator or zod)\n```\n\n### Spring Boot\n\n```java\n// Dangerous: SpEL injection\nparser.parseExpression(userInput).getValue();\n\n// Check application.properties\nserver.error.include-stacktrace=always  // Leaks internals\nmanagement.endpoints.web.exposure.include=*  // Exposes actuator\n```\n"},"items":[{"name":"SKILL.md","path":"resources/example-skills/docx/SKILL.md","rawUrl":"https://raw.githubusercontent.com/eigent-ai/eigent/HEAD/resources/example-skills/docx/SKILL.md","title":"docx","category":"anthropic-skill","format":"markdown","content":"---\nname: docx\ndescription: \"Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files). Triggers include: any mention of \\\"Word doc\\\", \\\"word document\\\", \\\".docx\\\", or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a \\\"report\\\", \\\"memo\\\", \\\"letter\\\", \\\"template\\\", or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# DOCX creation, editing, and analysis\n\n## Overview\n\nA .docx file is a ZIP archive containing XML files.\n\n## Quick Reference\n\n| Task | Approach |\n|------|----------|\n| Read/analyze content | `pandoc` or unpack for raw XML |\n| Create new document | Use `docx-js` - see Creating New Documents below |\n| Edit existing document | Unpack → edit XML → repack - see Editing Existing Documents below |\n\n### Converting .doc to .docx\n\nLegacy `.doc` files must be converted before editing:\n\n```bash\npython scripts/office/soffice.py --headless --convert-to docx document.doc\n```\n\n### Reading Content\n\n```bash\n# Text extraction with tracked changes\npandoc --track-changes=all document.docx -o output.md\n\n# Raw XML access\npython scripts/office/unpack.py document.docx unpacked/\n```\n\n### Converting to Images\n\n```bash\npython scripts/office/soffice.py --headless --convert-to pdf document.docx\npdftoppm -jpeg -r 150 document.pdf page\n```\n\n### Accepting Tracked Changes\n\nTo produce a clean document with all tracked changes accepted (requires LibreOffice):\n\n```bash\npython scripts/accept_changes.py input.docx output.docx\n```\n\n---\n\n## Creating New Documents\n\nGenerate .docx files with JavaScript, then validate. Install: `npm install -g docx`\n\n### Setup\n```javascript\nconst { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun,\n        Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink,\n        TableOfContents, HeadingLevel, BorderStyle, WidthType, ShadingType,\n        VerticalAlign, PageNumber, PageBreak } = require('docx');\n\nconst doc = new Document({ sections: [{ children: [/* content */] }] });\nPacker.toBuffer(doc).then(buffer => fs.writeFileSync(\"doc.docx\", buffer));\n```\n\n### Validation\nAfter creating the file, validate it. If validation fails, unpack, fix the XML, and repack.\n```bash\npython scripts/office/validate.py doc.docx\n```\n\n### Page Size\n\n```javascript\n// CRITICAL: docx-js defaults to A4, not US Letter\n// Always set page size explicitly for consistent results\nsections: [{\n  properties: {\n    page: {\n      size: {\n        width: 12240,   // 8.5 inches in DXA\n        height: 15840   // 11 inches in DXA\n      },\n      margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } // 1 inch margins\n    }\n  },\n  children: [/* content */]\n}]\n```\n\n**Common page sizes (DXA units, 1440 DXA = 1 inch):**\n\n| Paper | Width | Height | Content Width (1\" margins) |\n|-------|-------|--------|---------------------------|\n| US Letter | 12,240 | 15,840 | 9,360 |\n| A4 (default) | 11,906 | 16,838 | 9,026 |\n\n**Landscape orientation:** docx-js swaps width/height internally, so pass portrait dimensions and let it handle the swap:\n```javascript\nsize: {\n  width: 12240,   // Pass SHORT edge as width\n  height: 15840,  // Pass LONG edge as height\n  orientation: PageOrientation.LANDSCAPE  // docx-js swaps them in the XML\n},\n// Content width = 15840 - left margin - right margin (uses the long edge)\n```\n\n### Styles (Override Built-in Headings)\n\nUse Arial as the default font (universally supported). Keep titles black for readability.\n\n```javascript\nconst doc = new Document({\n  styles: {\n    default: { document: { run: { font: \"Arial\", size: 24 } } }, // 12pt default\n    paragraphStyles: [\n      // IMPORTANT: Use exact IDs to override built-in styles\n      { id: \"Heading1\", name: \"Heading 1\", basedOn: \"Normal\", next: \"Normal\", quickFormat: true,\n        run: { size: 32, bold: true, font: \"Arial\" },\n        paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } }, // outlineLevel required for TOC\n      { id: \"Heading2\", name: \"Heading 2\", basedOn: \"Normal\", next: \"Normal\", quickFormat: true,\n        run: { size: 28, bold: true, font: \"Arial\" },\n        paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 } },\n    ]\n  },\n  sections: [{\n    children: [\n      new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun(\"Title\")] }),\n    ]\n  }]\n});\n```\n\n### Lists (NEVER use unicode bullets)\n\n```javascript\n// ❌ WRONG - never manually insert bullet characters\nnew Paragraph({ children: [new TextRun(\"• Item\")] })  // BAD\nnew Paragraph({ children: [new TextRun(\"\\u2022 Item\")] })  // BAD\n\n// ✅ CORRECT - use numbering config with LevelFormat.BULLET\nconst doc = new Document({\n  numbering: {\n    config: [\n      { reference: \"bullets\",\n        levels: [{ level: 0, format: LevelFormat.BULLET, text: \"•\", alignment: AlignmentType.LEFT,\n          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },\n      { reference: \"numbers\",\n        levels: [{ level: 0, format: LevelFormat.DECIMAL, text: \"%1.\", alignment: AlignmentType.LEFT,\n          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },\n    ]\n  },\n  sections: [{\n    children: [\n      new Paragraph({ numbering: { reference: \"bullets\", level: 0 },\n        children: [new TextRun(\"Bullet item\")] }),\n      new Paragraph({ numbering: { reference: \"numbers\", level: 0 },\n        children: [new TextRun(\"Numbered item\")] }),\n    ]\n  }]\n});\n\n// ⚠️ Each reference creates INDEPENDENT numbering\n// Same reference = continues (1,2,3 then 4,5,6)\n// Different reference = restarts (1,2,3 then 1,2,3)\n```\n\n### Tables\n\n**CRITICAL: Tables need dual widths** - set both `columnWidths` on the table AND `width` on each cell. Without both, tables render incorrectly on some platforms.\n\n```javascript\n// CRITICAL: Always set table width for consistent rendering\n// CRITICAL: Use ShadingType.CLEAR (not SOLID) to prevent black backgrounds\nconst border = { style: BorderStyle.SINGLE, size: 1, color: \"CCCCCC\" };\nconst borders = { top: border, bottom: border, left: border, right: border };\n\nnew Table({\n  width: { size: 9360, type: WidthType.DXA }, // Always use DXA (percentages break in Google Docs)\n  columnWidths: [4680, 4680], // Must sum to table width (DXA: 1440 = 1 inch)\n  rows: [\n    new TableRow({\n      children: [\n        new TableCell({\n          borders,\n          width: { size: 4680, type: WidthType.DXA }, // Also set on each cell\n          shading: { fill: \"D5E8F0\", type: ShadingType.CLEAR }, // CLEAR not SOLID\n          margins: { top: 80, bottom: 80, left: 120, right: 120 }, // Cell padding (internal, not added to width)\n          children: [new Paragraph({ children: [new TextRun(\"Cell\")] })]\n        })\n      ]\n    })\n  ]\n})\n```\n\n**Table width calculation:**\n\nAlways use `WidthType.DXA` — `WidthType.PERCENTAGE` breaks in Google Docs.\n\n```javascript\n// Table width = sum of columnWidths = content width\n// US Letter with 1\" margins: 12240 - 2880 = 9360 DXA\nwidth: { size: 9360, type: WidthType.DXA },\ncolumnWidths: [7000, 2360]  // Must sum to table width\n```\n\n**Width rules:**\n- **Always use `WidthType.DXA`** — never `WidthType.PERCENTAGE` (incompatible with Google Docs)\n- Table width must equal the sum of `columnWidths`\n- Cell `width` must match corresponding `columnWidth`\n- Cell `margins` are internal padding - they reduce content area, not add to cell width\n- For full-width tables: use content width (page width minus left and right margins)\n\n### Images\n\n```javascript\n// CRITICAL: type parameter is REQUIRED\nnew Paragraph({\n  children: [new ImageRun({\n    type: \"png\", // Required: png, jpg, jpeg, gif, bmp, svg\n    data: fs.readFileSync(\"image.png\"),\n    transformation: { width: 200, height: 150 },\n    altText: { title: \"Title\", description: \"Desc\", name: \"Name\" } // All three required\n  })]\n})\n```\n\n### Page Breaks\n\n```javascript\n// CRITICAL: PageBreak must be inside a Paragraph\nnew Paragraph({ children: [new PageBreak()] })\n\n// Or use pageBreakBefore\nnew Paragraph({ pageBreakBefore: true, children: [new TextRun(\"New page\")] })\n```\n\n### Table of Contents\n\n```javascript\n// CRITICAL: Headings must use HeadingLevel ONLY - no custom styles\nnew TableOfContents(\"Table of Contents\", { hyperlink: true, headingStyleRange: \"1-3\" })\n```\n\n### Headers/Footers\n\n```javascript\nsections: [{\n  properties: {\n    page: { margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } } // 1440 = 1 inch\n  },\n  headers: {\n    default: new Header({ children: [new Paragraph({ children: [new TextRun(\"Header\")] })] })\n  },\n  footers: {\n    default: new Footer({ children: [new Paragraph({\n      children: [new TextRun(\"Page \"), new TextRun({ children: [PageNumber.CURRENT] })]\n    })] })\n  },\n  children: [/* content */]\n}]\n```\n\n### Critical Rules for docx-js\n\n- **Set page size explicitly** - docx-js defaults to A4; use US Letter (12240 x 15840 DXA) for US documents\n- **Landscape: pass portrait dimensions** - docx-js swaps width/height internally; pass short edge as `width`, long edge as `height`, and set `orientation: PageOrientation.LANDSCAPE`\n- **Never use `\\n`** - use separate Paragraph elements\n- **Never use unicode bullets** - use `LevelFormat.BULLET` with numbering config\n- **PageBreak must be in Paragraph** - standalone creates invalid XML\n- **ImageRun requires `type`** - always specify png/jpg/etc\n- **Always set table `width` with DXA** - never use `WidthType.PERCENTAGE` (breaks in Google Docs)\n- **Tables need dual widths** - `columnWidths` array AND cell `width`, both must match\n- **Table width = sum of columnWidths** - for DXA, ensure they add up exactly\n- **Always add cell margins** - use `margins: { top: 80, bottom: 80, left: 120, right: 120 }` for readable padding\n- **Use `ShadingType.CLEAR`** - never SOLID for table shading\n- **TOC requires HeadingLevel only** - no custom styles on heading paragraphs\n- **Override built-in styles** - use exact IDs: \"Heading1\", \"Heading2\", etc.\n- **Include `outlineLevel`** - required for TOC (0 for H1, 1 for H2, etc.)\n\n---\n\n## Editing Existing Documents\n\n**Follow all 3 steps in order.**\n\n### Step 1: Unpack\n```bash\npython scripts/office/unpack.py document.docx unpacked/\n```\nExtracts XML, pretty-prints, merges adjacent runs, and converts smart quotes to XML entities (`&#x201C;` etc.) so they survive editing. Use `--merge-runs false` to skip run merging.\n\n### Step 2: Edit XML\n\nEdit files in `unpacked/word/`. See XML Reference below for patterns.\n\n**Use \"Claude\" as the author** for tracked changes and comments, unless the user explicitly requests use of a different name.\n\n**Use the Edit tool directly for string replacement. Do not write Python scripts.** Scripts introduce unnecessary complexity. The Edit tool shows exactly what is being replaced.\n\n**CRITICAL: Use smart quotes for new content.** When adding text with apostrophes or quotes, use XML entities to produce smart quotes:\n```xml\n<!-- Use these entities for professional typography -->\n<w:t>Here&#x2019;s a quote: &#x201C;Hello&#x201D;</w:t>\n```\n| Entity | Character |\n|--------|-----------|\n| `&#x2018;` | ‘ (left single) |\n| `&#x2019;` | ’ (right single / apostrophe) |\n| `&#x201C;` | “ (left double) |\n| `&#x201D;` | ” (right double) |\n\n**Adding comments:** Use `comment.py` to handle boilerplate across multiple XML files (text must be pre-escaped XML):\n```bash\npython scripts/comment.py unpacked/ 0 \"Comment text with &amp; and &#x2019;\"\npython scripts/comment.py unpacked/ 1 \"Reply text\" --parent 0  # reply to comment 0\npython scripts/comment.py unpacked/ 0 \"Text\" --author \"Custom Author\"  # custom author name\n```\nThen add markers to document.xml (see Comments in XML Reference).\n\n### Step 3: Pack\n```bash\npython scripts/office/pack.py unpacked/ output.docx --original document.docx\n```\nValidates with auto-repair, condenses XML, and creates DOCX. Use `--validate false` to skip.\n\n**Auto-repair will fix:**\n- `durableId` >= 0x7FFFFFFF (regenerates valid ID)\n- Missing `xml:space=\"preserve\"` on `<w:t>` with whitespace\n\n**Auto-repair won't fix:**\n- Malformed XML, invalid element nesting, missing relationships, schema violations\n\n### Common Pitfalls\n\n- **Replace entire `<w:r>` elements**: When adding tracked changes, replace the whole `<w:r>...</w:r>` block with `<w:del>...<w:ins>...` as siblings. Don't inject tracked change tags inside a run.\n- **Preserve `<w:rPr>` formatting**: Copy the original run's `<w:rPr>` block into your tracked change runs to maintain bold, font size, etc.\n\n---\n\n## XML Reference\n\n### Schema Compliance\n\n- **Element order in `<w:pPr>`**: `<w:pStyle>`, `<w:numPr>`, `<w:spacing>`, `<w:ind>`, `<w:jc>`, `<w:rPr>` last\n- **Whitespace**: Add `xml:space=\"preserve\"` to `<w:t>` with leading/trailing spaces\n- **RSIDs**: Must be 8-digit hex (e.g., `00AB1234`)\n\n### Tracked Changes\n\n**Insertion:**\n```xml\n<w:ins w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:t>inserted text</w:t></w:r>\n</w:ins>\n```\n\n**Deletion:**\n```xml\n<w:del w:id=\"2\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:delText>deleted text</w:delText></w:r>\n</w:del>\n```\n\n**Inside `<w:del>`**: Use `<w:delText>` instead of `<w:t>`, and `<w:delInstrText>` instead of `<w:instrText>`.\n\n**Minimal edits** - only mark what changes:\n```xml\n<!-- Change \"30 days\" to \"60 days\" -->\n<w:r><w:t>The term is </w:t></w:r>\n<w:del w:id=\"1\" w:author=\"Claude\" w:date=\"...\">\n  <w:r><w:delText>30</w:delText></w:r>\n</w:del>\n<w:ins w:id=\"2\" w:author=\"Claude\" w:date=\"...\">\n  <w:r><w:t>60</w:t></w:r>\n</w:ins>\n<w:r><w:t> days.</w:t></w:r>\n```\n\n**Deleting entire paragraphs/list items** - when removing ALL content from a paragraph, also mark the paragraph mark as deleted so it merges with the next paragraph. Add `<w:del/>` inside `<w:pPr><w:rPr>`:\n```xml\n<w:p>\n  <w:pPr>\n    <w:numPr>...</w:numPr>  <!-- list numbering if present -->\n    <w:rPr>\n      <w:del w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\"/>\n    </w:rPr>\n  </w:pPr>\n  <w:del w:id=\"2\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n    <w:r><w:delText>Entire paragraph content being deleted...</w:delText></w:r>\n  </w:del>\n</w:p>\n```\nWithout the `<w:del/>` in `<w:pPr><w:rPr>`, accepting changes leaves an empty paragraph/list item.\n\n**Rejecting another author's insertion** - nest deletion inside their insertion:\n```xml\n<w:ins w:author=\"Jane\" w:id=\"5\">\n  <w:del w:author=\"Claude\" w:id=\"10\">\n    <w:r><w:delText>their inserted text</w:delText></w:r>\n  </w:del>\n</w:ins>\n```\n\n**Restoring another author's deletion** - add insertion after (don't modify their deletion):\n```xml\n<w:del w:author=\"Jane\" w:id=\"5\">\n  <w:r><w:delText>deleted text</w:delText></w:r>\n</w:del>\n<w:ins w:author=\"Claude\" w:id=\"10\">\n  <w:r><w:t>deleted text</w:t></w:r>\n</w:ins>\n```\n\n### Comments\n\nAfter running `comment.py` (see Step 2), add markers to document.xml. For replies, use `--parent` flag and nest markers inside the parent's.\n\n**CRITICAL: `<w:commentRangeStart>` and `<w:commentRangeEnd>` are siblings of `<w:r>`, never inside `<w:r>`.**\n\n```xml\n<!-- Comment markers are direct children of w:p, never inside w:r -->\n<w:commentRangeStart w:id=\"0\"/>\n<w:del w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:delText>deleted</w:delText></w:r>\n</w:del>\n<w:r><w:t> more text</w:t></w:r>\n<w:commentRangeEnd w:id=\"0\"/>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"0\"/></w:r>\n\n<!-- Comment 0 with reply 1 nested inside -->\n<w:commentRangeStart w:id=\"0\"/>\n  <w:commentRangeStart w:id=\"1\"/>\n  <w:r><w:t>text</w:t></w:r>\n  <w:commentRangeEnd w:id=\"1\"/>\n<w:commentRangeEnd w:id=\"0\"/>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"0\"/></w:r>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"1\"/></w:r>\n```\n\n### Images\n\n1. Add image file to `word/media/`\n2. Add relationship to `word/_rels/document.xml.rels`:\n```xml\n<Relationship Id=\"rId5\" Type=\".../image\" Target=\"media/image1.png\"/>\n```\n3. Add content type to `[Content_Types].xml`:\n```xml\n<Default Extension=\"png\" ContentType=\"image/png\"/>\n```\n4. Reference in document.xml:\n```xml\n<w:drawing>\n  <wp:inline>\n    <wp:extent cx=\"914400\" cy=\"914400\"/>  <!-- EMUs: 914400 = 1 inch -->\n    <a:graphic>\n      <a:graphicData uri=\".../picture\">\n        <pic:pic>\n          <pic:blipFill><a:blip r:embed=\"rId5\"/></pic:blipFill>\n        </pic:pic>\n      </a:graphicData>\n    </a:graphic>\n  </wp:inline>\n</w:drawing>\n```\n\n---\n\n## Dependencies\n\n- **pandoc**: Text extraction\n- **docx**: `npm install -g docx` (new documents)\n- **LibreOffice**: PDF conversion (auto-configured for sandboxed environments via `scripts/office/soffice.py`)\n- **Poppler**: `pdftoppm` for images\n","frontmatter":{"name":"docx","description":"Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files). Triggers include: any mention of \"Word doc\", \"word document\", \".docx\", or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a \"report\", \"memo\", \"letter\", \"template\", or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation.","license":"Proprietary. LICENSE.txt has complete terms"},"isInternal":false,"tokens":4945,"sizeBytes":17141},{"name":"SKILL.md","path":"resources/example-skills/pdf/SKILL.md","rawUrl":"https://raw.githubusercontent.com/eigent-ai/eigent/HEAD/resources/example-skills/pdf/SKILL.md","title":"pdf","category":"anthropic-skill","format":"markdown","content":"---\nname: pdf\ndescription: Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill.\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# PDF Processing Guide\n\n## Overview\n\nThis guide covers essential PDF processing operations using Python libraries and command-line tools. For advanced features, JavaScript libraries, and detailed examples, see REFERENCE.md. If you need to fill out a PDF form, read FORMS.md and follow its instructions.\n\n## Quick Start\n\n```python\nfrom pypdf import PdfReader, PdfWriter\n\n# Read a PDF\nreader = PdfReader(\"document.pdf\")\nprint(f\"Pages: {len(reader.pages)}\")\n\n# Extract text\ntext = \"\"\nfor page in reader.pages:\n    text += page.extract_text()\n```\n\n## Python Libraries\n\n### pypdf - Basic Operations\n\n#### Merge PDFs\n```python\nfrom pypdf import PdfWriter, PdfReader\n\nwriter = PdfWriter()\nfor pdf_file in [\"doc1.pdf\", \"doc2.pdf\", \"doc3.pdf\"]:\n    reader = PdfReader(pdf_file)\n    for page in reader.pages:\n        writer.add_page(page)\n\nwith open(\"merged.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n#### Split PDF\n```python\nreader = PdfReader(\"input.pdf\")\nfor i, page in enumerate(reader.pages):\n    writer = PdfWriter()\n    writer.add_page(page)\n    with open(f\"page_{i+1}.pdf\", \"wb\") as output:\n        writer.write(output)\n```\n\n#### Extract Metadata\n```python\nreader = PdfReader(\"document.pdf\")\nmeta = reader.metadata\nprint(f\"Title: {meta.title}\")\nprint(f\"Author: {meta.author}\")\nprint(f\"Subject: {meta.subject}\")\nprint(f\"Creator: {meta.creator}\")\n```\n\n#### Rotate Pages\n```python\nreader = PdfReader(\"input.pdf\")\nwriter = PdfWriter()\n\npage = reader.pages[0]\npage.rotate(90)  # Rotate 90 degrees clockwise\nwriter.add_page(page)\n\nwith open(\"rotated.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n### pdfplumber - Text and Table Extraction\n\n#### Extract Text with Layout\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    for page in pdf.pages:\n        text = page.extract_text()\n        print(text)\n```\n\n#### Extract Tables\n```python\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    for i, page in enumerate(pdf.pages):\n        tables = page.extract_tables()\n        for j, table in enumerate(tables):\n            print(f\"Table {j+1} on page {i+1}:\")\n            for row in table:\n                print(row)\n```\n\n#### Advanced Table Extraction\n```python\nimport pandas as pd\n\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    all_tables = []\n    for page in pdf.pages:\n        tables = page.extract_tables()\n        for table in tables:\n            if table:  # Check if table is not empty\n                df = pd.DataFrame(table[1:], columns=table[0])\n                all_tables.append(df)\n\n# Combine all tables\nif all_tables:\n    combined_df = pd.concat(all_tables, ignore_index=True)\n    combined_df.to_excel(\"extracted_tables.xlsx\", index=False)\n```\n\n### reportlab - Create PDFs\n\n#### Basic PDF Creation\n```python\nfrom reportlab.lib.pagesizes import letter\nfrom reportlab.pdfgen import canvas\n\nc = canvas.Canvas(\"hello.pdf\", pagesize=letter)\nwidth, height = letter\n\n# Add text\nc.drawString(100, height - 100, \"Hello World!\")\nc.drawString(100, height - 120, \"This is a PDF created with reportlab\")\n\n# Add a line\nc.line(100, height - 140, 400, height - 140)\n\n# Save\nc.save()\n```\n\n#### Create PDF with Multiple Pages\n```python\nfrom reportlab.lib.pagesizes import letter\nfrom reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak\nfrom reportlab.lib.styles import getSampleStyleSheet\n\ndoc = SimpleDocTemplate(\"report.pdf\", pagesize=letter)\nstyles = getSampleStyleSheet()\nstory = []\n\n# Add content\ntitle = Paragraph(\"Report Title\", styles['Title'])\nstory.append(title)\nstory.append(Spacer(1, 12))\n\nbody = Paragraph(\"This is the body of the report. \" * 20, styles['Normal'])\nstory.append(body)\nstory.append(PageBreak())\n\n# Page 2\nstory.append(Paragraph(\"Page 2\", styles['Heading1']))\nstory.append(Paragraph(\"Content for page 2\", styles['Normal']))\n\n# Build PDF\ndoc.build(story)\n```\n\n#### Subscripts and Superscripts\n\n**IMPORTANT**: Never use Unicode subscript/superscript characters (₀₁₂₃₄₅₆₇₈₉, ⁰¹²³⁴⁵⁶⁷⁸⁹) in ReportLab PDFs. The built-in fonts do not include these glyphs, causing them to render as solid black boxes.\n\nInstead, use ReportLab's XML markup tags in Paragraph objects:\n```python\nfrom reportlab.platypus import Paragraph\nfrom reportlab.lib.styles import getSampleStyleSheet\n\nstyles = getSampleStyleSheet()\n\n# Subscripts: use <sub> tag\nchemical = Paragraph(\"H<sub>2</sub>O\", styles['Normal'])\n\n# Superscripts: use <super> tag\nsquared = Paragraph(\"x<super>2</super> + y<super>2</super>\", styles['Normal'])\n```\n\nFor canvas-drawn text (not Paragraph objects), manually adjust font the size and position rather than using Unicode subscripts/superscripts.\n\n## Command-Line Tools\n\n### pdftotext (poppler-utils)\n```bash\n# Extract text\npdftotext input.pdf output.txt\n\n# Extract text preserving layout\npdftotext -layout input.pdf output.txt\n\n# Extract specific pages\npdftotext -f 1 -l 5 input.pdf output.txt  # Pages 1-5\n```\n\n### qpdf\n```bash\n# Merge PDFs\nqpdf --empty --pages file1.pdf file2.pdf -- merged.pdf\n\n# Split pages\nqpdf input.pdf --pages . 1-5 -- pages1-5.pdf\nqpdf input.pdf --pages . 6-10 -- pages6-10.pdf\n\n# Rotate pages\nqpdf input.pdf output.pdf --rotate=+90:1  # Rotate page 1 by 90 degrees\n\n# Remove password\nqpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf\n```\n\n### pdftk (if available)\n```bash\n# Merge\npdftk file1.pdf file2.pdf cat output merged.pdf\n\n# Split\npdftk input.pdf burst\n\n# Rotate\npdftk input.pdf rotate 1east output rotated.pdf\n```\n\n## Common Tasks\n\n### Extract Text from Scanned PDFs\n```python\n# Requires: pip install pytesseract pdf2image\nimport pytesseract\nfrom pdf2image import convert_from_path\n\n# Convert PDF to images\nimages = convert_from_path('scanned.pdf')\n\n# OCR each page\ntext = \"\"\nfor i, image in enumerate(images):\n    text += f\"Page {i+1}:\\n\"\n    text += pytesseract.image_to_string(image)\n    text += \"\\n\\n\"\n\nprint(text)\n```\n\n### Add Watermark\n```python\nfrom pypdf import PdfReader, PdfWriter\n\n# Create watermark (or load existing)\nwatermark = PdfReader(\"watermark.pdf\").pages[0]\n\n# Apply to all pages\nreader = PdfReader(\"document.pdf\")\nwriter = PdfWriter()\n\nfor page in reader.pages:\n    page.merge_page(watermark)\n    writer.add_page(page)\n\nwith open(\"watermarked.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n### Extract Images\n```bash\n# Using pdfimages (poppler-utils)\npdfimages -j input.pdf output_prefix\n\n# This extracts all images as output_prefix-000.jpg, output_prefix-001.jpg, etc.\n```\n\n### Password Protection\n```python\nfrom pypdf import PdfReader, PdfWriter\n\nreader = PdfReader(\"input.pdf\")\nwriter = PdfWriter()\n\nfor page in reader.pages:\n    writer.add_page(page)\n\n# Add password\nwriter.encrypt(\"userpassword\", \"ownerpassword\")\n\nwith open(\"encrypted.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n## Quick Reference\n\n| Task | Best Tool | Command/Code |\n|------|-----------|--------------|\n| Merge PDFs | pypdf | `writer.add_page(page)` |\n| Split PDFs | pypdf | One page per file |\n| Extract text | pdfplumber | `page.extract_text()` |\n| Extract tables | pdfplumber | `page.extract_tables()` |\n| Create PDFs | reportlab | Canvas or Platypus |\n| Command line merge | qpdf | `qpdf --empty --pages ...` |\n| OCR scanned PDFs | pytesseract | Convert to image first |\n| Fill PDF forms | pdf-lib or pypdf (see FORMS.md) | See FORMS.md |\n\n## Next Steps\n\n- For advanced pypdfium2 usage, see REFERENCE.md\n- For JavaScript libraries (pdf-lib), see REFERENCE.md\n- If you need to fill out a PDF form, follow the instructions in FORMS.md\n- For troubleshooting guides, see REFERENCE.md\n","frontmatter":{"name":"pdf","description":"Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill.","license":"Proprietary. LICENSE.txt has complete terms"},"isInternal":false,"tokens":2079,"sizeBytes":8072},{"name":"SKILL.md","path":"resources/example-skills/pptx/SKILL.md","rawUrl":"https://raw.githubusercontent.com/eigent-ai/eigent/HEAD/resources/example-skills/pptx/SKILL.md","title":"pptx","category":"anthropic-skill","format":"markdown","content":"---\nname: pptx\ndescription: \"Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates, layouts, speaker notes, or comments. Trigger whenever the user mentions \\\"deck,\\\" \\\"slides,\\\" \\\"presentation,\\\" or references a .pptx filename, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# PPTX Skill\n\n## Quick Reference\n\n| Task | Guide |\n|------|-------|\n| Read/analyze content | `python -m markitdown presentation.pptx` |\n| Edit or create from template | Read [editing.md](editing.md) |\n| Create from scratch | Read [pptxgenjs.md](pptxgenjs.md) |\n\n---\n\n## Reading Content\n\n```bash\n# Text extraction\npython -m markitdown presentation.pptx\n\n# Visual overview\npython scripts/thumbnail.py presentation.pptx\n\n# Raw XML\npython scripts/office/unpack.py presentation.pptx unpacked/\n```\n\n---\n\n## Editing Workflow\n\n**Read [editing.md](editing.md) for full details.**\n\n1. Analyze template with `thumbnail.py`\n2. Unpack → manipulate slides → edit content → clean → pack\n\n---\n\n## Creating from Scratch\n\n**Read [pptxgenjs.md](pptxgenjs.md) for full details.**\n\nUse when no template or reference presentation is available.\n\n---\n\n## Design Ideas\n\n**Don't create boring slides.** Plain bullets on a white background won't impress anyone. Consider ideas from this list for each slide.\n\n### Before Starting\n\n- **Pick a bold, content-informed color palette**: The palette should feel designed for THIS topic. If swapping your colors into a completely different presentation would still \"work,\" you haven't made specific enough choices.\n- **Dominance over equality**: One color should dominate (60-70% visual weight), with 1-2 supporting tones and one sharp accent. Never give all colors equal weight.\n- **Dark/light contrast**: Dark backgrounds for title + conclusion slides, light for content (\"sandwich\" structure). Or commit to dark throughout for a premium feel.\n- **Commit to a visual motif**: Pick ONE distinctive element and repeat it — rounded image frames, icons in colored circles, thick single-side borders. Carry it across every slide.\n\n### Color Palettes\n\nChoose colors that match your topic — don't default to generic blue. Use these palettes as inspiration:\n\n| Theme | Primary | Secondary | Accent |\n|-------|---------|-----------|--------|\n| **Midnight Executive** | `1E2761` (navy) | `CADCFC` (ice blue) | `FFFFFF` (white) |\n| **Forest & Moss** | `2C5F2D` (forest) | `97BC62` (moss) | `F5F5F5` (cream) |\n| **Coral Energy** | `F96167` (coral) | `F9E795` (gold) | `2F3C7E` (navy) |\n| **Warm Terracotta** | `B85042` (terracotta) | `E7E8D1` (sand) | `A7BEAE` (sage) |\n| **Ocean Gradient** | `065A82` (deep blue) | `1C7293` (teal) | `21295C` (midnight) |\n| **Charcoal Minimal** | `36454F` (charcoal) | `F2F2F2` (off-white) | `212121` (black) |\n| **Teal Trust** | `028090` (teal) | `00A896` (seafoam) | `02C39A` (mint) |\n| **Berry & Cream** | `6D2E46` (berry) | `A26769` (dusty rose) | `ECE2D0` (cream) |\n| **Sage Calm** | `84B59F` (sage) | `69A297` (eucalyptus) | `50808E` (slate) |\n| **Cherry Bold** | `990011` (cherry) | `FCF6F5` (off-white) | `2F3C7E` (navy) |\n\n### For Each Slide\n\n**Every slide needs a visual element** — image, chart, icon, or shape. Text-only slides are forgettable.\n\n**Layout options:**\n- Two-column (text left, illustration on right)\n- Icon + text rows (icon in colored circle, bold header, description below)\n- 2x2 or 2x3 grid (image on one side, grid of content blocks on other)\n- Half-bleed image (full left or right side) with content overlay\n\n**Data display:**\n- Large stat callouts (big numbers 60-72pt with small labels below)\n- Comparison columns (before/after, pros/cons, side-by-side options)\n- Timeline or process flow (numbered steps, arrows)\n\n**Visual polish:**\n- Icons in small colored circles next to section headers\n- Italic accent text for key stats or taglines\n\n### Typography\n\n**Choose an interesting font pairing** — don't default to Arial. Pick a header font with personality and pair it with a clean body font.\n\n| Header Font | Body Font |\n|-------------|-----------|\n| Georgia | Calibri |\n| Arial Black | Arial |\n| Calibri | Calibri Light |\n| Cambria | Calibri |\n| Trebuchet MS | Calibri |\n| Impact | Arial |\n| Palatino | Garamond |\n| Consolas | Calibri |\n\n| Element | Size |\n|---------|------|\n| Slide title | 36-44pt bold |\n| Section header | 20-24pt bold |\n| Body text | 14-16pt |\n| Captions | 10-12pt muted |\n\n### Spacing\n\n- 0.5\" minimum margins\n- 0.3-0.5\" between content blocks\n- Leave breathing room—don't fill every inch\n\n### Avoid (Common Mistakes)\n\n- **Don't repeat the same layout** — vary columns, cards, and callouts across slides\n- **Don't center body text** — left-align paragraphs and lists; center only titles\n- **Don't skimp on size contrast** — titles need 36pt+ to stand out from 14-16pt body\n- **Don't default to blue** — pick colors that reflect the specific topic\n- **Don't mix spacing randomly** — choose 0.3\" or 0.5\" gaps and use consistently\n- **Don't style one slide and leave the rest plain** — commit fully or keep it simple throughout\n- **Don't create text-only slides** — add images, icons, charts, or visual elements; avoid plain title + bullets\n- **Don't forget text box padding** — when aligning lines or shapes with text edges, set `margin: 0` on the text box or offset the shape to account for padding\n- **Don't use low-contrast elements** — icons AND text need strong contrast against the background; avoid light text on light backgrounds or dark text on dark backgrounds\n- **NEVER use accent lines under titles** — these are a hallmark of AI-generated slides; use whitespace or background color instead\n\n---\n\n## QA (Required)\n\n**Assume there are problems. Your job is to find them.**\n\nYour first render is almost never correct. Approach QA as a bug hunt, not a confirmation step. If you found zero issues on first inspection, you weren't looking hard enough.\n\n### Content QA\n\n```bash\npython -m markitdown output.pptx\n```\n\nCheck for missing content, typos, wrong order.\n\n**When using templates, check for leftover placeholder text:**\n\n```bash\npython -m markitdown output.pptx | grep -iE \"xxxx|lorem|ipsum|this.*(page|slide).*layout\"\n```\n\nIf grep returns results, fix them before declaring success.\n\n### Visual QA\n\n### Verification Loop\n\n1. Generate slides → Convert to images → Inspect\n2. **List issues found** (if none found, look again more critically)\n3. Fix issues\n4. **Re-verify affected slides** — one fix often creates another problem\n5. Repeat until a full pass reveals no new issues\n\n**Do not declare success until you've completed at least one fix-and-verify cycle.**\n\n---\n\n## Converting to Images\n\nConvert presentations to individual slide images for visual inspection:\n\n```bash\npython scripts/office/soffice.py --headless --convert-to pdf output.pptx\npdftoppm -jpeg -r 150 output.pdf slide\n```\n\nThis creates `slide-01.jpg`, `slide-02.jpg`, etc.\n\nTo re-render specific slides after fixes:\n\n```bash\npdftoppm -jpeg -r 150 -f N -l N output.pdf slide-fixed\n```\n\n---\n\n## Dependencies\n\n- `pip install \"markitdown[pptx]\"` - text extraction\n- `pip install Pillow` - thumbnail grids\n- `npm install -g pptxgenjs` - creating from scratch\n- LibreOffice (`soffice`) - PDF conversion (auto-configured for sandboxed environments via `scripts/office/soffice.py`)\n- Poppler (`pdftoppm`) - PDF to images\n","frontmatter":{"name":"pptx","description":"Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates, layouts, speaker notes, or comments. Trigger whenever the user mentions \"deck,\" \"slides,\" \"presentation,\" or references a .pptx filename, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill.","license":"Proprietary. LICENSE.txt has complete terms"},"isInternal":false,"tokens":2087,"sizeBytes":7817},{"name":"output-patterns.md","path":"resources/example-skills/skill-creator/references/output-patterns.md","rawUrl":"https://raw.githubusercontent.com/eigent-ai/eigent/HEAD/resources/example-skills/skill-creator/references/output-patterns.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Output Patterns\n\nUse these patterns when skills need to produce consistent, high-quality output.\n\n## Template Pattern\n\nProvide templates for output format. Match the level of strictness to your needs.\n\n**For strict requirements (like API responses or data formats):**\n\n```markdown\n## Report structure\n\nALWAYS use this exact template structure:\n\n# [Analysis Title]\n\n## Executive summary\n[One-paragraph overview of key findings]\n\n## Key findings\n- Finding 1 with supporting data\n- Finding 2 with supporting data\n- Finding 3 with supporting data\n\n## Recommendations\n1. Specific actionable recommendation\n2. Specific actionable recommendation\n```\n\n**For flexible guidance (when adaptation is useful):**\n\n```markdown\n## Report structure\n\nHere is a sensible default format, but use your best judgment:\n\n# [Analysis Title]\n\n## Executive summary\n[Overview]\n\n## Key findings\n[Adapt sections based on what you discover]\n\n## Recommendations\n[Tailor to the specific context]\n\nAdjust sections as needed for the specific analysis type.\n```\n\n## Examples Pattern\n\nFor skills where output quality depends on seeing examples, provide input/output pairs:\n\n```markdown\n## Commit message format\n\nGenerate commit messages following these examples:\n\n**Example 1:**\nInput: Added user authentication with JWT tokens\nOutput:\n```\nfeat(auth): implement JWT-based authentication\n\nAdd login endpoint and token validation middleware\n```\n\n**Example 2:**\nInput: Fixed bug where dates displayed incorrectly in reports\nOutput:\n```\nfix(reports): correct date formatting in timezone conversion\n\nUse UTC timestamps consistently across report generation\n```\n\nFollow this style: type(scope): brief description, then detailed explanation.\n```\n\nExamples help the agent understand the desired style and level of detail more clearly than descriptions alone.\n","isInternal":false,"tokens":356,"sizeBytes":1816},{"name":"workflows.md","path":"resources/example-skills/skill-creator/references/workflows.md","rawUrl":"https://raw.githubusercontent.com/eigent-ai/eigent/HEAD/resources/example-skills/skill-creator/references/workflows.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Workflow Patterns\n\n## Sequential Workflows\n\nFor complex tasks, break operations into clear, sequential steps. It is often helpful to give the agent an overview of the process towards the beginning of SKILL.md:\n\n```markdown\nFilling a PDF form involves these steps:\n\n1. Analyze the form (run analyze_form.py)\n2. Create field mapping (edit fields.json)\n3. Validate mapping (run validate_fields.py)\n4. Fill the form (run fill_form.py)\n5. Verify output (run verify_output.py)\n```\n\n## Conditional Workflows\n\nFor tasks with branching logic, guide the agent through decision points:\n\n```markdown\n1. Determine the modification type:\n   **Creating new content?** → Follow \"Creation workflow\" below\n   **Editing existing content?** → Follow \"Editing workflow\" below\n\n2. Creation workflow: [steps]\n3. Editing workflow: [steps]\n```","isInternal":false,"tokens":184,"sizeBytes":824},{"name":"SKILL.md","path":"resources/example-skills/skill-creator/SKILL.md","rawUrl":"https://raw.githubusercontent.com/eigent-ai/eigent/HEAD/resources/example-skills/skill-creator/SKILL.md","title":"skill-creator","category":"anthropic-skill","format":"markdown","content":"---\nname: skill-creator\ndescription: Guide for creating effective skills. Use when creating a new skill or updating an existing skill that extends agent capabilities with specialized knowledge, workflows, or tool integrations.\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills.\n\n## About Skills\n\nSkills are modular, self-contained packages that extend agent capabilities by providing\nspecialized knowledge, workflows, and tools. Think of them as \"onboarding guides\" for specific\ndomains or tasks—they transform a general-purpose agent into a specialized agent\nequipped with procedural knowledge that no model can fully possess.\n\n### What Skills Provide\n\n1. Specialized workflows - Multi-step procedures for specific domains\n2. Tool integrations - Instructions for working with specific file formats or APIs\n3. Domain expertise - Company-specific knowledge, schemas, business logic\n4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks\n\n## Core Principles\n\n### Concise is Key\n\nThe context window is a public good. Skills share the context window with everything else the agent needs: system prompt, conversation history, other Skills' metadata, and the actual user request.\n\n**Default assumption: The agent is already very capable.** Only add context the agent doesn't already have. Challenge each piece of information: \"Does the agent really need this explanation?\" and \"Does this paragraph justify its token cost?\"\n\nPrefer concise examples over verbose explanations.\n\n### Set Appropriate Degrees of Freedom\n\nMatch the level of specificity to the task's fragility and variability:\n\n**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.\n\n**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.\n\n**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.\n\nThink of the agent exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).\n\n### Anatomy of a Skill\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   ├── description: (required)\n│   │   └── compatibility: (optional, rarely needed)\n│   └── Markdown instructions (required)\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n#### SKILL.md (required)\n\nEvery SKILL.md consists of:\n\n- **Frontmatter** (YAML): Contains `name` and `description` fields (required), plus optional fields like `license`, `metadata`, and `compatibility`. Only `name` and `description` are read by the agent to determine when the skill triggers, so be clear and comprehensive about what the skill is and when it should be used. The `compatibility` field is for noting environment requirements (target product, system packages, etc.) but most skills don't need it.\n- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).\n\n#### Bundled Resources (optional)\n\n##### Scripts (`scripts/`)\n\nExecutable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.\n\n- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed\n- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks\n- **Benefits**: Token efficient, deterministic, may be executed without loading into context\n- **Note**: Scripts may still need to be read by the agent for patching or environment-specific adjustments\n\n##### References (`references/`)\n\nDocumentation and reference material intended to be loaded as needed into context to inform the agent's process and thinking.\n\n- **When to include**: For documentation that the agent should reference while working\n- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications\n- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides\n- **Benefits**: Keeps SKILL.md lean, loaded only when the agent determines it's needed\n- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md\n- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.\n\n##### Assets (`assets/`)\n\nFiles not intended to be loaded into context, but rather used within the output the agent produces.\n\n- **When to include**: When the skill needs files that will be used in the final output\n- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography\n- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified\n- **Benefits**: Separates output resources from documentation, enables the agent to use files without loading them into context\n\n#### What to Not Include in a Skill\n\nA skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:\n\n- README.md\n- INSTALLATION_GUIDE.md\n- QUICK_REFERENCE.md\n- CHANGELOG.md\n- etc.\n\nThe skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxilary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.\n\n### Progressive Disclosure Design Principle\n\nSkills use a three-level loading system to manage context efficiently:\n\n1. **Metadata (name + description)** - Always in context (~100 words)\n2. **SKILL.md body** - When skill triggers (<5k words)\n3. **Bundled resources** - As needed by the agent (Unlimited because scripts can be executed without reading into context window)\n\n#### Progressive Disclosure Patterns\n\nKeep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.\n\n**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.\n\n**Pattern 1: High-level guide with references**\n\n```markdown\n# PDF Processing\n\n## Quick start\n\nExtract text with pdfplumber:\n[code example]\n\n## Advanced features\n\n- **Form filling**: See [FORMS.md](FORMS.md) for complete guide\n- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods\n- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns\n```\n\nThe agent loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.\n\n**Pattern 2: Domain-specific organization**\n\nFor Skills with multiple domains, organize content by domain to avoid loading irrelevant context:\n\n```\nbigquery-skill/\n├── SKILL.md (overview and navigation)\n└── reference/\n    ├── finance.md (revenue, billing metrics)\n    ├── sales.md (opportunities, pipeline)\n    ├── product.md (API usage, features)\n    └── marketing.md (campaigns, attribution)\n```\n\nWhen a user asks about sales metrics, the agent only reads sales.md.\n\nSimilarly, for skills supporting multiple frameworks or variants, organize by variant:\n\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md (AWS deployment patterns)\n    ├── gcp.md (GCP deployment patterns)\n    └── azure.md (Azure deployment patterns)\n```\n\nWhen the user chooses AWS, the agent only reads aws.md.\n\n**Pattern 3: Conditional details**\n\nShow basic content, link to advanced content:\n\n```markdown\n# DOCX Processing\n\n## Creating documents\n\nUse docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).\n\n## Editing documents\n\nFor simple edits, modify the XML directly.\n\n**For tracked changes**: See [REDLINING.md](REDLINING.md)\n**For OOXML details**: See [OOXML.md](OOXML.md)\n```\n\nThe agent reads REDLINING.md or OOXML.md only when the user needs those features.\n\n**Important guidelines:**\n\n- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.\n- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so the agent can see the full scope when previewing.\n\n## Skill Creation Process\n\nSkill creation involves these steps:\n\n1. Understand the skill with concrete examples\n2. Plan reusable skill contents (scripts, references, assets)\n3. Initialize the skill (run init_skill.py)\n4. Edit the skill (implement resources and write SKILL.md)\n5. Package the skill (run package_skill.py)\n6. Iterate based on real usage\n\nFollow these steps in order, skipping only if there is a clear reason why they are not applicable.\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.\n\n### Step 3: Initializing the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists, and iteration or packaging is needed. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage (run from the skill-creator skill directory):\n\n```bash\npython scripts/init_skill.py <skill-name> --path <output-directory>\n```\n\nNote: The scripts are located in this skill's `scripts/` directory. Use the full path if running from a different directory.\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Creates example resource directories: `scripts/`, `references/`, and `assets/`\n- Adds example files in each directory that can be customized or deleted\n\nAfter initialization, customize or remove the generated SKILL.md and example files as needed.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for an agent to use. Include information that would be beneficial and non-obvious to the agent. Consider what procedural knowledge, domain-specific details, or reusable assets would help the agent execute these tasks more effectively.\n\n#### Learn Proven Design Patterns\n\nConsult these helpful guides based on your skill's needs:\n\n- **Multi-step processes**: See references/workflows.md for sequential workflows and conditional logic\n- **Specific output formats or quality standards**: See references/output-patterns.md for template and example patterns\n\nThese files contain established best practices for effective skill design.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nAny example files and directories not needed for the skill should be deleted. The initialization script creates example files in `scripts/`, `references/`, and `assets/` to demonstrate structure, but most skills won't need all of them.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name` and `description`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps the agent understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to the agent.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when the agent needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n\nDo not include any other fields in YAML frontmatter.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n### Step 5: Packaging a Skill\n\nOnce development of the skill is complete, it must be packaged into a distributable .skill file that gets shared with the user. The packaging process automatically validates the skill first to ensure it meets all requirements.\n\nUsage (run from the skill-creator skill directory):\n\n```bash\npython scripts/package_skill.py <path/to/skill-folder>\n```\n\nOptional output directory specification:\n\n```bash\npython scripts/package_skill.py <path/to/skill-folder> ./dist\n```\n\nNote: The scripts are located in this skill's `scripts/` directory. Use the full path if running from a different directory.\n\nThe packaging script will:\n\n1. **Validate** the skill automatically, checking:\n   - YAML frontmatter format and required fields\n   - Skill naming conventions and directory structure\n   - Description completeness and quality\n   - File organization and resource references\n\n2. **Package** the skill if validation passes, creating a .skill file named after the skill (e.g., `my-skill.skill`) that includes all files and maintains the proper directory structure for distribution. The .skill file is a zip file with a .skill extension.\n\nIf validation fails, the script will report the errors and exit without creating a package. Fix any validation errors and run the packaging command again.\n\n### Step 6: Iterate\n\nAfter testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.\n\n**Iteration workflow:**\n\n1. Use the skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify how SKILL.md or bundled resources should be updated\n4. Implement changes and test again\n","frontmatter":{"name":"skill-creator","description":"Guide for creating effective skills. Use when creating a new skill or updating an existing skill that extends agent capabilities with specialized knowledge, workflows, or tool integrations.","license":"Proprietary. LICENSE.txt has complete terms"},"isInternal":false,"tokens":3789,"sizeBytes":18451},{"name":"secrets-patterns.md","path":"resources/example-skills/skill-security-auditor/references/secrets-patterns.md","rawUrl":"https://raw.githubusercontent.com/eigent-ai/eigent/HEAD/resources/example-skills/skill-security-auditor/references/secrets-patterns.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Secrets Detection Patterns\n\nRegex patterns and rules for detecting hardcoded secrets, credentials, and sensitive data in source code.\n\n## Table of Contents\n\n- [API Keys and Tokens](#api-keys-and-tokens)\n- [Cloud Provider Credentials](#cloud-provider-credentials)\n- [Database Connection Strings](#database-connection-strings)\n- [Private Keys and Certificates](#private-keys-and-certificates)\n- [Generic Patterns](#generic-patterns)\n- [Files to Always Check](#files-to-always-check)\n- [False Positive Reduction](#false-positive-reduction)\n\n## API Keys and Tokens\n\n| Service | Pattern | Example |\n|---------|---------|---------|\n| AWS Access Key | `AKIA[0-9A-Z]{16}` | AKIAIOSFODNN7EXAMPLE |\n| AWS Secret Key | `(?i)aws_secret_access_key\\s*=\\s*\\S{40}` | |\n| GitHub Token | `gh[ps]_[A-Za-z0-9_]{36,}` | ghp_xxxxxxxxxxxx |\n| GitHub Fine-grained | `github_pat_[A-Za-z0-9_]{22,}` | |\n| GitLab Token | `glpat-[A-Za-z0-9\\-]{20,}` | |\n| Slack Token | `xox[baprs]-[A-Za-z0-9\\-]{10,}` | |\n| Slack Webhook | `https://hooks\\.slack\\.com/services/T[A-Z0-9]+/B[A-Z0-9]+/[A-Za-z0-9]+` | |\n| Stripe Secret | `sk_live_[A-Za-z0-9]{24,}` | |\n| Stripe Publishable | `pk_live_[A-Za-z0-9]{24,}` | |\n| Twilio | `SK[0-9a-fA-F]{32}` | |\n| SendGrid | `SG\\.[A-Za-z0-9\\-_]{22}\\.[A-Za-z0-9\\-_]{43}` | |\n| Mailgun | `key-[0-9a-zA-Z]{32}` | |\n| Google API Key | `AIza[0-9A-Za-z\\-_]{35}` | |\n| Google OAuth | `[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com` | |\n| Heroku API Key | `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}` | |\n| npm Token | `npm_[A-Za-z0-9]{36}` | |\n| PyPI Token | `pypi-[A-Za-z0-9\\-_]{50,}` | |\n\n## Cloud Provider Credentials\n\n### AWS\n```\n# Access Key ID\nAKIA[0-9A-Z]{16}\n\n# Secret Access Key (in config context)\n(?i)(aws_secret_access_key|aws_secret_key)\\s*[=:]\\s*[A-Za-z0-9/+=]{40}\n\n# Session Token\n(?i)aws_session_token\\s*[=:]\\s*\\S+\n```\n\n### GCP\n```\n# Service account key file indicators\n\"type\"\\s*:\\s*\"service_account\"\n\"private_key\"\\s*:\\s*\"-----BEGIN\n\n# OAuth client secret\n(?i)client_secret\\s*[=:]\\s*\\S+\n```\n\n### Azure\n```\n# Storage account key\n(?i)(AccountKey|account_key)\\s*[=:]\\s*[A-Za-z0-9+/=]{86,}\n\n# Connection strings\n(?i)(DefaultEndpointsProtocol|AccountName|AccountKey)=[^;\\s]+\n```\n\n## Database Connection Strings\n\n```\n# Generic with embedded password\n(?i)(mysql|postgres|postgresql|mongodb|redis|mssql|sqlserver)://[^:]+:[^@]+@\n\n# Django DATABASE_URL\n(?i)DATABASE_URL\\s*=\\s*\\S+://\\S+:\\S+@\n\n# JDBC with password\n(?i)jdbc:[a-z]+://[^;]+password=[^;\\s]+\n```\n\n## Private Keys and Certificates\n\n```\n# RSA private key\n-----BEGIN RSA PRIVATE KEY-----\n\n# Generic private key\n-----BEGIN PRIVATE KEY-----\n\n# EC private key\n-----BEGIN EC PRIVATE KEY-----\n\n# OpenSSH private key\n-----BEGIN OPENSSH PRIVATE KEY-----\n\n# PGP private key\n-----BEGIN PGP PRIVATE KEY BLOCK-----\n\n# Certificate (not a secret, but may indicate key nearby)\n-----BEGIN CERTIFICATE-----\n```\n\n## Generic Patterns\n\nThese catch secrets not covered by service-specific patterns:\n\n```\n# Assignment patterns with secret-like variable names\n(?i)(password|passwd|pwd|secret|token|api_key|apikey|api_secret|access_key|auth_token|credentials)\\s*[=:]\\s*['\"][^'\"]{8,}['\"]\n\n# Bearer tokens in code\n(?i)bearer\\s+[A-Za-z0-9\\-._~+/]+=*\n\n# Base64 encoded secrets (high entropy, 20+ chars)\n(?i)(secret|key|token|password)\\s*[=:]\\s*['\"][A-Za-z0-9+/]{20,}={0,2}['\"]\n\n# Hex-encoded secrets (32+ chars)\n(?i)(secret|key|token)\\s*[=:]\\s*['\"][0-9a-fA-F]{32,}['\"]\n```\n\n## Files to Always Check\n\n**High priority** (most likely to contain secrets):\n```\n.env, .env.*, .env.local, .env.production\nconfig.json, config.yaml, config.yml, config.toml\nsettings.py, settings.json\napplication.properties, application.yml\ndocker-compose.yml, docker-compose.*.yml\n.aws/credentials, .boto\n.netrc, .npmrc, .pypirc\nid_rsa, id_ecdsa, id_ed25519, *.pem, *.key\n```\n\n**Check .gitignore coverage**: Ensure these files are listed in `.gitignore`. If they are tracked by git, flag as a finding.\n\n**Git history**: Secrets may have been committed and later removed. Check with:\n```bash\ngit log --all --diff-filter=D -- \"*.env\" \"*.pem\" \"*.key\"\ngit log --all -p -S \"AKIA\" -- . # Search for AWS keys in history\n```\n\n## False Positive Reduction\n\nSkip matches that are likely not real secrets:\n- Values containing only placeholder text: `example`, `changeme`, `TODO`, `xxx`, `your_`, `placeholder`, `dummy`, `test`, `sample`\n- Values from documentation or comments on the same line as `example`, `e.g.`, `doc`, `TODO`\n- Values in test files matching `*_test.*`, `test_*.*`, `*.spec.*`, `**/test/**`, `**/tests/**`, `**/__tests__/**`\n- Environment variable references: `${VAR}`, `$VAR`, `%VAR%`, `os.environ`, `process.env`\n- Empty or whitespace-only values\n","isInternal":false,"tokens":1506,"sizeBytes":4703},{"name":"vulnerability-patterns.md","path":"resources/example-skills/skill-security-auditor/references/vulnerability-patterns.md","rawUrl":"https://raw.githubusercontent.com/eigent-ai/eigent/HEAD/resources/example-skills/skill-security-auditor/references/vulnerability-patterns.md","title":"References Skill","category":"anthropic-skill","format":"markdown","content":"# Vulnerability Patterns Reference\n\nDetailed patterns for identifying security vulnerabilities across languages and frameworks.\n\n## Table of Contents\n\n- [Injection Vulnerabilities](#injection-vulnerabilities)\n- [Authentication and Session Issues](#authentication-and-session-issues)\n- [Cryptographic Weaknesses](#cryptographic-weaknesses)\n- [Insecure Deserialization](#insecure-deserialization)\n- [Server-Side Request Forgery](#server-side-request-forgery)\n- [File Operations](#file-operations)\n- [Framework-Specific Patterns](#framework-specific-patterns)\n\n## Injection Vulnerabilities\n\n### SQL Injection\n\n**Vulnerable patterns** (string concatenation or f-strings in queries):\n```\n# Python\nexecute(f\"...{var}...\")\nexecute(\"...\" + var + \"...\")\nexecute(\"...%s...\" % var)\n\n# JavaScript\nquery(`...${var}...`)\nquery(\"...\" + var + \"...\")\n\n# Go\ndb.Query(\"...\" + var + \"...\")\nfmt.Sprintf(\"SELECT ... %s\", var) passed to Query()\n\n# Java\nstatement.execute(\"...\" + var + \"...\")\n```\n\n**Safe alternatives**: Parameterized queries, prepared statements, ORM query builders.\n\n### NoSQL Injection\n\n**Vulnerable patterns**:\n```javascript\n// MongoDB: user input directly in query object\ndb.collection.find({ user: req.body.user, pass: req.body.pass })\n// Attacker sends: { \"pass\": { \"$gt\": \"\" } }\n```\n\n**Safe alternative**: Validate input types, use `$eq` explicitly, sanitize with libraries like `mongo-sanitize`.\n\n### Command Injection\n\n**Vulnerable functions by language**:\n```\nPython:  os.system(), os.popen(), subprocess.call(shell=True), subprocess.Popen(shell=True)\nNode.js: child_process.exec(), child_process.execSync()\nGo:      exec.Command(\"sh\", \"-c\", userInput)\nJava:    Runtime.exec(userInput)\nPHP:     exec(), system(), passthru(), shell_exec(), backticks\nRuby:    system(), exec(), backticks, %x{}\n```\n\n**Safe alternative**: Use subprocess with list arguments (no shell), validate and allowlist input values.\n\n### LDAP Injection\n\n**Vulnerable pattern**:\n```python\nldap.search_s(base, scope, f\"(uid={username})\")\n```\n\n**Safe alternative**: Escape special characters `()*\\` and null bytes in user input.\n\n### XSS (Cross-Site Scripting)\n\n**Vulnerable sinks**:\n```\nJavaScript: innerHTML, outerHTML, document.write(), eval(), v-html, dangerouslySetInnerHTML\nTemplate:   |safe, {% autoescape off %}, !=, !{}, {!! !!}\n```\n\n**Safe alternatives**: Use `textContent`, template auto-escaping, CSP headers, DOMPurify for required HTML.\n\n## Authentication and Session Issues\n\n### Weak Password Storage\n\n**Vulnerable**:\n```python\n# Plaintext or weak hashing\nhashlib.md5(password.encode()).hexdigest()\nhashlib.sha256(password.encode()).hexdigest()\n```\n\n**Safe**:\n```python\n# Use adaptive hashing with salt\nimport bcrypt\nhashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))\n```\n\n### JWT Vulnerabilities\n\n**Common issues**:\n- Accepting `alg: \"none\"`\n- Using symmetric algorithms (HS256) with public keys\n- Not validating expiry (`exp`) or issuer (`iss`)\n- Storing sensitive data in payload (JWT is base64, not encrypted)\n\n**Verification checklist**:\n```python\n# Ensure algorithm is explicitly specified\njwt.decode(token, key, algorithms=[\"RS256\"])  # explicit algorithm\njwt.decode(token, key)  # VULNERABLE: accepts any algorithm\n```\n\n### Session Management\n\n**Issues to flag**:\n- Session IDs in URLs\n- Missing `HttpOnly`, `Secure`, `SameSite` flags on session cookies\n- No session timeout or rotation after authentication\n- Predictable session identifiers\n\n## Cryptographic Weaknesses\n\n### Insecure Algorithms\n\n**Deprecated/broken** (flag if found):\n```\nHash:    MD5, SHA1 (for security purposes)\nCipher:  DES, 3DES, RC4, Blowfish\nMode:    ECB mode for any block cipher\nRSA:     Key size < 2048 bits\n```\n\n**Acceptable**:\n```\nHash:    SHA-256, SHA-384, SHA-512, BLAKE2\nCipher:  AES-128/256-GCM, ChaCha20-Poly1305\nRSA:     2048+ bits with OAEP padding\nECDSA:   P-256 or P-384 curves\n```\n\n### Hardcoded Cryptographic Material\n\n**Flag if found in source**:\n- Encryption keys, IV/nonce values\n- Private keys (RSA, ECDSA, Ed25519)\n- Salt values for password hashing\n\n## Insecure Deserialization\n\n**Vulnerable functions by language**:\n```\nPython:  pickle.loads(), yaml.load() (without SafeLoader), marshal.loads()\nJava:    ObjectInputStream.readObject(), XMLDecoder\nPHP:     unserialize()\nRuby:    Marshal.load(), YAML.load()\nNode.js: node-serialize, js-yaml.load() (with dangerous schema)\n```\n\n**Safe alternatives**: Use JSON for data exchange, use safe loaders (`yaml.safe_load()`), validate and type-check deserialized data.\n\n## Server-Side Request Forgery\n\n**Vulnerable pattern**:\n```python\n# User controls the URL\nrequests.get(user_provided_url)\nurllib.request.urlopen(user_provided_url)\n```\n\n**Mitigations**:\n- Validate URLs against an allowlist of domains/IPs\n- Block requests to internal/private IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, 169.254.x)\n- Disable redirects or validate redirect targets\n- Use a network-level firewall for outbound requests\n\n## File Operations\n\n### Path Traversal\n\n**Vulnerable pattern**:\n```python\n# User controls filename\nopen(os.path.join(base_dir, user_filename))\n```\n\n**Safe pattern**:\n```python\nimport pathlib\nbase = pathlib.Path(base_dir).resolve()\ntarget = (base / user_filename).resolve()\nif not str(target).startswith(str(base)):\n    raise ValueError(\"Path traversal detected\")\n```\n\n### Unrestricted File Upload\n\n**Checklist**:\n- Validate file type by content (magic bytes), not just extension\n- Enforce maximum file size limits\n- Store uploads outside the web root\n- Generate random filenames, do not use user-supplied names\n- Scan uploads for malware when possible\n\n## Framework-Specific Patterns\n\n### Django\n\n```python\n# Dangerous: raw SQL\nModel.objects.raw(f\"SELECT * FROM t WHERE id = {user_id}\")\n# Safe: ORM or parameterized raw\nModel.objects.filter(id=user_id)\nModel.objects.raw(\"SELECT * FROM t WHERE id = %s\", [user_id])\n\n# Check settings.py\nDEBUG = True                      # Must be False in production\nALLOWED_HOSTS = ['*']            # Must be restricted\nCSRF_COOKIE_SECURE = False       # Must be True with HTTPS\nSESSION_COOKIE_SECURE = False    # Must be True with HTTPS\n```\n\n### Flask\n\n```python\n# Dangerous: XSS via Markup\nfrom markupsafe import Markup\nreturn Markup(f\"<p>{user_input}</p>\")\n# Safe: Use templates with auto-escaping\nreturn render_template(\"page.html\", data=user_input)\n\n# Check for debug mode\napp.run(debug=True)  # Must be False in production\n```\n\n### Express.js\n\n```javascript\n// Missing security headers - use helmet\nconst helmet = require('helmet');\napp.use(helmet());\n\n// Missing CSRF protection on state-changing routes\n// Missing rate limiting on auth endpoints\n// Missing input validation (use express-validator or zod)\n```\n\n### Spring Boot\n\n```java\n// Dangerous: SpEL injection\nparser.parseExpression(userInput).getValue();\n\n// Check application.properties\nserver.error.include-stacktrace=always  // Leaks internals\nmanagement.endpoints.web.exposure.include=*  // Exposes actuator\n```\n","isInternal":false,"tokens":1685,"sizeBytes":6970},{"name":"SKILL.md","path":"resources/example-skills/skill-security-auditor/SKILL.md","rawUrl":"https://raw.githubusercontent.com/eigent-ai/eigent/HEAD/resources/example-skills/skill-security-auditor/SKILL.md","title":"skill-security-auditor","category":"anthropic-skill","format":"markdown","content":"---\nname: skill-security-auditor\ndescription: \"Security auditing for code, configs, and infrastructure. Use when the user wants to audit or improve security: scan for vulnerabilities (SQL injection, XSS, command injection, path traversal), detect hardcoded secrets and credentials, review auth and authorization, check dependencies for known CVEs, audit config files for insecure defaults, or generate security reports. Trigger on \\\"security audit\\\", \\\"vulnerability scan\\\", \\\"code review for security\\\", \\\"find secrets\\\", \\\"check for vulnerabilities\\\", \\\"OWASP\\\", \\\"CVE\\\", or questions about code security.\"\nlicense: Complete terms in LICENSE.txt\n---\n\n# Security Auditor Guide\n\n## Overview\n\nThis guide covers security auditing workflows for source code, dependencies, and configurations. For detailed vulnerability patterns and detection rules, see references/vulnerability-patterns.md. For secrets detection patterns, see references/secrets-patterns.md.\n\n## Quick Start\n\nRun the bundled scan script against a project directory:\n\n```bash\npython scripts/scan_project.py /path/to/project\n```\n\nThis performs a lightweight scan for common issues: hardcoded secrets, dangerous function calls, and insecure patterns. For deeper analysis, follow the workflows below.\n\n### Testing the scripts\n\n```bash\npython scripts/scan_project.py /path/to/some/project --format text\npython scripts/scan_secrets.py /path/to/some/project --format text\n```\n\n## Audit Workflow\n\n### 1. Reconnaissance\n\nBefore auditing, understand the project:\n\n```bash\n# Identify languages, frameworks, and entry points\nfind . -type f -name \"*.py\" -o -name \"*.js\" -o -name \"*.ts\" -o -name \"*.go\" -o -name \"*.java\" | head -20\ncat package.json pyproject.toml requirements.txt go.mod pom.xml 2>/dev/null\n```\n\nKey questions:\n- What frameworks are used? (Express, Django, Flask, Spring, etc.)\n- Where are the entry points? (routes, controllers, API handlers)\n- How is authentication handled?\n- What external services are called?\n- Is user input accepted? Where?\n\n### 2. Secrets Detection\n\nScan for hardcoded credentials, API keys, and tokens. See references/secrets-patterns.md for the full pattern list.\n\n```bash\npython scripts/scan_secrets.py /path/to/project\n```\n\nCommon patterns to check:\n- API keys and tokens in source files\n- Database connection strings with embedded passwords\n- Private keys or certificates committed to the repo\n- `.env` files or config files with plaintext secrets\n- Secrets in CI/CD configuration files\n\n### 3. Vulnerability Scanning\n\n#### OWASP Top 10 Checklist\n\n| # | Category | What to Look For |\n|---|----------|-----------------|\n| A01 | Broken Access Control | Missing auth checks, IDOR, privilege escalation |\n| A02 | Cryptographic Failures | Weak algorithms, plaintext storage, missing TLS |\n| A03 | Injection | SQL, NoSQL, OS command, LDAP, XSS |\n| A04 | Insecure Design | Missing rate limits, business logic flaws |\n| A05 | Security Misconfiguration | Debug mode, default credentials, verbose errors |\n| A06 | Vulnerable Components | Outdated dependencies with known CVEs |\n| A07 | Auth Failures | Weak passwords, missing MFA, session issues |\n| A08 | Data Integrity Failures | Insecure deserialization, unsigned updates |\n| A09 | Logging Failures | Missing audit logs, sensitive data in logs |\n| A10 | SSRF | Unvalidated URLs in server-side requests |\n\n#### Language-Specific Checks\n\n**Python**\n```python\n# Dangerous: SQL injection\ncursor.execute(f\"SELECT * FROM users WHERE id = {user_id}\")\n# Safe: Parameterized query\ncursor.execute(\"SELECT * FROM users WHERE id = %s\", (user_id,))\n\n# Dangerous: Command injection\nos.system(f\"ping {hostname}\")\n# Safe: Use subprocess with list args\nsubprocess.run([\"ping\", hostname], capture_output=True)\n\n# Dangerous: Path traversal\nopen(f\"/data/{user_input}\")\n# Safe: Validate and resolve path\npath = pathlib.Path(\"/data\") / user_input\npath.resolve().relative_to(pathlib.Path(\"/data\").resolve())\n```\n\n**JavaScript/TypeScript**\n```javascript\n// Dangerous: XSS via innerHTML\nelement.innerHTML = userInput;\n// Safe: Use textContent or sanitize\nelement.textContent = userInput;\n\n// Dangerous: Prototype pollution\nObject.assign(target, JSON.parse(userInput));\n// Safe: Validate input structure\nconst parsed = JSON.parse(userInput);\nif (typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error();\nconst sanitized = Object.fromEntries(\n  Object.entries(parsed).filter(([k]) => !k.startsWith('__'))\n);\n\n// Dangerous: eval or Function constructor\neval(userInput);\n// Safe: Never use eval with user input\n```\n\n**Go**\n```go\n// Dangerous: SQL injection\ndb.Query(\"SELECT * FROM users WHERE id = \" + id)\n// Safe: Parameterized query\ndb.Query(\"SELECT * FROM users WHERE id = $1\", id)\n\n// Dangerous: Path traversal\nhttp.ServeFile(w, r, filepath.Join(baseDir, r.URL.Path))\n// Safe: Clean and validate path\ncleaned := filepath.Clean(r.URL.Path)\nfull := filepath.Join(baseDir, cleaned)\nif !strings.HasPrefix(full, baseDir) { http.Error(...) }\n```\n\n### 4. Dependency Audit\n\nCheck for known vulnerabilities in project dependencies:\n\n```bash\n# Python\npip audit\nsafety check -r requirements.txt\n\n# Node.js\nnpm audit\nnpx auditjs ossi\n\n# Go\ngovulncheck ./...\n\n# General (if Trivy is available)\ntrivy fs --scanners vuln /path/to/project\n```\n\nReview the output and categorize by severity (critical, high, medium, low). Critical and high severity findings should be addressed before deployment.\n\n### 5. Configuration Review\n\nCheck for insecure defaults in configuration files:\n\n```yaml\n# Common misconfigurations to flag:\nDEBUG: true                    # Debug mode in production\nALLOWED_HOSTS: [\"*\"]          # Unrestricted host access\nCORS_ALLOW_ALL_ORIGINS: true  # Open CORS policy\nSECRET_KEY: \"default\"         # Default or weak secret key\nSSL_VERIFY: false             # Disabled TLS verification\n```\n\nCheck infrastructure configs:\n- Dockerfiles: Running as root, exposing unnecessary ports\n- CI/CD: Secrets in plaintext, overly permissive permissions\n- Cloud configs: Public S3 buckets, open security groups\n\n### 6. Authentication and Authorization Review\n\nKey areas to verify:\n- Password hashing uses strong algorithms (bcrypt, argon2, scrypt)\n- Sessions have appropriate timeouts and rotation\n- JWT tokens are validated properly (algorithm, expiry, signature)\n- API endpoints enforce authorization checks\n- Role-based access control is consistently applied\n- Rate limiting is in place for login and sensitive endpoints\n\n## Report Format\n\nWhen generating a security audit report, use this structure:\n\n```markdown\n# Security Audit Report\n\n## Summary\n- **Project**: [name]\n- **Date**: [date]\n- **Scope**: [what was audited]\n- **Risk Level**: [Critical/High/Medium/Low]\n\n## Findings\n\n### [SEVERITY] Finding Title\n- **Category**: [OWASP category]\n- **Location**: [file:line]\n- **Description**: [what the issue is]\n- **Impact**: [what could happen if exploited]\n- **Recommendation**: [how to fix]\n\n## Statistics\n- Total findings: [count]\n- Critical: [count] | High: [count] | Medium: [count] | Low: [count]\n```\n\n## Next Steps\n\n- For detailed vulnerability patterns and code examples, see references/vulnerability-patterns.md\n- For secrets detection regex patterns, see references/secrets-patterns.md\n","frontmatter":{"name":"skill-security-auditor","description":"Security auditing for code, configs, and infrastructure. Use when the user wants to audit or improve security: scan for vulnerabilities (SQL injection, XSS, command injection, path traversal), detect hardcoded secrets and credentials, review auth and authorization, check dependencies for known CVEs, audit config files for insecure defaults, or generate security reports. Trigger on \"security audit\", \"vulnerability scan\", \"code review for security\", \"find secrets\", \"check for vulnerabilities\", \"OWASP\", \"CVE\", or questions about code security.","license":"Complete terms in LICENSE.txt"},"isInternal":false,"tokens":1643,"sizeBytes":7215},{"name":"SKILL.md","path":"resources/example-skills/xlsx/SKILL.md","rawUrl":"https://raw.githubusercontent.com/eigent-ai/eigent/HEAD/resources/example-skills/xlsx/SKILL.md","title":"xlsx","category":"anthropic-skill","format":"markdown","content":"---\nname: xlsx\ndescription: \"Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like \\\"the xlsx in my downloads\\\") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# Requirements for Outputs\n\n## All Excel files\n\n### Professional Font\n- Use a consistent, professional font (e.g., Arial, Times New Roman) for all deliverables unless otherwise instructed by the user\n\n### Zero Formula Errors\n- Every Excel model MUST be delivered with ZERO formula errors (#REF!, #DIV/0!, #VALUE!, #N/A, #NAME?)\n\n### Preserve Existing Templates (when updating templates)\n- Study and EXACTLY match existing format, style, and conventions when modifying files\n- Never impose standardized formatting on files with established patterns\n- Existing template conventions ALWAYS override these guidelines\n\n## Financial models\n\n### Color Coding Standards\nUnless otherwise stated by the user or existing template\n\n#### Industry-Standard Color Conventions\n- **Blue text (RGB: 0,0,255)**: Hardcoded inputs, and numbers users will change for scenarios\n- **Black text (RGB: 0,0,0)**: ALL formulas and calculations\n- **Green text (RGB: 0,128,0)**: Links pulling from other worksheets within same workbook\n- **Red text (RGB: 255,0,0)**: External links to other files\n- **Yellow background (RGB: 255,255,0)**: Key assumptions needing attention or cells that need to be updated\n\n### Number Formatting Standards\n\n#### Required Format Rules\n- **Years**: Format as text strings (e.g., \"2024\" not \"2,024\")\n- **Currency**: Use $#,##0 format; ALWAYS specify units in headers (\"Revenue ($mm)\")\n- **Zeros**: Use number formatting to make all zeros \"-\", including percentages (e.g., \"$#,##0;($#,##0);-\")\n- **Percentages**: Default to 0.0% format (one decimal)\n- **Multiples**: Format as 0.0x for valuation multiples (EV/EBITDA, P/E)\n- **Negative numbers**: Use parentheses (123) not minus -123\n\n### Formula Construction Rules\n\n#### Assumptions Placement\n- Place ALL assumptions (growth rates, margins, multiples, etc.) in separate assumption cells\n- Use cell references instead of hardcoded values in formulas\n- Example: Use =B5*(1+$B$6) instead of =B5*1.05\n\n#### Formula Error Prevention\n- Verify all cell references are correct\n- Check for off-by-one errors in ranges\n- Ensure consistent formulas across all projection periods\n- Test with edge cases (zero values, negative numbers)\n- Verify no unintended circular references\n\n#### Documentation Requirements for Hardcodes\n- Comment or in cells beside (if end of table). Format: \"Source: [System/Document], [Date], [Specific Reference], [URL if applicable]\"\n- Examples:\n  - \"Source: Company 10-K, FY2024, Page 45, Revenue Note, [SEC EDGAR URL]\"\n  - \"Source: Company 10-Q, Q2 2025, Exhibit 99.1, [SEC EDGAR URL]\"\n  - \"Source: Bloomberg Terminal, 8/15/2025, AAPL US Equity\"\n  - \"Source: FactSet, 8/20/2025, Consensus Estimates Screen\"\n\n# XLSX creation, editing, and analysis\n\n## Overview\n\nA user may ask you to create, edit, or analyze the contents of an .xlsx file. You have different tools and workflows available for different tasks.\n\n## Important Requirements\n\n**LibreOffice Required for Formula Recalculation**: You can assume LibreOffice is installed for recalculating formula values using the `scripts/recalc.py` script. The script automatically configures LibreOffice on first run, including in sandboxed environments where Unix sockets are restricted (handled by `scripts/office/soffice.py`)\n\n## Reading and analyzing data\n\n### Data analysis with pandas\nFor data analysis, visualization, and basic operations, use **pandas** which provides powerful data manipulation capabilities:\n\n```python\nimport pandas as pd\n\n# Read Excel\ndf = pd.read_excel('file.xlsx')  # Default: first sheet\nall_sheets = pd.read_excel('file.xlsx', sheet_name=None)  # All sheets as dict\n\n# Analyze\ndf.head()      # Preview data\ndf.info()      # Column info\ndf.describe()  # Statistics\n\n# Write Excel\ndf.to_excel('output.xlsx', index=False)\n```\n\n## Excel File Workflows\n\n## CRITICAL: Use Formulas, Not Hardcoded Values\n\n**Always use Excel formulas instead of calculating values in Python and hardcoding them.** This ensures the spreadsheet remains dynamic and updateable.\n\n### ❌ WRONG - Hardcoding Calculated Values\n```python\n# Bad: Calculating in Python and hardcoding result\ntotal = df['Sales'].sum()\nsheet['B10'] = total  # Hardcodes 5000\n\n# Bad: Computing growth rate in Python\ngrowth = (df.iloc[-1]['Revenue'] - df.iloc[0]['Revenue']) / df.iloc[0]['Revenue']\nsheet['C5'] = growth  # Hardcodes 0.15\n\n# Bad: Python calculation for average\navg = sum(values) / len(values)\nsheet['D20'] = avg  # Hardcodes 42.5\n```\n\n### ✅ CORRECT - Using Excel Formulas\n```python\n# Good: Let Excel calculate the sum\nsheet['B10'] = '=SUM(B2:B9)'\n\n# Good: Growth rate as Excel formula\nsheet['C5'] = '=(C4-C2)/C2'\n\n# Good: Average using Excel function\nsheet['D20'] = '=AVERAGE(D2:D19)'\n```\n\nThis applies to ALL calculations - totals, percentages, ratios, differences, etc. The spreadsheet should be able to recalculate when source data changes.\n\n## Common Workflow\n1. **Choose tool**: pandas for data, openpyxl for formulas/formatting\n2. **Create/Load**: Create new workbook or load existing file\n3. **Modify**: Add/edit data, formulas, and formatting\n4. **Save**: Write to file\n5. **Recalculate formulas (MANDATORY IF USING FORMULAS)**: Use the scripts/recalc.py script\n   ```bash\n   python scripts/recalc.py output.xlsx\n   ```\n6. **Verify and fix any errors**: \n   - The script returns JSON with error details\n   - If `status` is `errors_found`, check `error_summary` for specific error types and locations\n   - Fix the identified errors and recalculate again\n   - Common errors to fix:\n     - `#REF!`: Invalid cell references\n     - `#DIV/0!`: Division by zero\n     - `#VALUE!`: Wrong data type in formula\n     - `#NAME?`: Unrecognized formula name\n\n### Creating new Excel files\n\n```python\n# Using openpyxl for formulas and formatting\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font, PatternFill, Alignment\n\nwb = Workbook()\nsheet = wb.active\n\n# Add data\nsheet['A1'] = 'Hello'\nsheet['B1'] = 'World'\nsheet.append(['Row', 'of', 'data'])\n\n# Add formula\nsheet['B2'] = '=SUM(A1:A10)'\n\n# Formatting\nsheet['A1'].font = Font(bold=True, color='FF0000')\nsheet['A1'].fill = PatternFill('solid', start_color='FFFF00')\nsheet['A1'].alignment = Alignment(horizontal='center')\n\n# Column width\nsheet.column_dimensions['A'].width = 20\n\nwb.save('output.xlsx')\n```\n\n### Editing existing Excel files\n\n```python\n# Using openpyxl to preserve formulas and formatting\nfrom openpyxl import load_workbook\n\n# Load existing file\nwb = load_workbook('existing.xlsx')\nsheet = wb.active  # or wb['SheetName'] for specific sheet\n\n# Working with multiple sheets\nfor sheet_name in wb.sheetnames:\n    sheet = wb[sheet_name]\n    print(f\"Sheet: {sheet_name}\")\n\n# Modify cells\nsheet['A1'] = 'New Value'\nsheet.insert_rows(2)  # Insert row at position 2\nsheet.delete_cols(3)  # Delete column 3\n\n# Add new sheet\nnew_sheet = wb.create_sheet('NewSheet')\nnew_sheet['A1'] = 'Data'\n\nwb.save('modified.xlsx')\n```\n\n## Recalculating formulas\n\nExcel files created or modified by openpyxl contain formulas as strings but not calculated values. Use the provided `scripts/recalc.py` script to recalculate formulas:\n\n```bash\npython scripts/recalc.py <excel_file> [timeout_seconds]\n```\n\nExample:\n```bash\npython scripts/recalc.py output.xlsx 30\n```\n\nThe script:\n- Automatically sets up LibreOffice macro on first run\n- Recalculates all formulas in all sheets\n- Scans ALL cells for Excel errors (#REF!, #DIV/0!, etc.)\n- Returns JSON with detailed error locations and counts\n- Works on both Linux and macOS\n\n## Formula Verification Checklist\n\nQuick checks to ensure formulas work correctly:\n\n### Essential Verification\n- [ ] **Test 2-3 sample references**: Verify they pull correct values before building full model\n- [ ] **Column mapping**: Confirm Excel columns match (e.g., column 64 = BL, not BK)\n- [ ] **Row offset**: Remember Excel rows are 1-indexed (DataFrame row 5 = Excel row 6)\n\n### Common Pitfalls\n- [ ] **NaN handling**: Check for null values with `pd.notna()`\n- [ ] **Far-right columns**: FY data often in columns 50+ \n- [ ] **Multiple matches**: Search all occurrences, not just first\n- [ ] **Division by zero**: Check denominators before using `/` in formulas (#DIV/0!)\n- [ ] **Wrong references**: Verify all cell references point to intended cells (#REF!)\n- [ ] **Cross-sheet references**: Use correct format (Sheet1!A1) for linking sheets\n\n### Formula Testing Strategy\n- [ ] **Start small**: Test formulas on 2-3 cells before applying broadly\n- [ ] **Verify dependencies**: Check all cells referenced in formulas exist\n- [ ] **Test edge cases**: Include zero, negative, and very large values\n\n### Interpreting scripts/recalc.py Output\nThe script returns JSON with error details:\n```json\n{\n  \"status\": \"success\",           // or \"errors_found\"\n  \"total_errors\": 0,              // Total error count\n  \"total_formulas\": 42,           // Number of formulas in file\n  \"error_summary\": {              // Only present if errors found\n    \"#REF!\": {\n      \"count\": 2,\n      \"locations\": [\"Sheet1!B5\", \"Sheet1!C10\"]\n    }\n  }\n}\n```\n\n## Best Practices\n\n### Library Selection\n- **pandas**: Best for data analysis, bulk operations, and simple data export\n- **openpyxl**: Best for complex formatting, formulas, and Excel-specific features\n\n### Working with openpyxl\n- Cell indices are 1-based (row=1, column=1 refers to cell A1)\n- Use `data_only=True` to read calculated values: `load_workbook('file.xlsx', data_only=True)`\n- **Warning**: If opened with `data_only=True` and saved, formulas are replaced with values and permanently lost\n- For large files: Use `read_only=True` for reading or `write_only=True` for writing\n- Formulas are preserved but not evaluated - use scripts/recalc.py to update values\n\n### Working with pandas\n- Specify data types to avoid inference issues: `pd.read_excel('file.xlsx', dtype={'id': str})`\n- For large files, read specific columns: `pd.read_excel('file.xlsx', usecols=['A', 'C', 'E'])`\n- Handle dates properly: `pd.read_excel('file.xlsx', parse_dates=['date_column'])`\n\n## Code Style Guidelines\n**IMPORTANT**: When generating Python code for Excel operations:\n- Write minimal, concise Python code without unnecessary comments\n- Avoid verbose variable names and redundant operations\n- Avoid unnecessary print statements\n\n**For Excel files themselves**:\n- Add comments to cells with complex formulas or important assumptions\n- Document data sources for hardcoded values\n- Include notes for key calculations and model sections","frontmatter":{"name":"xlsx","description":"Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like \"the xlsx in my downloads\") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.","license":"Proprietary. LICENSE.txt has complete terms"},"isInternal":false,"tokens":2814,"sizeBytes":11463}],"systemPromptSnippet":"<yakaai_skills repo=\"eigent-ai/eigent\">\n<!-- File: resources/example-skills/docx/SKILL.md (Tokens: ~4945 | Category: anthropic-skill) -->\n---\nname: docx\ndescription: \"Use this skill whenever the user wants to create, read, edit, or manipulate Word documents (.docx files). Triggers include: any mention of \\\"Word doc\\\", \\\"word document\\\", \\\".docx\\\", or requests to produce professional documents with formatting like tables of contents, headings, page numbers, or letterheads. Also use when extracting or reorganizing content from .docx files, inserting or replacing images in documents, performing find-and-replace in Word files, working with tracked changes or comments, or converting content into a polished Word document. If the user asks for a \\\"report\\\", \\\"memo\\\", \\\"letter\\\", \\\"template\\\", or similar deliverable as a Word or .docx file, use this skill. Do NOT use for PDFs, spreadsheets, Google Docs, or general coding tasks unrelated to document generation.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# DOCX creation, editing, and analysis\n\n## Overview\n\nA .docx file is a ZIP archive containing XML files.\n\n## Quick Reference\n\n| Task | Approach |\n|------|----------|\n| Read/analyze content | `pandoc` or unpack for raw XML |\n| Create new document | Use `docx-js` - see Creating New Documents below |\n| Edit existing document | Unpack → edit XML → repack - see Editing Existing Documents below |\n\n### Converting .doc to .docx\n\nLegacy `.doc` files must be converted before editing:\n\n```bash\npython scripts/office/soffice.py --headless --convert-to docx document.doc\n```\n\n### Reading Content\n\n```bash\n# Text extraction with tracked changes\npandoc --track-changes=all document.docx -o output.md\n\n# Raw XML access\npython scripts/office/unpack.py document.docx unpacked/\n```\n\n### Converting to Images\n\n```bash\npython scripts/office/soffice.py --headless --convert-to pdf document.docx\npdftoppm -jpeg -r 150 document.pdf page\n```\n\n### Accepting Tracked Changes\n\nTo produce a clean document with all tracked changes accepted (requires LibreOffice):\n\n```bash\npython scripts/accept_changes.py input.docx output.docx\n```\n\n---\n\n## Creating New Documents\n\nGenerate .docx files with JavaScript, then validate. Install: `npm install -g docx`\n\n### Setup\n```javascript\nconst { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, ImageRun,\n        Header, Footer, AlignmentType, PageOrientation, LevelFormat, ExternalHyperlink,\n        TableOfContents, HeadingLevel, BorderStyle, WidthType, ShadingType,\n        VerticalAlign, PageNumber, PageBreak } = require('docx');\n\nconst doc = new Document({ sections: [{ children: [/* content */] }] });\nPacker.toBuffer(doc).then(buffer => fs.writeFileSync(\"doc.docx\", buffer));\n```\n\n### Validation\nAfter creating the file, validate it. If validation fails, unpack, fix the XML, and repack.\n```bash\npython scripts/office/validate.py doc.docx\n```\n\n### Page Size\n\n```javascript\n// CRITICAL: docx-js defaults to A4, not US Letter\n// Always set page size explicitly for consistent results\nsections: [{\n  properties: {\n    page: {\n      size: {\n        width: 12240,   // 8.5 inches in DXA\n        height: 15840   // 11 inches in DXA\n      },\n      margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } // 1 inch margins\n    }\n  },\n  children: [/* content */]\n}]\n```\n\n**Common page sizes (DXA units, 1440 DXA = 1 inch):**\n\n| Paper | Width | Height | Content Width (1\" margins) |\n|-------|-------|--------|---------------------------|\n| US Letter | 12,240 | 15,840 | 9,360 |\n| A4 (default) | 11,906 | 16,838 | 9,026 |\n\n**Landscape orientation:** docx-js swaps width/height internally, so pass portrait dimensions and let it handle the swap:\n```javascript\nsize: {\n  width: 12240,   // Pass SHORT edge as width\n  height: 15840,  // Pass LONG edge as height\n  orientation: PageOrientation.LANDSCAPE  // docx-js swaps them in the XML\n},\n// Content width = 15840 - left margin - right margin (uses the long edge)\n```\n\n### Styles (Override Built-in Headings)\n\nUse Arial as the default font (universally supported). Keep titles black for readability.\n\n```javascript\nconst doc = new Document({\n  styles: {\n    default: { document: { run: { font: \"Arial\", size: 24 } } }, // 12pt default\n    paragraphStyles: [\n      // IMPORTANT: Use exact IDs to override built-in styles\n      { id: \"Heading1\", name: \"Heading 1\", basedOn: \"Normal\", next: \"Normal\", quickFormat: true,\n        run: { size: 32, bold: true, font: \"Arial\" },\n        paragraph: { spacing: { before: 240, after: 240 }, outlineLevel: 0 } }, // outlineLevel required for TOC\n      { id: \"Heading2\", name: \"Heading 2\", basedOn: \"Normal\", next: \"Normal\", quickFormat: true,\n        run: { size: 28, bold: true, font: \"Arial\" },\n        paragraph: { spacing: { before: 180, after: 180 }, outlineLevel: 1 } },\n    ]\n  },\n  sections: [{\n    children: [\n      new Paragraph({ heading: HeadingLevel.HEADING_1, children: [new TextRun(\"Title\")] }),\n    ]\n  }]\n});\n```\n\n### Lists (NEVER use unicode bullets)\n\n```javascript\n// ❌ WRONG - never manually insert bullet characters\nnew Paragraph({ children: [new TextRun(\"• Item\")] })  // BAD\nnew Paragraph({ children: [new TextRun(\"\\u2022 Item\")] })  // BAD\n\n// ✅ CORRECT - use numbering config with LevelFormat.BULLET\nconst doc = new Document({\n  numbering: {\n    config: [\n      { reference: \"bullets\",\n        levels: [{ level: 0, format: LevelFormat.BULLET, text: \"•\", alignment: AlignmentType.LEFT,\n          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },\n      { reference: \"numbers\",\n        levels: [{ level: 0, format: LevelFormat.DECIMAL, text: \"%1.\", alignment: AlignmentType.LEFT,\n          style: { paragraph: { indent: { left: 720, hanging: 360 } } } }] },\n    ]\n  },\n  sections: [{\n    children: [\n      new Paragraph({ numbering: { reference: \"bullets\", level: 0 },\n        children: [new TextRun(\"Bullet item\")] }),\n      new Paragraph({ numbering: { reference: \"numbers\", level: 0 },\n        children: [new TextRun(\"Numbered item\")] }),\n    ]\n  }]\n});\n\n// ⚠️ Each reference creates INDEPENDENT numbering\n// Same reference = continues (1,2,3 then 4,5,6)\n// Different reference = restarts (1,2,3 then 1,2,3)\n```\n\n### Tables\n\n**CRITICAL: Tables need dual widths** - set both `columnWidths` on the table AND `width` on each cell. Without both, tables render incorrectly on some platforms.\n\n```javascript\n// CRITICAL: Always set table width for consistent rendering\n// CRITICAL: Use ShadingType.CLEAR (not SOLID) to prevent black backgrounds\nconst border = { style: BorderStyle.SINGLE, size: 1, color: \"CCCCCC\" };\nconst borders = { top: border, bottom: border, left: border, right: border };\n\nnew Table({\n  width: { size: 9360, type: WidthType.DXA }, // Always use DXA (percentages break in Google Docs)\n  columnWidths: [4680, 4680], // Must sum to table width (DXA: 1440 = 1 inch)\n  rows: [\n    new TableRow({\n      children: [\n        new TableCell({\n          borders,\n          width: { size: 4680, type: WidthType.DXA }, // Also set on each cell\n          shading: { fill: \"D5E8F0\", type: ShadingType.CLEAR }, // CLEAR not SOLID\n          margins: { top: 80, bottom: 80, left: 120, right: 120 }, // Cell padding (internal, not added to width)\n          children: [new Paragraph({ children: [new TextRun(\"Cell\")] })]\n        })\n      ]\n    })\n  ]\n})\n```\n\n**Table width calculation:**\n\nAlways use `WidthType.DXA` — `WidthType.PERCENTAGE` breaks in Google Docs.\n\n```javascript\n// Table width = sum of columnWidths = content width\n// US Letter with 1\" margins: 12240 - 2880 = 9360 DXA\nwidth: { size: 9360, type: WidthType.DXA },\ncolumnWidths: [7000, 2360]  // Must sum to table width\n```\n\n**Width rules:**\n- **Always use `WidthType.DXA`** — never `WidthType.PERCENTAGE` (incompatible with Google Docs)\n- Table width must equal the sum of `columnWidths`\n- Cell `width` must match corresponding `columnWidth`\n- Cell `margins` are internal padding - they reduce content area, not add to cell width\n- For full-width tables: use content width (page width minus left and right margins)\n\n### Images\n\n```javascript\n// CRITICAL: type parameter is REQUIRED\nnew Paragraph({\n  children: [new ImageRun({\n    type: \"png\", // Required: png, jpg, jpeg, gif, bmp, svg\n    data: fs.readFileSync(\"image.png\"),\n    transformation: { width: 200, height: 150 },\n    altText: { title: \"Title\", description: \"Desc\", name: \"Name\" } // All three required\n  })]\n})\n```\n\n### Page Breaks\n\n```javascript\n// CRITICAL: PageBreak must be inside a Paragraph\nnew Paragraph({ children: [new PageBreak()] })\n\n// Or use pageBreakBefore\nnew Paragraph({ pageBreakBefore: true, children: [new TextRun(\"New page\")] })\n```\n\n### Table of Contents\n\n```javascript\n// CRITICAL: Headings must use HeadingLevel ONLY - no custom styles\nnew TableOfContents(\"Table of Contents\", { hyperlink: true, headingStyleRange: \"1-3\" })\n```\n\n### Headers/Footers\n\n```javascript\nsections: [{\n  properties: {\n    page: { margin: { top: 1440, right: 1440, bottom: 1440, left: 1440 } } // 1440 = 1 inch\n  },\n  headers: {\n    default: new Header({ children: [new Paragraph({ children: [new TextRun(\"Header\")] })] })\n  },\n  footers: {\n    default: new Footer({ children: [new Paragraph({\n      children: [new TextRun(\"Page \"), new TextRun({ children: [PageNumber.CURRENT] })]\n    })] })\n  },\n  children: [/* content */]\n}]\n```\n\n### Critical Rules for docx-js\n\n- **Set page size explicitly** - docx-js defaults to A4; use US Letter (12240 x 15840 DXA) for US documents\n- **Landscape: pass portrait dimensions** - docx-js swaps width/height internally; pass short edge as `width`, long edge as `height`, and set `orientation: PageOrientation.LANDSCAPE`\n- **Never use `\\n`** - use separate Paragraph elements\n- **Never use unicode bullets** - use `LevelFormat.BULLET` with numbering config\n- **PageBreak must be in Paragraph** - standalone creates invalid XML\n- **ImageRun requires `type`** - always specify png/jpg/etc\n- **Always set table `width` with DXA** - never use `WidthType.PERCENTAGE` (breaks in Google Docs)\n- **Tables need dual widths** - `columnWidths` array AND cell `width`, both must match\n- **Table width = sum of columnWidths** - for DXA, ensure they add up exactly\n- **Always add cell margins** - use `margins: { top: 80, bottom: 80, left: 120, right: 120 }` for readable padding\n- **Use `ShadingType.CLEAR`** - never SOLID for table shading\n- **TOC requires HeadingLevel only** - no custom styles on heading paragraphs\n- **Override built-in styles** - use exact IDs: \"Heading1\", \"Heading2\", etc.\n- **Include `outlineLevel`** - required for TOC (0 for H1, 1 for H2, etc.)\n\n---\n\n## Editing Existing Documents\n\n**Follow all 3 steps in order.**\n\n### Step 1: Unpack\n```bash\npython scripts/office/unpack.py document.docx unpacked/\n```\nExtracts XML, pretty-prints, merges adjacent runs, and converts smart quotes to XML entities (`&#x201C;` etc.) so they survive editing. Use `--merge-runs false` to skip run merging.\n\n### Step 2: Edit XML\n\nEdit files in `unpacked/word/`. See XML Reference below for patterns.\n\n**Use \"Claude\" as the author** for tracked changes and comments, unless the user explicitly requests use of a different name.\n\n**Use the Edit tool directly for string replacement. Do not write Python scripts.** Scripts introduce unnecessary complexity. The Edit tool shows exactly what is being replaced.\n\n**CRITICAL: Use smart quotes for new content.** When adding text with apostrophes or quotes, use XML entities to produce smart quotes:\n```xml\n<!-- Use these entities for professional typography -->\n<w:t>Here&#x2019;s a quote: &#x201C;Hello&#x201D;</w:t>\n```\n| Entity | Character |\n|--------|-----------|\n| `&#x2018;` | ‘ (left single) |\n| `&#x2019;` | ’ (right single / apostrophe) |\n| `&#x201C;` | “ (left double) |\n| `&#x201D;` | ” (right double) |\n\n**Adding comments:** Use `comment.py` to handle boilerplate across multiple XML files (text must be pre-escaped XML):\n```bash\npython scripts/comment.py unpacked/ 0 \"Comment text with &amp; and &#x2019;\"\npython scripts/comment.py unpacked/ 1 \"Reply text\" --parent 0  # reply to comment 0\npython scripts/comment.py unpacked/ 0 \"Text\" --author \"Custom Author\"  # custom author name\n```\nThen add markers to document.xml (see Comments in XML Reference).\n\n### Step 3: Pack\n```bash\npython scripts/office/pack.py unpacked/ output.docx --original document.docx\n```\nValidates with auto-repair, condenses XML, and creates DOCX. Use `--validate false` to skip.\n\n**Auto-repair will fix:**\n- `durableId` >= 0x7FFFFFFF (regenerates valid ID)\n- Missing `xml:space=\"preserve\"` on `<w:t>` with whitespace\n\n**Auto-repair won't fix:**\n- Malformed XML, invalid element nesting, missing relationships, schema violations\n\n### Common Pitfalls\n\n- **Replace entire `<w:r>` elements**: When adding tracked changes, replace the whole `<w:r>...</w:r>` block with `<w:del>...<w:ins>...` as siblings. Don't inject tracked change tags inside a run.\n- **Preserve `<w:rPr>` formatting**: Copy the original run's `<w:rPr>` block into your tracked change runs to maintain bold, font size, etc.\n\n---\n\n## XML Reference\n\n### Schema Compliance\n\n- **Element order in `<w:pPr>`**: `<w:pStyle>`, `<w:numPr>`, `<w:spacing>`, `<w:ind>`, `<w:jc>`, `<w:rPr>` last\n- **Whitespace**: Add `xml:space=\"preserve\"` to `<w:t>` with leading/trailing spaces\n- **RSIDs**: Must be 8-digit hex (e.g., `00AB1234`)\n\n### Tracked Changes\n\n**Insertion:**\n```xml\n<w:ins w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:t>inserted text</w:t></w:r>\n</w:ins>\n```\n\n**Deletion:**\n```xml\n<w:del w:id=\"2\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:delText>deleted text</w:delText></w:r>\n</w:del>\n```\n\n**Inside `<w:del>`**: Use `<w:delText>` instead of `<w:t>`, and `<w:delInstrText>` instead of `<w:instrText>`.\n\n**Minimal edits** - only mark what changes:\n```xml\n<!-- Change \"30 days\" to \"60 days\" -->\n<w:r><w:t>The term is </w:t></w:r>\n<w:del w:id=\"1\" w:author=\"Claude\" w:date=\"...\">\n  <w:r><w:delText>30</w:delText></w:r>\n</w:del>\n<w:ins w:id=\"2\" w:author=\"Claude\" w:date=\"...\">\n  <w:r><w:t>60</w:t></w:r>\n</w:ins>\n<w:r><w:t> days.</w:t></w:r>\n```\n\n**Deleting entire paragraphs/list items** - when removing ALL content from a paragraph, also mark the paragraph mark as deleted so it merges with the next paragraph. Add `<w:del/>` inside `<w:pPr><w:rPr>`:\n```xml\n<w:p>\n  <w:pPr>\n    <w:numPr>...</w:numPr>  <!-- list numbering if present -->\n    <w:rPr>\n      <w:del w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\"/>\n    </w:rPr>\n  </w:pPr>\n  <w:del w:id=\"2\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n    <w:r><w:delText>Entire paragraph content being deleted...</w:delText></w:r>\n  </w:del>\n</w:p>\n```\nWithout the `<w:del/>` in `<w:pPr><w:rPr>`, accepting changes leaves an empty paragraph/list item.\n\n**Rejecting another author's insertion** - nest deletion inside their insertion:\n```xml\n<w:ins w:author=\"Jane\" w:id=\"5\">\n  <w:del w:author=\"Claude\" w:id=\"10\">\n    <w:r><w:delText>their inserted text</w:delText></w:r>\n  </w:del>\n</w:ins>\n```\n\n**Restoring another author's deletion** - add insertion after (don't modify their deletion):\n```xml\n<w:del w:author=\"Jane\" w:id=\"5\">\n  <w:r><w:delText>deleted text</w:delText></w:r>\n</w:del>\n<w:ins w:author=\"Claude\" w:id=\"10\">\n  <w:r><w:t>deleted text</w:t></w:r>\n</w:ins>\n```\n\n### Comments\n\nAfter running `comment.py` (see Step 2), add markers to document.xml. For replies, use `--parent` flag and nest markers inside the parent's.\n\n**CRITICAL: `<w:commentRangeStart>` and `<w:commentRangeEnd>` are siblings of `<w:r>`, never inside `<w:r>`.**\n\n```xml\n<!-- Comment markers are direct children of w:p, never inside w:r -->\n<w:commentRangeStart w:id=\"0\"/>\n<w:del w:id=\"1\" w:author=\"Claude\" w:date=\"2025-01-01T00:00:00Z\">\n  <w:r><w:delText>deleted</w:delText></w:r>\n</w:del>\n<w:r><w:t> more text</w:t></w:r>\n<w:commentRangeEnd w:id=\"0\"/>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"0\"/></w:r>\n\n<!-- Comment 0 with reply 1 nested inside -->\n<w:commentRangeStart w:id=\"0\"/>\n  <w:commentRangeStart w:id=\"1\"/>\n  <w:r><w:t>text</w:t></w:r>\n  <w:commentRangeEnd w:id=\"1\"/>\n<w:commentRangeEnd w:id=\"0\"/>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"0\"/></w:r>\n<w:r><w:rPr><w:rStyle w:val=\"CommentReference\"/></w:rPr><w:commentReference w:id=\"1\"/></w:r>\n```\n\n### Images\n\n1. Add image file to `word/media/`\n2. Add relationship to `word/_rels/document.xml.rels`:\n```xml\n<Relationship Id=\"rId5\" Type=\".../image\" Target=\"media/image1.png\"/>\n```\n3. Add content type to `[Content_Types].xml`:\n```xml\n<Default Extension=\"png\" ContentType=\"image/png\"/>\n```\n4. Reference in document.xml:\n```xml\n<w:drawing>\n  <wp:inline>\n    <wp:extent cx=\"914400\" cy=\"914400\"/>  <!-- EMUs: 914400 = 1 inch -->\n    <a:graphic>\n      <a:graphicData uri=\".../picture\">\n        <pic:pic>\n          <pic:blipFill><a:blip r:embed=\"rId5\"/></pic:blipFill>\n        </pic:pic>\n      </a:graphicData>\n    </a:graphic>\n  </wp:inline>\n</w:drawing>\n```\n\n---\n\n## Dependencies\n\n- **pandoc**: Text extraction\n- **docx**: `npm install -g docx` (new documents)\n- **LibreOffice**: PDF conversion (auto-configured for sandboxed environments via `scripts/office/soffice.py`)\n- **Poppler**: `pdftoppm` for images\n\n<!-- File: resources/example-skills/pdf/SKILL.md (Tokens: ~2079 | Category: anthropic-skill) -->\n---\nname: pdf\ndescription: Use this skill whenever the user wants to do anything with PDF files. This includes reading or extracting text/tables from PDFs, combining or merging multiple PDFs into one, splitting PDFs apart, rotating pages, adding watermarks, creating new PDFs, filling PDF forms, encrypting/decrypting PDFs, extracting images, and OCR on scanned PDFs to make them searchable. If the user mentions a .pdf file or asks to produce one, use this skill.\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# PDF Processing Guide\n\n## Overview\n\nThis guide covers essential PDF processing operations using Python libraries and command-line tools. For advanced features, JavaScript libraries, and detailed examples, see REFERENCE.md. If you need to fill out a PDF form, read FORMS.md and follow its instructions.\n\n## Quick Start\n\n```python\nfrom pypdf import PdfReader, PdfWriter\n\n# Read a PDF\nreader = PdfReader(\"document.pdf\")\nprint(f\"Pages: {len(reader.pages)}\")\n\n# Extract text\ntext = \"\"\nfor page in reader.pages:\n    text += page.extract_text()\n```\n\n## Python Libraries\n\n### pypdf - Basic Operations\n\n#### Merge PDFs\n```python\nfrom pypdf import PdfWriter, PdfReader\n\nwriter = PdfWriter()\nfor pdf_file in [\"doc1.pdf\", \"doc2.pdf\", \"doc3.pdf\"]:\n    reader = PdfReader(pdf_file)\n    for page in reader.pages:\n        writer.add_page(page)\n\nwith open(\"merged.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n#### Split PDF\n```python\nreader = PdfReader(\"input.pdf\")\nfor i, page in enumerate(reader.pages):\n    writer = PdfWriter()\n    writer.add_page(page)\n    with open(f\"page_{i+1}.pdf\", \"wb\") as output:\n        writer.write(output)\n```\n\n#### Extract Metadata\n```python\nreader = PdfReader(\"document.pdf\")\nmeta = reader.metadata\nprint(f\"Title: {meta.title}\")\nprint(f\"Author: {meta.author}\")\nprint(f\"Subject: {meta.subject}\")\nprint(f\"Creator: {meta.creator}\")\n```\n\n#### Rotate Pages\n```python\nreader = PdfReader(\"input.pdf\")\nwriter = PdfWriter()\n\npage = reader.pages[0]\npage.rotate(90)  # Rotate 90 degrees clockwise\nwriter.add_page(page)\n\nwith open(\"rotated.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n### pdfplumber - Text and Table Extraction\n\n#### Extract Text with Layout\n```python\nimport pdfplumber\n\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    for page in pdf.pages:\n        text = page.extract_text()\n        print(text)\n```\n\n#### Extract Tables\n```python\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    for i, page in enumerate(pdf.pages):\n        tables = page.extract_tables()\n        for j, table in enumerate(tables):\n            print(f\"Table {j+1} on page {i+1}:\")\n            for row in table:\n                print(row)\n```\n\n#### Advanced Table Extraction\n```python\nimport pandas as pd\n\nwith pdfplumber.open(\"document.pdf\") as pdf:\n    all_tables = []\n    for page in pdf.pages:\n        tables = page.extract_tables()\n        for table in tables:\n            if table:  # Check if table is not empty\n                df = pd.DataFrame(table[1:], columns=table[0])\n                all_tables.append(df)\n\n# Combine all tables\nif all_tables:\n    combined_df = pd.concat(all_tables, ignore_index=True)\n    combined_df.to_excel(\"extracted_tables.xlsx\", index=False)\n```\n\n### reportlab - Create PDFs\n\n#### Basic PDF Creation\n```python\nfrom reportlab.lib.pagesizes import letter\nfrom reportlab.pdfgen import canvas\n\nc = canvas.Canvas(\"hello.pdf\", pagesize=letter)\nwidth, height = letter\n\n# Add text\nc.drawString(100, height - 100, \"Hello World!\")\nc.drawString(100, height - 120, \"This is a PDF created with reportlab\")\n\n# Add a line\nc.line(100, height - 140, 400, height - 140)\n\n# Save\nc.save()\n```\n\n#### Create PDF with Multiple Pages\n```python\nfrom reportlab.lib.pagesizes import letter\nfrom reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak\nfrom reportlab.lib.styles import getSampleStyleSheet\n\ndoc = SimpleDocTemplate(\"report.pdf\", pagesize=letter)\nstyles = getSampleStyleSheet()\nstory = []\n\n# Add content\ntitle = Paragraph(\"Report Title\", styles['Title'])\nstory.append(title)\nstory.append(Spacer(1, 12))\n\nbody = Paragraph(\"This is the body of the report. \" * 20, styles['Normal'])\nstory.append(body)\nstory.append(PageBreak())\n\n# Page 2\nstory.append(Paragraph(\"Page 2\", styles['Heading1']))\nstory.append(Paragraph(\"Content for page 2\", styles['Normal']))\n\n# Build PDF\ndoc.build(story)\n```\n\n#### Subscripts and Superscripts\n\n**IMPORTANT**: Never use Unicode subscript/superscript characters (₀₁₂₃₄₅₆₇₈₉, ⁰¹²³⁴⁵⁶⁷⁸⁹) in ReportLab PDFs. The built-in fonts do not include these glyphs, causing them to render as solid black boxes.\n\nInstead, use ReportLab's XML markup tags in Paragraph objects:\n```python\nfrom reportlab.platypus import Paragraph\nfrom reportlab.lib.styles import getSampleStyleSheet\n\nstyles = getSampleStyleSheet()\n\n# Subscripts: use <sub> tag\nchemical = Paragraph(\"H<sub>2</sub>O\", styles['Normal'])\n\n# Superscripts: use <super> tag\nsquared = Paragraph(\"x<super>2</super> + y<super>2</super>\", styles['Normal'])\n```\n\nFor canvas-drawn text (not Paragraph objects), manually adjust font the size and position rather than using Unicode subscripts/superscripts.\n\n## Command-Line Tools\n\n### pdftotext (poppler-utils)\n```bash\n# Extract text\npdftotext input.pdf output.txt\n\n# Extract text preserving layout\npdftotext -layout input.pdf output.txt\n\n# Extract specific pages\npdftotext -f 1 -l 5 input.pdf output.txt  # Pages 1-5\n```\n\n### qpdf\n```bash\n# Merge PDFs\nqpdf --empty --pages file1.pdf file2.pdf -- merged.pdf\n\n# Split pages\nqpdf input.pdf --pages . 1-5 -- pages1-5.pdf\nqpdf input.pdf --pages . 6-10 -- pages6-10.pdf\n\n# Rotate pages\nqpdf input.pdf output.pdf --rotate=+90:1  # Rotate page 1 by 90 degrees\n\n# Remove password\nqpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf\n```\n\n### pdftk (if available)\n```bash\n# Merge\npdftk file1.pdf file2.pdf cat output merged.pdf\n\n# Split\npdftk input.pdf burst\n\n# Rotate\npdftk input.pdf rotate 1east output rotated.pdf\n```\n\n## Common Tasks\n\n### Extract Text from Scanned PDFs\n```python\n# Requires: pip install pytesseract pdf2image\nimport pytesseract\nfrom pdf2image import convert_from_path\n\n# Convert PDF to images\nimages = convert_from_path('scanned.pdf')\n\n# OCR each page\ntext = \"\"\nfor i, image in enumerate(images):\n    text += f\"Page {i+1}:\\n\"\n    text += pytesseract.image_to_string(image)\n    text += \"\\n\\n\"\n\nprint(text)\n```\n\n### Add Watermark\n```python\nfrom pypdf import PdfReader, PdfWriter\n\n# Create watermark (or load existing)\nwatermark = PdfReader(\"watermark.pdf\").pages[0]\n\n# Apply to all pages\nreader = PdfReader(\"document.pdf\")\nwriter = PdfWriter()\n\nfor page in reader.pages:\n    page.merge_page(watermark)\n    writer.add_page(page)\n\nwith open(\"watermarked.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n### Extract Images\n```bash\n# Using pdfimages (poppler-utils)\npdfimages -j input.pdf output_prefix\n\n# This extracts all images as output_prefix-000.jpg, output_prefix-001.jpg, etc.\n```\n\n### Password Protection\n```python\nfrom pypdf import PdfReader, PdfWriter\n\nreader = PdfReader(\"input.pdf\")\nwriter = PdfWriter()\n\nfor page in reader.pages:\n    writer.add_page(page)\n\n# Add password\nwriter.encrypt(\"userpassword\", \"ownerpassword\")\n\nwith open(\"encrypted.pdf\", \"wb\") as output:\n    writer.write(output)\n```\n\n## Quick Reference\n\n| Task | Best Tool | Command/Code |\n|------|-----------|--------------|\n| Merge PDFs | pypdf | `writer.add_page(page)` |\n| Split PDFs | pypdf | One page per file |\n| Extract text | pdfplumber | `page.extract_text()` |\n| Extract tables | pdfplumber | `page.extract_tables()` |\n| Create PDFs | reportlab | Canvas or Platypus |\n| Command line merge | qpdf | `qpdf --empty --pages ...` |\n| OCR scanned PDFs | pytesseract | Convert to image first |\n| Fill PDF forms | pdf-lib or pypdf (see FORMS.md) | See FORMS.md |\n\n## Next Steps\n\n- For advanced pypdfium2 usage, see REFERENCE.md\n- For JavaScript libraries (pdf-lib), see REFERENCE.md\n- If you need to fill out a PDF form, follow the instructions in FORMS.md\n- For troubleshooting guides, see REFERENCE.md\n\n<!-- File: resources/example-skills/pptx/SKILL.md (Tokens: ~2087 | Category: anthropic-skill) -->\n---\nname: pptx\ndescription: \"Use this skill any time a .pptx file is involved in any way — as input, output, or both. This includes: creating slide decks, pitch decks, or presentations; reading, parsing, or extracting text from any .pptx file (even if the extracted content will be used elsewhere, like in an email or summary); editing, modifying, or updating existing presentations; combining or splitting slide files; working with templates, layouts, speaker notes, or comments. Trigger whenever the user mentions \\\"deck,\\\" \\\"slides,\\\" \\\"presentation,\\\" or references a .pptx filename, regardless of what they plan to do with the content afterward. If a .pptx file needs to be opened, created, or touched, use this skill.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# PPTX Skill\n\n## Quick Reference\n\n| Task | Guide |\n|------|-------|\n| Read/analyze content | `python -m markitdown presentation.pptx` |\n| Edit or create from template | Read [editing.md](editing.md) |\n| Create from scratch | Read [pptxgenjs.md](pptxgenjs.md) |\n\n---\n\n## Reading Content\n\n```bash\n# Text extraction\npython -m markitdown presentation.pptx\n\n# Visual overview\npython scripts/thumbnail.py presentation.pptx\n\n# Raw XML\npython scripts/office/unpack.py presentation.pptx unpacked/\n```\n\n---\n\n## Editing Workflow\n\n**Read [editing.md](editing.md) for full details.**\n\n1. Analyze template with `thumbnail.py`\n2. Unpack → manipulate slides → edit content → clean → pack\n\n---\n\n## Creating from Scratch\n\n**Read [pptxgenjs.md](pptxgenjs.md) for full details.**\n\nUse when no template or reference presentation is available.\n\n---\n\n## Design Ideas\n\n**Don't create boring slides.** Plain bullets on a white background won't impress anyone. Consider ideas from this list for each slide.\n\n### Before Starting\n\n- **Pick a bold, content-informed color palette**: The palette should feel designed for THIS topic. If swapping your colors into a completely different presentation would still \"work,\" you haven't made specific enough choices.\n- **Dominance over equality**: One color should dominate (60-70% visual weight), with 1-2 supporting tones and one sharp accent. Never give all colors equal weight.\n- **Dark/light contrast**: Dark backgrounds for title + conclusion slides, light for content (\"sandwich\" structure). Or commit to dark throughout for a premium feel.\n- **Commit to a visual motif**: Pick ONE distinctive element and repeat it — rounded image frames, icons in colored circles, thick single-side borders. Carry it across every slide.\n\n### Color Palettes\n\nChoose colors that match your topic — don't default to generic blue. Use these palettes as inspiration:\n\n| Theme | Primary | Secondary | Accent |\n|-------|---------|-----------|--------|\n| **Midnight Executive** | `1E2761` (navy) | `CADCFC` (ice blue) | `FFFFFF` (white) |\n| **Forest & Moss** | `2C5F2D` (forest) | `97BC62` (moss) | `F5F5F5` (cream) |\n| **Coral Energy** | `F96167` (coral) | `F9E795` (gold) | `2F3C7E` (navy) |\n| **Warm Terracotta** | `B85042` (terracotta) | `E7E8D1` (sand) | `A7BEAE` (sage) |\n| **Ocean Gradient** | `065A82` (deep blue) | `1C7293` (teal) | `21295C` (midnight) |\n| **Charcoal Minimal** | `36454F` (charcoal) | `F2F2F2` (off-white) | `212121` (black) |\n| **Teal Trust** | `028090` (teal) | `00A896` (seafoam) | `02C39A` (mint) |\n| **Berry & Cream** | `6D2E46` (berry) | `A26769` (dusty rose) | `ECE2D0` (cream) |\n| **Sage Calm** | `84B59F` (sage) | `69A297` (eucalyptus) | `50808E` (slate) |\n| **Cherry Bold** | `990011` (cherry) | `FCF6F5` (off-white) | `2F3C7E` (navy) |\n\n### For Each Slide\n\n**Every slide needs a visual element** — image, chart, icon, or shape. Text-only slides are forgettable.\n\n**Layout options:**\n- Two-column (text left, illustration on right)\n- Icon + text rows (icon in colored circle, bold header, description below)\n- 2x2 or 2x3 grid (image on one side, grid of content blocks on other)\n- Half-bleed image (full left or right side) with content overlay\n\n**Data display:**\n- Large stat callouts (big numbers 60-72pt with small labels below)\n- Comparison columns (before/after, pros/cons, side-by-side options)\n- Timeline or process flow (numbered steps, arrows)\n\n**Visual polish:**\n- Icons in small colored circles next to section headers\n- Italic accent text for key stats or taglines\n\n### Typography\n\n**Choose an interesting font pairing** — don't default to Arial. Pick a header font with personality and pair it with a clean body font.\n\n| Header Font | Body Font |\n|-------------|-----------|\n| Georgia | Calibri |\n| Arial Black | Arial |\n| Calibri | Calibri Light |\n| Cambria | Calibri |\n| Trebuchet MS | Calibri |\n| Impact | Arial |\n| Palatino | Garamond |\n| Consolas | Calibri |\n\n| Element | Size |\n|---------|------|\n| Slide title | 36-44pt bold |\n| Section header | 20-24pt bold |\n| Body text | 14-16pt |\n| Captions | 10-12pt muted |\n\n### Spacing\n\n- 0.5\" minimum margins\n- 0.3-0.5\" between content blocks\n- Leave breathing room—don't fill every inch\n\n### Avoid (Common Mistakes)\n\n- **Don't repeat the same layout** — vary columns, cards, and callouts across slides\n- **Don't center body text** — left-align paragraphs and lists; center only titles\n- **Don't skimp on size contrast** — titles need 36pt+ to stand out from 14-16pt body\n- **Don't default to blue** — pick colors that reflect the specific topic\n- **Don't mix spacing randomly** — choose 0.3\" or 0.5\" gaps and use consistently\n- **Don't style one slide and leave the rest plain** — commit fully or keep it simple throughout\n- **Don't create text-only slides** — add images, icons, charts, or visual elements; avoid plain title + bullets\n- **Don't forget text box padding** — when aligning lines or shapes with text edges, set `margin: 0` on the text box or offset the shape to account for padding\n- **Don't use low-contrast elements** — icons AND text need strong contrast against the background; avoid light text on light backgrounds or dark text on dark backgrounds\n- **NEVER use accent lines under titles** — these are a hallmark of AI-generated slides; use whitespace or background color instead\n\n---\n\n## QA (Required)\n\n**Assume there are problems. Your job is to find them.**\n\nYour first render is almost never correct. Approach QA as a bug hunt, not a confirmation step. If you found zero issues on first inspection, you weren't looking hard enough.\n\n### Content QA\n\n```bash\npython -m markitdown output.pptx\n```\n\nCheck for missing content, typos, wrong order.\n\n**When using templates, check for leftover placeholder text:**\n\n```bash\npython -m markitdown output.pptx | grep -iE \"xxxx|lorem|ipsum|this.*(page|slide).*layout\"\n```\n\nIf grep returns results, fix them before declaring success.\n\n### Visual QA\n\n### Verification Loop\n\n1. Generate slides → Convert to images → Inspect\n2. **List issues found** (if none found, look again more critically)\n3. Fix issues\n4. **Re-verify affected slides** — one fix often creates another problem\n5. Repeat until a full pass reveals no new issues\n\n**Do not declare success until you've completed at least one fix-and-verify cycle.**\n\n---\n\n## Converting to Images\n\nConvert presentations to individual slide images for visual inspection:\n\n```bash\npython scripts/office/soffice.py --headless --convert-to pdf output.pptx\npdftoppm -jpeg -r 150 output.pdf slide\n```\n\nThis creates `slide-01.jpg`, `slide-02.jpg`, etc.\n\nTo re-render specific slides after fixes:\n\n```bash\npdftoppm -jpeg -r 150 -f N -l N output.pdf slide-fixed\n```\n\n---\n\n## Dependencies\n\n- `pip install \"markitdown[pptx]\"` - text extraction\n- `pip install Pillow` - thumbnail grids\n- `npm install -g pptxgenjs` - creating from scratch\n- LibreOffice (`soffice`) - PDF conversion (auto-configured for sandboxed environments via `scripts/office/soffice.py`)\n- Poppler (`pdftoppm`) - PDF to images\n\n<!-- File: resources/example-skills/skill-creator/references/output-patterns.md (Tokens: ~356 | Category: anthropic-skill) -->\n# Output Patterns\n\nUse these patterns when skills need to produce consistent, high-quality output.\n\n## Template Pattern\n\nProvide templates for output format. Match the level of strictness to your needs.\n\n**For strict requirements (like API responses or data formats):**\n\n```markdown\n## Report structure\n\nALWAYS use this exact template structure:\n\n# [Analysis Title]\n\n## Executive summary\n[One-paragraph overview of key findings]\n\n## Key findings\n- Finding 1 with supporting data\n- Finding 2 with supporting data\n- Finding 3 with supporting data\n\n## Recommendations\n1. Specific actionable recommendation\n2. Specific actionable recommendation\n```\n\n**For flexible guidance (when adaptation is useful):**\n\n```markdown\n## Report structure\n\nHere is a sensible default format, but use your best judgment:\n\n# [Analysis Title]\n\n## Executive summary\n[Overview]\n\n## Key findings\n[Adapt sections based on what you discover]\n\n## Recommendations\n[Tailor to the specific context]\n\nAdjust sections as needed for the specific analysis type.\n```\n\n## Examples Pattern\n\nFor skills where output quality depends on seeing examples, provide input/output pairs:\n\n```markdown\n## Commit message format\n\nGenerate commit messages following these examples:\n\n**Example 1:**\nInput: Added user authentication with JWT tokens\nOutput:\n```\nfeat(auth): implement JWT-based authentication\n\nAdd login endpoint and token validation middleware\n```\n\n**Example 2:**\nInput: Fixed bug where dates displayed incorrectly in reports\nOutput:\n```\nfix(reports): correct date formatting in timezone conversion\n\nUse UTC timestamps consistently across report generation\n```\n\nFollow this style: type(scope): brief description, then detailed explanation.\n```\n\nExamples help the agent understand the desired style and level of detail more clearly than descriptions alone.\n\n<!-- File: resources/example-skills/skill-creator/references/workflows.md (Tokens: ~184 | Category: anthropic-skill) -->\n# Workflow Patterns\n\n## Sequential Workflows\n\nFor complex tasks, break operations into clear, sequential steps. It is often helpful to give the agent an overview of the process towards the beginning of SKILL.md:\n\n```markdown\nFilling a PDF form involves these steps:\n\n1. Analyze the form (run analyze_form.py)\n2. Create field mapping (edit fields.json)\n3. Validate mapping (run validate_fields.py)\n4. Fill the form (run fill_form.py)\n5. Verify output (run verify_output.py)\n```\n\n## Conditional Workflows\n\nFor tasks with branching logic, guide the agent through decision points:\n\n```markdown\n1. Determine the modification type:\n   **Creating new content?** → Follow \"Creation workflow\" below\n   **Editing existing content?** → Follow \"Editing workflow\" below\n\n2. Creation workflow: [steps]\n3. Editing workflow: [steps]\n```\n\n<!-- File: resources/example-skills/skill-creator/SKILL.md (Tokens: ~3789 | Category: anthropic-skill) -->\n---\nname: skill-creator\ndescription: Guide for creating effective skills. Use when creating a new skill or updating an existing skill that extends agent capabilities with specialized knowledge, workflows, or tool integrations.\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# Skill Creator\n\nThis skill provides guidance for creating effective skills.\n\n## About Skills\n\nSkills are modular, self-contained packages that extend agent capabilities by providing\nspecialized knowledge, workflows, and tools. Think of them as \"onboarding guides\" for specific\ndomains or tasks—they transform a general-purpose agent into a specialized agent\nequipped with procedural knowledge that no model can fully possess.\n\n### What Skills Provide\n\n1. Specialized workflows - Multi-step procedures for specific domains\n2. Tool integrations - Instructions for working with specific file formats or APIs\n3. Domain expertise - Company-specific knowledge, schemas, business logic\n4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks\n\n## Core Principles\n\n### Concise is Key\n\nThe context window is a public good. Skills share the context window with everything else the agent needs: system prompt, conversation history, other Skills' metadata, and the actual user request.\n\n**Default assumption: The agent is already very capable.** Only add context the agent doesn't already have. Challenge each piece of information: \"Does the agent really need this explanation?\" and \"Does this paragraph justify its token cost?\"\n\nPrefer concise examples over verbose explanations.\n\n### Set Appropriate Degrees of Freedom\n\nMatch the level of specificity to the task's fragility and variability:\n\n**High freedom (text-based instructions)**: Use when multiple approaches are valid, decisions depend on context, or heuristics guide the approach.\n\n**Medium freedom (pseudocode or scripts with parameters)**: Use when a preferred pattern exists, some variation is acceptable, or configuration affects behavior.\n\n**Low freedom (specific scripts, few parameters)**: Use when operations are fragile and error-prone, consistency is critical, or a specific sequence must be followed.\n\nThink of the agent exploring a path: a narrow bridge with cliffs needs specific guardrails (low freedom), while an open field allows many routes (high freedom).\n\n### Anatomy of a Skill\n\nEvery skill consists of a required SKILL.md file and optional bundled resources:\n\n```\nskill-name/\n├── SKILL.md (required)\n│   ├── YAML frontmatter metadata (required)\n│   │   ├── name: (required)\n│   │   ├── description: (required)\n│   │   └── compatibility: (optional, rarely needed)\n│   └── Markdown instructions (required)\n└── Bundled Resources (optional)\n    ├── scripts/          - Executable code (Python/Bash/etc.)\n    ├── references/       - Documentation intended to be loaded into context as needed\n    └── assets/           - Files used in output (templates, icons, fonts, etc.)\n```\n\n#### SKILL.md (required)\n\nEvery SKILL.md consists of:\n\n- **Frontmatter** (YAML): Contains `name` and `description` fields (required), plus optional fields like `license`, `metadata`, and `compatibility`. Only `name` and `description` are read by the agent to determine when the skill triggers, so be clear and comprehensive about what the skill is and when it should be used. The `compatibility` field is for noting environment requirements (target product, system packages, etc.) but most skills don't need it.\n- **Body** (Markdown): Instructions and guidance for using the skill. Only loaded AFTER the skill triggers (if at all).\n\n#### Bundled Resources (optional)\n\n##### Scripts (`scripts/`)\n\nExecutable code (Python/Bash/etc.) for tasks that require deterministic reliability or are repeatedly rewritten.\n\n- **When to include**: When the same code is being rewritten repeatedly or deterministic reliability is needed\n- **Example**: `scripts/rotate_pdf.py` for PDF rotation tasks\n- **Benefits**: Token efficient, deterministic, may be executed without loading into context\n- **Note**: Scripts may still need to be read by the agent for patching or environment-specific adjustments\n\n##### References (`references/`)\n\nDocumentation and reference material intended to be loaded as needed into context to inform the agent's process and thinking.\n\n- **When to include**: For documentation that the agent should reference while working\n- **Examples**: `references/finance.md` for financial schemas, `references/mnda.md` for company NDA template, `references/policies.md` for company policies, `references/api_docs.md` for API specifications\n- **Use cases**: Database schemas, API documentation, domain knowledge, company policies, detailed workflow guides\n- **Benefits**: Keeps SKILL.md lean, loaded only when the agent determines it's needed\n- **Best practice**: If files are large (>10k words), include grep search patterns in SKILL.md\n- **Avoid duplication**: Information should live in either SKILL.md or references files, not both. Prefer references files for detailed information unless it's truly core to the skill—this keeps SKILL.md lean while making information discoverable without hogging the context window. Keep only essential procedural instructions and workflow guidance in SKILL.md; move detailed reference material, schemas, and examples to references files.\n\n##### Assets (`assets/`)\n\nFiles not intended to be loaded into context, but rather used within the output the agent produces.\n\n- **When to include**: When the skill needs files that will be used in the final output\n- **Examples**: `assets/logo.png` for brand assets, `assets/slides.pptx` for PowerPoint templates, `assets/frontend-template/` for HTML/React boilerplate, `assets/font.ttf` for typography\n- **Use cases**: Templates, images, icons, boilerplate code, fonts, sample documents that get copied or modified\n- **Benefits**: Separates output resources from documentation, enables the agent to use files without loading them into context\n\n#### What to Not Include in a Skill\n\nA skill should only contain essential files that directly support its functionality. Do NOT create extraneous documentation or auxiliary files, including:\n\n- README.md\n- INSTALLATION_GUIDE.md\n- QUICK_REFERENCE.md\n- CHANGELOG.md\n- etc.\n\nThe skill should only contain the information needed for an AI agent to do the job at hand. It should not contain auxilary context about the process that went into creating it, setup and testing procedures, user-facing documentation, etc. Creating additional documentation files just adds clutter and confusion.\n\n### Progressive Disclosure Design Principle\n\nSkills use a three-level loading system to manage context efficiently:\n\n1. **Metadata (name + description)** - Always in context (~100 words)\n2. **SKILL.md body** - When skill triggers (<5k words)\n3. **Bundled resources** - As needed by the agent (Unlimited because scripts can be executed without reading into context window)\n\n#### Progressive Disclosure Patterns\n\nKeep SKILL.md body to the essentials and under 500 lines to minimize context bloat. Split content into separate files when approaching this limit. When splitting out content into other files, it is very important to reference them from SKILL.md and describe clearly when to read them, to ensure the reader of the skill knows they exist and when to use them.\n\n**Key principle:** When a skill supports multiple variations, frameworks, or options, keep only the core workflow and selection guidance in SKILL.md. Move variant-specific details (patterns, examples, configuration) into separate reference files.\n\n**Pattern 1: High-level guide with references**\n\n```markdown\n# PDF Processing\n\n## Quick start\n\nExtract text with pdfplumber:\n[code example]\n\n## Advanced features\n\n- **Form filling**: See [FORMS.md](FORMS.md) for complete guide\n- **API reference**: See [REFERENCE.md](REFERENCE.md) for all methods\n- **Examples**: See [EXAMPLES.md](EXAMPLES.md) for common patterns\n```\n\nThe agent loads FORMS.md, REFERENCE.md, or EXAMPLES.md only when needed.\n\n**Pattern 2: Domain-specific organization**\n\nFor Skills with multiple domains, organize content by domain to avoid loading irrelevant context:\n\n```\nbigquery-skill/\n├── SKILL.md (overview and navigation)\n└── reference/\n    ├── finance.md (revenue, billing metrics)\n    ├── sales.md (opportunities, pipeline)\n    ├── product.md (API usage, features)\n    └── marketing.md (campaigns, attribution)\n```\n\nWhen a user asks about sales metrics, the agent only reads sales.md.\n\nSimilarly, for skills supporting multiple frameworks or variants, organize by variant:\n\n```\ncloud-deploy/\n├── SKILL.md (workflow + provider selection)\n└── references/\n    ├── aws.md (AWS deployment patterns)\n    ├── gcp.md (GCP deployment patterns)\n    └── azure.md (Azure deployment patterns)\n```\n\nWhen the user chooses AWS, the agent only reads aws.md.\n\n**Pattern 3: Conditional details**\n\nShow basic content, link to advanced content:\n\n```markdown\n# DOCX Processing\n\n## Creating documents\n\nUse docx-js for new documents. See [DOCX-JS.md](DOCX-JS.md).\n\n## Editing documents\n\nFor simple edits, modify the XML directly.\n\n**For tracked changes**: See [REDLINING.md](REDLINING.md)\n**For OOXML details**: See [OOXML.md](OOXML.md)\n```\n\nThe agent reads REDLINING.md or OOXML.md only when the user needs those features.\n\n**Important guidelines:**\n\n- **Avoid deeply nested references** - Keep references one level deep from SKILL.md. All reference files should link directly from SKILL.md.\n- **Structure longer reference files** - For files longer than 100 lines, include a table of contents at the top so the agent can see the full scope when previewing.\n\n## Skill Creation Process\n\nSkill creation involves these steps:\n\n1. Understand the skill with concrete examples\n2. Plan reusable skill contents (scripts, references, assets)\n3. Initialize the skill (run init_skill.py)\n4. Edit the skill (implement resources and write SKILL.md)\n5. Package the skill (run package_skill.py)\n6. Iterate based on real usage\n\nFollow these steps in order, skipping only if there is a clear reason why they are not applicable.\n\n### Step 1: Understanding the Skill with Concrete Examples\n\nSkip this step only when the skill's usage patterns are already clearly understood. It remains valuable even when working with an existing skill.\n\nTo create an effective skill, clearly understand concrete examples of how the skill will be used. This understanding can come from either direct user examples or generated examples that are validated with user feedback.\n\nFor example, when building an image-editor skill, relevant questions include:\n\n- \"What functionality should the image-editor skill support? Editing, rotating, anything else?\"\n- \"Can you give some examples of how this skill would be used?\"\n- \"I can imagine users asking for things like 'Remove the red-eye from this image' or 'Rotate this image'. Are there other ways you imagine this skill being used?\"\n- \"What would a user say that should trigger this skill?\"\n\nTo avoid overwhelming users, avoid asking too many questions in a single message. Start with the most important questions and follow up as needed for better effectiveness.\n\nConclude this step when there is a clear sense of the functionality the skill should support.\n\n### Step 2: Planning the Reusable Skill Contents\n\nTo turn concrete examples into an effective skill, analyze each example by:\n\n1. Considering how to execute on the example from scratch\n2. Identifying what scripts, references, and assets would be helpful when executing these workflows repeatedly\n\nExample: When building a `pdf-editor` skill to handle queries like \"Help me rotate this PDF,\" the analysis shows:\n\n1. Rotating a PDF requires re-writing the same code each time\n2. A `scripts/rotate_pdf.py` script would be helpful to store in the skill\n\nExample: When designing a `frontend-webapp-builder` skill for queries like \"Build me a todo app\" or \"Build me a dashboard to track my steps,\" the analysis shows:\n\n1. Writing a frontend webapp requires the same boilerplate HTML/React each time\n2. An `assets/hello-world/` template containing the boilerplate HTML/React project files would be helpful to store in the skill\n\nExample: When building a `big-query` skill to handle queries like \"How many users have logged in today?\" the analysis shows:\n\n1. Querying BigQuery requires re-discovering the table schemas and relationships each time\n2. A `references/schema.md` file documenting the table schemas would be helpful to store in the skill\n\nTo establish the skill's contents, analyze each concrete example to create a list of the reusable resources to include: scripts, references, and assets.\n\n### Step 3: Initializing the Skill\n\nAt this point, it is time to actually create the skill.\n\nSkip this step only if the skill being developed already exists, and iteration or packaging is needed. In this case, continue to the next step.\n\nWhen creating a new skill from scratch, always run the `init_skill.py` script. The script conveniently generates a new template skill directory that automatically includes everything a skill requires, making the skill creation process much more efficient and reliable.\n\nUsage (run from the skill-creator skill directory):\n\n```bash\npython scripts/init_skill.py <skill-name> --path <output-directory>\n```\n\nNote: The scripts are located in this skill's `scripts/` directory. Use the full path if running from a different directory.\n\nThe script:\n\n- Creates the skill directory at the specified path\n- Generates a SKILL.md template with proper frontmatter and TODO placeholders\n- Creates example resource directories: `scripts/`, `references/`, and `assets/`\n- Adds example files in each directory that can be customized or deleted\n\nAfter initialization, customize or remove the generated SKILL.md and example files as needed.\n\n### Step 4: Edit the Skill\n\nWhen editing the (newly-generated or existing) skill, remember that the skill is being created for an agent to use. Include information that would be beneficial and non-obvious to the agent. Consider what procedural knowledge, domain-specific details, or reusable assets would help the agent execute these tasks more effectively.\n\n#### Learn Proven Design Patterns\n\nConsult these helpful guides based on your skill's needs:\n\n- **Multi-step processes**: See references/workflows.md for sequential workflows and conditional logic\n- **Specific output formats or quality standards**: See references/output-patterns.md for template and example patterns\n\nThese files contain established best practices for effective skill design.\n\n#### Start with Reusable Skill Contents\n\nTo begin implementation, start with the reusable resources identified above: `scripts/`, `references/`, and `assets/` files. Note that this step may require user input. For example, when implementing a `brand-guidelines` skill, the user may need to provide brand assets or templates to store in `assets/`, or documentation to store in `references/`.\n\nAdded scripts must be tested by actually running them to ensure there are no bugs and that the output matches what is expected. If there are many similar scripts, only a representative sample needs to be tested to ensure confidence that they all work while balancing time to completion.\n\nAny example files and directories not needed for the skill should be deleted. The initialization script creates example files in `scripts/`, `references/`, and `assets/` to demonstrate structure, but most skills won't need all of them.\n\n#### Update SKILL.md\n\n**Writing Guidelines:** Always use imperative/infinitive form.\n\n##### Frontmatter\n\nWrite the YAML frontmatter with `name` and `description`:\n\n- `name`: The skill name\n- `description`: This is the primary triggering mechanism for your skill, and helps the agent understand when to use the skill.\n  - Include both what the Skill does and specific triggers/contexts for when to use it.\n  - Include all \"when to use\" information here - Not in the body. The body is only loaded after triggering, so \"When to Use This Skill\" sections in the body are not helpful to the agent.\n  - Example description for a `docx` skill: \"Comprehensive document creation, editing, and analysis with support for tracked changes, comments, formatting preservation, and text extraction. Use when the agent needs to work with professional documents (.docx files) for: (1) Creating new documents, (2) Modifying or editing content, (3) Working with tracked changes, (4) Adding comments, or any other document tasks\"\n\nDo not include any other fields in YAML frontmatter.\n\n##### Body\n\nWrite instructions for using the skill and its bundled resources.\n\n### Step 5: Packaging a Skill\n\nOnce development of the skill is complete, it must be packaged into a distributable .skill file that gets shared with the user. The packaging process automatically validates the skill first to ensure it meets all requirements.\n\nUsage (run from the skill-creator skill directory):\n\n```bash\npython scripts/package_skill.py <path/to/skill-folder>\n```\n\nOptional output directory specification:\n\n```bash\npython scripts/package_skill.py <path/to/skill-folder> ./dist\n```\n\nNote: The scripts are located in this skill's `scripts/` directory. Use the full path if running from a different directory.\n\nThe packaging script will:\n\n1. **Validate** the skill automatically, checking:\n   - YAML frontmatter format and required fields\n   - Skill naming conventions and directory structure\n   - Description completeness and quality\n   - File organization and resource references\n\n2. **Package** the skill if validation passes, creating a .skill file named after the skill (e.g., `my-skill.skill`) that includes all files and maintains the proper directory structure for distribution. The .skill file is a zip file with a .skill extension.\n\nIf validation fails, the script will report the errors and exit without creating a package. Fix any validation errors and run the packaging command again.\n\n### Step 6: Iterate\n\nAfter testing the skill, users may request improvements. Often this happens right after using the skill, with fresh context of how the skill performed.\n\n**Iteration workflow:**\n\n1. Use the skill on real tasks\n2. Notice struggles or inefficiencies\n3. Identify how SKILL.md or bundled resources should be updated\n4. Implement changes and test again\n\n<!-- File: resources/example-skills/skill-security-auditor/references/secrets-patterns.md (Tokens: ~1506 | Category: anthropic-skill) -->\n# Secrets Detection Patterns\n\nRegex patterns and rules for detecting hardcoded secrets, credentials, and sensitive data in source code.\n\n## Table of Contents\n\n- [API Keys and Tokens](#api-keys-and-tokens)\n- [Cloud Provider Credentials](#cloud-provider-credentials)\n- [Database Connection Strings](#database-connection-strings)\n- [Private Keys and Certificates](#private-keys-and-certificates)\n- [Generic Patterns](#generic-patterns)\n- [Files to Always Check](#files-to-always-check)\n- [False Positive Reduction](#false-positive-reduction)\n\n## API Keys and Tokens\n\n| Service | Pattern | Example |\n|---------|---------|---------|\n| AWS Access Key | `AKIA[0-9A-Z]{16}` | AKIAIOSFODNN7EXAMPLE |\n| AWS Secret Key | `(?i)aws_secret_access_key\\s*=\\s*\\S{40}` | |\n| GitHub Token | `gh[ps]_[A-Za-z0-9_]{36,}` | ghp_xxxxxxxxxxxx |\n| GitHub Fine-grained | `github_pat_[A-Za-z0-9_]{22,}` | |\n| GitLab Token | `glpat-[A-Za-z0-9\\-]{20,}` | |\n| Slack Token | `xox[baprs]-[A-Za-z0-9\\-]{10,}` | |\n| Slack Webhook | `https://hooks\\.slack\\.com/services/T[A-Z0-9]+/B[A-Z0-9]+/[A-Za-z0-9]+` | |\n| Stripe Secret | `sk_live_[A-Za-z0-9]{24,}` | |\n| Stripe Publishable | `pk_live_[A-Za-z0-9]{24,}` | |\n| Twilio | `SK[0-9a-fA-F]{32}` | |\n| SendGrid | `SG\\.[A-Za-z0-9\\-_]{22}\\.[A-Za-z0-9\\-_]{43}` | |\n| Mailgun | `key-[0-9a-zA-Z]{32}` | |\n| Google API Key | `AIza[0-9A-Za-z\\-_]{35}` | |\n| Google OAuth | `[0-9]+-[0-9A-Za-z_]{32}\\.apps\\.googleusercontent\\.com` | |\n| Heroku API Key | `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}` | |\n| npm Token | `npm_[A-Za-z0-9]{36}` | |\n| PyPI Token | `pypi-[A-Za-z0-9\\-_]{50,}` | |\n\n## Cloud Provider Credentials\n\n### AWS\n```\n# Access Key ID\nAKIA[0-9A-Z]{16}\n\n# Secret Access Key (in config context)\n(?i)(aws_secret_access_key|aws_secret_key)\\s*[=:]\\s*[A-Za-z0-9/+=]{40}\n\n# Session Token\n(?i)aws_session_token\\s*[=:]\\s*\\S+\n```\n\n### GCP\n```\n# Service account key file indicators\n\"type\"\\s*:\\s*\"service_account\"\n\"private_key\"\\s*:\\s*\"-----BEGIN\n\n# OAuth client secret\n(?i)client_secret\\s*[=:]\\s*\\S+\n```\n\n### Azure\n```\n# Storage account key\n(?i)(AccountKey|account_key)\\s*[=:]\\s*[A-Za-z0-9+/=]{86,}\n\n# Connection strings\n(?i)(DefaultEndpointsProtocol|AccountName|AccountKey)=[^;\\s]+\n```\n\n## Database Connection Strings\n\n```\n# Generic with embedded password\n(?i)(mysql|postgres|postgresql|mongodb|redis|mssql|sqlserver)://[^:]+:[^@]+@\n\n# Django DATABASE_URL\n(?i)DATABASE_URL\\s*=\\s*\\S+://\\S+:\\S+@\n\n# JDBC with password\n(?i)jdbc:[a-z]+://[^;]+password=[^;\\s]+\n```\n\n## Private Keys and Certificates\n\n```\n# RSA private key\n-----BEGIN RSA PRIVATE KEY-----\n\n# Generic private key\n-----BEGIN PRIVATE KEY-----\n\n# EC private key\n-----BEGIN EC PRIVATE KEY-----\n\n# OpenSSH private key\n-----BEGIN OPENSSH PRIVATE KEY-----\n\n# PGP private key\n-----BEGIN PGP PRIVATE KEY BLOCK-----\n\n# Certificate (not a secret, but may indicate key nearby)\n-----BEGIN CERTIFICATE-----\n```\n\n## Generic Patterns\n\nThese catch secrets not covered by service-specific patterns:\n\n```\n# Assignment patterns with secret-like variable names\n(?i)(password|passwd|pwd|secret|token|api_key|apikey|api_secret|access_key|auth_token|credentials)\\s*[=:]\\s*['\"][^'\"]{8,}['\"]\n\n# Bearer tokens in code\n(?i)bearer\\s+[A-Za-z0-9\\-._~+/]+=*\n\n# Base64 encoded secrets (high entropy, 20+ chars)\n(?i)(secret|key|token|password)\\s*[=:]\\s*['\"][A-Za-z0-9+/]{20,}={0,2}['\"]\n\n# Hex-encoded secrets (32+ chars)\n(?i)(secret|key|token)\\s*[=:]\\s*['\"][0-9a-fA-F]{32,}['\"]\n```\n\n## Files to Always Check\n\n**High priority** (most likely to contain secrets):\n```\n.env, .env.*, .env.local, .env.production\nconfig.json, config.yaml, config.yml, config.toml\nsettings.py, settings.json\napplication.properties, application.yml\ndocker-compose.yml, docker-compose.*.yml\n.aws/credentials, .boto\n.netrc, .npmrc, .pypirc\nid_rsa, id_ecdsa, id_ed25519, *.pem, *.key\n```\n\n**Check .gitignore coverage**: Ensure these files are listed in `.gitignore`. If they are tracked by git, flag as a finding.\n\n**Git history**: Secrets may have been committed and later removed. Check with:\n```bash\ngit log --all --diff-filter=D -- \"*.env\" \"*.pem\" \"*.key\"\ngit log --all -p -S \"AKIA\" -- . # Search for AWS keys in history\n```\n\n## False Positive Reduction\n\nSkip matches that are likely not real secrets:\n- Values containing only placeholder text: `example`, `changeme`, `TODO`, `xxx`, `your_`, `placeholder`, `dummy`, `test`, `sample`\n- Values from documentation or comments on the same line as `example`, `e.g.`, `doc`, `TODO`\n- Values in test files matching `*_test.*`, `test_*.*`, `*.spec.*`, `**/test/**`, `**/tests/**`, `**/__tests__/**`\n- Environment variable references: `${VAR}`, `$VAR`, `%VAR%`, `os.environ`, `process.env`\n- Empty or whitespace-only values\n\n<!-- File: resources/example-skills/skill-security-auditor/references/vulnerability-patterns.md (Tokens: ~1685 | Category: anthropic-skill) -->\n# Vulnerability Patterns Reference\n\nDetailed patterns for identifying security vulnerabilities across languages and frameworks.\n\n## Table of Contents\n\n- [Injection Vulnerabilities](#injection-vulnerabilities)\n- [Authentication and Session Issues](#authentication-and-session-issues)\n- [Cryptographic Weaknesses](#cryptographic-weaknesses)\n- [Insecure Deserialization](#insecure-deserialization)\n- [Server-Side Request Forgery](#server-side-request-forgery)\n- [File Operations](#file-operations)\n- [Framework-Specific Patterns](#framework-specific-patterns)\n\n## Injection Vulnerabilities\n\n### SQL Injection\n\n**Vulnerable patterns** (string concatenation or f-strings in queries):\n```\n# Python\nexecute(f\"...{var}...\")\nexecute(\"...\" + var + \"...\")\nexecute(\"...%s...\" % var)\n\n# JavaScript\nquery(`...${var}...`)\nquery(\"...\" + var + \"...\")\n\n# Go\ndb.Query(\"...\" + var + \"...\")\nfmt.Sprintf(\"SELECT ... %s\", var) passed to Query()\n\n# Java\nstatement.execute(\"...\" + var + \"...\")\n```\n\n**Safe alternatives**: Parameterized queries, prepared statements, ORM query builders.\n\n### NoSQL Injection\n\n**Vulnerable patterns**:\n```javascript\n// MongoDB: user input directly in query object\ndb.collection.find({ user: req.body.user, pass: req.body.pass })\n// Attacker sends: { \"pass\": { \"$gt\": \"\" } }\n```\n\n**Safe alternative**: Validate input types, use `$eq` explicitly, sanitize with libraries like `mongo-sanitize`.\n\n### Command Injection\n\n**Vulnerable functions by language**:\n```\nPython:  os.system(), os.popen(), subprocess.call(shell=True), subprocess.Popen(shell=True)\nNode.js: child_process.exec(), child_process.execSync()\nGo:      exec.Command(\"sh\", \"-c\", userInput)\nJava:    Runtime.exec(userInput)\nPHP:     exec(), system(), passthru(), shell_exec(), backticks\nRuby:    system(), exec(), backticks, %x{}\n```\n\n**Safe alternative**: Use subprocess with list arguments (no shell), validate and allowlist input values.\n\n### LDAP Injection\n\n**Vulnerable pattern**:\n```python\nldap.search_s(base, scope, f\"(uid={username})\")\n```\n\n**Safe alternative**: Escape special characters `()*\\` and null bytes in user input.\n\n### XSS (Cross-Site Scripting)\n\n**Vulnerable sinks**:\n```\nJavaScript: innerHTML, outerHTML, document.write(), eval(), v-html, dangerouslySetInnerHTML\nTemplate:   |safe, {% autoescape off %}, !=, !{}, {!! !!}\n```\n\n**Safe alternatives**: Use `textContent`, template auto-escaping, CSP headers, DOMPurify for required HTML.\n\n## Authentication and Session Issues\n\n### Weak Password Storage\n\n**Vulnerable**:\n```python\n# Plaintext or weak hashing\nhashlib.md5(password.encode()).hexdigest()\nhashlib.sha256(password.encode()).hexdigest()\n```\n\n**Safe**:\n```python\n# Use adaptive hashing with salt\nimport bcrypt\nhashed = bcrypt.hashpw(password.encode(), bcrypt.gensalt(rounds=12))\n```\n\n### JWT Vulnerabilities\n\n**Common issues**:\n- Accepting `alg: \"none\"`\n- Using symmetric algorithms (HS256) with public keys\n- Not validating expiry (`exp`) or issuer (`iss`)\n- Storing sensitive data in payload (JWT is base64, not encrypted)\n\n**Verification checklist**:\n```python\n# Ensure algorithm is explicitly specified\njwt.decode(token, key, algorithms=[\"RS256\"])  # explicit algorithm\njwt.decode(token, key)  # VULNERABLE: accepts any algorithm\n```\n\n### Session Management\n\n**Issues to flag**:\n- Session IDs in URLs\n- Missing `HttpOnly`, `Secure`, `SameSite` flags on session cookies\n- No session timeout or rotation after authentication\n- Predictable session identifiers\n\n## Cryptographic Weaknesses\n\n### Insecure Algorithms\n\n**Deprecated/broken** (flag if found):\n```\nHash:    MD5, SHA1 (for security purposes)\nCipher:  DES, 3DES, RC4, Blowfish\nMode:    ECB mode for any block cipher\nRSA:     Key size < 2048 bits\n```\n\n**Acceptable**:\n```\nHash:    SHA-256, SHA-384, SHA-512, BLAKE2\nCipher:  AES-128/256-GCM, ChaCha20-Poly1305\nRSA:     2048+ bits with OAEP padding\nECDSA:   P-256 or P-384 curves\n```\n\n### Hardcoded Cryptographic Material\n\n**Flag if found in source**:\n- Encryption keys, IV/nonce values\n- Private keys (RSA, ECDSA, Ed25519)\n- Salt values for password hashing\n\n## Insecure Deserialization\n\n**Vulnerable functions by language**:\n```\nPython:  pickle.loads(), yaml.load() (without SafeLoader), marshal.loads()\nJava:    ObjectInputStream.readObject(), XMLDecoder\nPHP:     unserialize()\nRuby:    Marshal.load(), YAML.load()\nNode.js: node-serialize, js-yaml.load() (with dangerous schema)\n```\n\n**Safe alternatives**: Use JSON for data exchange, use safe loaders (`yaml.safe_load()`), validate and type-check deserialized data.\n\n## Server-Side Request Forgery\n\n**Vulnerable pattern**:\n```python\n# User controls the URL\nrequests.get(user_provided_url)\nurllib.request.urlopen(user_provided_url)\n```\n\n**Mitigations**:\n- Validate URLs against an allowlist of domains/IPs\n- Block requests to internal/private IP ranges (10.x, 172.16-31.x, 192.168.x, 127.x, 169.254.x)\n- Disable redirects or validate redirect targets\n- Use a network-level firewall for outbound requests\n\n## File Operations\n\n### Path Traversal\n\n**Vulnerable pattern**:\n```python\n# User controls filename\nopen(os.path.join(base_dir, user_filename))\n```\n\n**Safe pattern**:\n```python\nimport pathlib\nbase = pathlib.Path(base_dir).resolve()\ntarget = (base / user_filename).resolve()\nif not str(target).startswith(str(base)):\n    raise ValueError(\"Path traversal detected\")\n```\n\n### Unrestricted File Upload\n\n**Checklist**:\n- Validate file type by content (magic bytes), not just extension\n- Enforce maximum file size limits\n- Store uploads outside the web root\n- Generate random filenames, do not use user-supplied names\n- Scan uploads for malware when possible\n\n## Framework-Specific Patterns\n\n### Django\n\n```python\n# Dangerous: raw SQL\nModel.objects.raw(f\"SELECT * FROM t WHERE id = {user_id}\")\n# Safe: ORM or parameterized raw\nModel.objects.filter(id=user_id)\nModel.objects.raw(\"SELECT * FROM t WHERE id = %s\", [user_id])\n\n# Check settings.py\nDEBUG = True                      # Must be False in production\nALLOWED_HOSTS = ['*']            # Must be restricted\nCSRF_COOKIE_SECURE = False       # Must be True with HTTPS\nSESSION_COOKIE_SECURE = False    # Must be True with HTTPS\n```\n\n### Flask\n\n```python\n# Dangerous: XSS via Markup\nfrom markupsafe import Markup\nreturn Markup(f\"<p>{user_input}</p>\")\n# Safe: Use templates with auto-escaping\nreturn render_template(\"page.html\", data=user_input)\n\n# Check for debug mode\napp.run(debug=True)  # Must be False in production\n```\n\n### Express.js\n\n```javascript\n// Missing security headers - use helmet\nconst helmet = require('helmet');\napp.use(helmet());\n\n// Missing CSRF protection on state-changing routes\n// Missing rate limiting on auth endpoints\n// Missing input validation (use express-validator or zod)\n```\n\n### Spring Boot\n\n```java\n// Dangerous: SpEL injection\nparser.parseExpression(userInput).getValue();\n\n// Check application.properties\nserver.error.include-stacktrace=always  // Leaks internals\nmanagement.endpoints.web.exposure.include=*  // Exposes actuator\n```\n\n<!-- File: resources/example-skills/skill-security-auditor/SKILL.md (Tokens: ~1643 | Category: anthropic-skill) -->\n---\nname: skill-security-auditor\ndescription: \"Security auditing for code, configs, and infrastructure. Use when the user wants to audit or improve security: scan for vulnerabilities (SQL injection, XSS, command injection, path traversal), detect hardcoded secrets and credentials, review auth and authorization, check dependencies for known CVEs, audit config files for insecure defaults, or generate security reports. Trigger on \\\"security audit\\\", \\\"vulnerability scan\\\", \\\"code review for security\\\", \\\"find secrets\\\", \\\"check for vulnerabilities\\\", \\\"OWASP\\\", \\\"CVE\\\", or questions about code security.\"\nlicense: Complete terms in LICENSE.txt\n---\n\n# Security Auditor Guide\n\n## Overview\n\nThis guide covers security auditing workflows for source code, dependencies, and configurations. For detailed vulnerability patterns and detection rules, see references/vulnerability-patterns.md. For secrets detection patterns, see references/secrets-patterns.md.\n\n## Quick Start\n\nRun the bundled scan script against a project directory:\n\n```bash\npython scripts/scan_project.py /path/to/project\n```\n\nThis performs a lightweight scan for common issues: hardcoded secrets, dangerous function calls, and insecure patterns. For deeper analysis, follow the workflows below.\n\n### Testing the scripts\n\n```bash\npython scripts/scan_project.py /path/to/some/project --format text\npython scripts/scan_secrets.py /path/to/some/project --format text\n```\n\n## Audit Workflow\n\n### 1. Reconnaissance\n\nBefore auditing, understand the project:\n\n```bash\n# Identify languages, frameworks, and entry points\nfind . -type f -name \"*.py\" -o -name \"*.js\" -o -name \"*.ts\" -o -name \"*.go\" -o -name \"*.java\" | head -20\ncat package.json pyproject.toml requirements.txt go.mod pom.xml 2>/dev/null\n```\n\nKey questions:\n- What frameworks are used? (Express, Django, Flask, Spring, etc.)\n- Where are the entry points? (routes, controllers, API handlers)\n- How is authentication handled?\n- What external services are called?\n- Is user input accepted? Where?\n\n### 2. Secrets Detection\n\nScan for hardcoded credentials, API keys, and tokens. See references/secrets-patterns.md for the full pattern list.\n\n```bash\npython scripts/scan_secrets.py /path/to/project\n```\n\nCommon patterns to check:\n- API keys and tokens in source files\n- Database connection strings with embedded passwords\n- Private keys or certificates committed to the repo\n- `.env` files or config files with plaintext secrets\n- Secrets in CI/CD configuration files\n\n### 3. Vulnerability Scanning\n\n#### OWASP Top 10 Checklist\n\n| # | Category | What to Look For |\n|---|----------|-----------------|\n| A01 | Broken Access Control | Missing auth checks, IDOR, privilege escalation |\n| A02 | Cryptographic Failures | Weak algorithms, plaintext storage, missing TLS |\n| A03 | Injection | SQL, NoSQL, OS command, LDAP, XSS |\n| A04 | Insecure Design | Missing rate limits, business logic flaws |\n| A05 | Security Misconfiguration | Debug mode, default credentials, verbose errors |\n| A06 | Vulnerable Components | Outdated dependencies with known CVEs |\n| A07 | Auth Failures | Weak passwords, missing MFA, session issues |\n| A08 | Data Integrity Failures | Insecure deserialization, unsigned updates |\n| A09 | Logging Failures | Missing audit logs, sensitive data in logs |\n| A10 | SSRF | Unvalidated URLs in server-side requests |\n\n#### Language-Specific Checks\n\n**Python**\n```python\n# Dangerous: SQL injection\ncursor.execute(f\"SELECT * FROM users WHERE id = {user_id}\")\n# Safe: Parameterized query\ncursor.execute(\"SELECT * FROM users WHERE id = %s\", (user_id,))\n\n# Dangerous: Command injection\nos.system(f\"ping {hostname}\")\n# Safe: Use subprocess with list args\nsubprocess.run([\"ping\", hostname], capture_output=True)\n\n# Dangerous: Path traversal\nopen(f\"/data/{user_input}\")\n# Safe: Validate and resolve path\npath = pathlib.Path(\"/data\") / user_input\npath.resolve().relative_to(pathlib.Path(\"/data\").resolve())\n```\n\n**JavaScript/TypeScript**\n```javascript\n// Dangerous: XSS via innerHTML\nelement.innerHTML = userInput;\n// Safe: Use textContent or sanitize\nelement.textContent = userInput;\n\n// Dangerous: Prototype pollution\nObject.assign(target, JSON.parse(userInput));\n// Safe: Validate input structure\nconst parsed = JSON.parse(userInput);\nif (typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error();\nconst sanitized = Object.fromEntries(\n  Object.entries(parsed).filter(([k]) => !k.startsWith('__'))\n);\n\n// Dangerous: eval or Function constructor\neval(userInput);\n// Safe: Never use eval with user input\n```\n\n**Go**\n```go\n// Dangerous: SQL injection\ndb.Query(\"SELECT * FROM users WHERE id = \" + id)\n// Safe: Parameterized query\ndb.Query(\"SELECT * FROM users WHERE id = $1\", id)\n\n// Dangerous: Path traversal\nhttp.ServeFile(w, r, filepath.Join(baseDir, r.URL.Path))\n// Safe: Clean and validate path\ncleaned := filepath.Clean(r.URL.Path)\nfull := filepath.Join(baseDir, cleaned)\nif !strings.HasPrefix(full, baseDir) { http.Error(...) }\n```\n\n### 4. Dependency Audit\n\nCheck for known vulnerabilities in project dependencies:\n\n```bash\n# Python\npip audit\nsafety check -r requirements.txt\n\n# Node.js\nnpm audit\nnpx auditjs ossi\n\n# Go\ngovulncheck ./...\n\n# General (if Trivy is available)\ntrivy fs --scanners vuln /path/to/project\n```\n\nReview the output and categorize by severity (critical, high, medium, low). Critical and high severity findings should be addressed before deployment.\n\n### 5. Configuration Review\n\nCheck for insecure defaults in configuration files:\n\n```yaml\n# Common misconfigurations to flag:\nDEBUG: true                    # Debug mode in production\nALLOWED_HOSTS: [\"*\"]          # Unrestricted host access\nCORS_ALLOW_ALL_ORIGINS: true  # Open CORS policy\nSECRET_KEY: \"default\"         # Default or weak secret key\nSSL_VERIFY: false             # Disabled TLS verification\n```\n\nCheck infrastructure configs:\n- Dockerfiles: Running as root, exposing unnecessary ports\n- CI/CD: Secrets in plaintext, overly permissive permissions\n- Cloud configs: Public S3 buckets, open security groups\n\n### 6. Authentication and Authorization Review\n\nKey areas to verify:\n- Password hashing uses strong algorithms (bcrypt, argon2, scrypt)\n- Sessions have appropriate timeouts and rotation\n- JWT tokens are validated properly (algorithm, expiry, signature)\n- API endpoints enforce authorization checks\n- Role-based access control is consistently applied\n- Rate limiting is in place for login and sensitive endpoints\n\n## Report Format\n\nWhen generating a security audit report, use this structure:\n\n```markdown\n# Security Audit Report\n\n## Summary\n- **Project**: [name]\n- **Date**: [date]\n- **Scope**: [what was audited]\n- **Risk Level**: [Critical/High/Medium/Low]\n\n## Findings\n\n### [SEVERITY] Finding Title\n- **Category**: [OWASP category]\n- **Location**: [file:line]\n- **Description**: [what the issue is]\n- **Impact**: [what could happen if exploited]\n- **Recommendation**: [how to fix]\n\n## Statistics\n- Total findings: [count]\n- Critical: [count] | High: [count] | Medium: [count] | Low: [count]\n```\n\n## Next Steps\n\n- For detailed vulnerability patterns and code examples, see references/vulnerability-patterns.md\n- For secrets detection regex patterns, see references/secrets-patterns.md\n\n<!-- File: resources/example-skills/xlsx/SKILL.md (Tokens: ~2814 | Category: anthropic-skill) -->\n---\nname: xlsx\ndescription: \"Use this skill any time a spreadsheet file is the primary input or output. This means any task where the user wants to: open, read, edit, or fix an existing .xlsx, .xlsm, .csv, or .tsv file (e.g., adding columns, computing formulas, formatting, charting, cleaning messy data); create a new spreadsheet from scratch or from other data sources; or convert between tabular file formats. Trigger especially when the user references a spreadsheet file by name or path — even casually (like \\\"the xlsx in my downloads\\\") — and wants something done to it or produced from it. Also trigger for cleaning or restructuring messy tabular data files (malformed rows, misplaced headers, junk data) into proper spreadsheets. The deliverable must be a spreadsheet file. Do NOT trigger when the primary deliverable is a Word document, HTML report, standalone Python script, database pipeline, or Google Sheets API integration, even if tabular data is involved.\"\nlicense: Proprietary. LICENSE.txt has complete terms\n---\n\n# Requirements for Outputs\n\n## All Excel files\n\n### Professional Font\n- Use a consistent, professional font (e.g., Arial, Times New Roman) for all deliverables unless otherwise instructed by the user\n\n### Zero Formula Errors\n- Every Excel model MUST be delivered with ZERO formula errors (#REF!, #DIV/0!, #VALUE!, #N/A, #NAME?)\n\n### Preserve Existing Templates (when updating templates)\n- Study and EXACTLY match existing format, style, and conventions when modifying files\n- Never impose standardized formatting on files with established patterns\n- Existing template conventions ALWAYS override these guidelines\n\n## Financial models\n\n### Color Coding Standards\nUnless otherwise stated by the user or existing template\n\n#### Industry-Standard Color Conventions\n- **Blue text (RGB: 0,0,255)**: Hardcoded inputs, and numbers users will change for scenarios\n- **Black text (RGB: 0,0,0)**: ALL formulas and calculations\n- **Green text (RGB: 0,128,0)**: Links pulling from other worksheets within same workbook\n- **Red text (RGB: 255,0,0)**: External links to other files\n- **Yellow background (RGB: 255,255,0)**: Key assumptions needing attention or cells that need to be updated\n\n### Number Formatting Standards\n\n#### Required Format Rules\n- **Years**: Format as text strings (e.g., \"2024\" not \"2,024\")\n- **Currency**: Use $#,##0 format; ALWAYS specify units in headers (\"Revenue ($mm)\")\n- **Zeros**: Use number formatting to make all zeros \"-\", including percentages (e.g., \"$#,##0;($#,##0);-\")\n- **Percentages**: Default to 0.0% format (one decimal)\n- **Multiples**: Format as 0.0x for valuation multiples (EV/EBITDA, P/E)\n- **Negative numbers**: Use parentheses (123) not minus -123\n\n### Formula Construction Rules\n\n#### Assumptions Placement\n- Place ALL assumptions (growth rates, margins, multiples, etc.) in separate assumption cells\n- Use cell references instead of hardcoded values in formulas\n- Example: Use =B5*(1+$B$6) instead of =B5*1.05\n\n#### Formula Error Prevention\n- Verify all cell references are correct\n- Check for off-by-one errors in ranges\n- Ensure consistent formulas across all projection periods\n- Test with edge cases (zero values, negative numbers)\n- Verify no unintended circular references\n\n#### Documentation Requirements for Hardcodes\n- Comment or in cells beside (if end of table). Format: \"Source: [System/Document], [Date], [Specific Reference], [URL if applicable]\"\n- Examples:\n  - \"Source: Company 10-K, FY2024, Page 45, Revenue Note, [SEC EDGAR URL]\"\n  - \"Source: Company 10-Q, Q2 2025, Exhibit 99.1, [SEC EDGAR URL]\"\n  - \"Source: Bloomberg Terminal, 8/15/2025, AAPL US Equity\"\n  - \"Source: FactSet, 8/20/2025, Consensus Estimates Screen\"\n\n# XLSX creation, editing, and analysis\n\n## Overview\n\nA user may ask you to create, edit, or analyze the contents of an .xlsx file. You have different tools and workflows available for different tasks.\n\n## Important Requirements\n\n**LibreOffice Required for Formula Recalculation**: You can assume LibreOffice is installed for recalculating formula values using the `scripts/recalc.py` script. The script automatically configures LibreOffice on first run, including in sandboxed environments where Unix sockets are restricted (handled by `scripts/office/soffice.py`)\n\n## Reading and analyzing data\n\n### Data analysis with pandas\nFor data analysis, visualization, and basic operations, use **pandas** which provides powerful data manipulation capabilities:\n\n```python\nimport pandas as pd\n\n# Read Excel\ndf = pd.read_excel('file.xlsx')  # Default: first sheet\nall_sheets = pd.read_excel('file.xlsx', sheet_name=None)  # All sheets as dict\n\n# Analyze\ndf.head()      # Preview data\ndf.info()      # Column info\ndf.describe()  # Statistics\n\n# Write Excel\ndf.to_excel('output.xlsx', index=False)\n```\n\n## Excel File Workflows\n\n## CRITICAL: Use Formulas, Not Hardcoded Values\n\n**Always use Excel formulas instead of calculating values in Python and hardcoding them.** This ensures the spreadsheet remains dynamic and updateable.\n\n### ❌ WRONG - Hardcoding Calculated Values\n```python\n# Bad: Calculating in Python and hardcoding result\ntotal = df['Sales'].sum()\nsheet['B10'] = total  # Hardcodes 5000\n\n# Bad: Computing growth rate in Python\ngrowth = (df.iloc[-1]['Revenue'] - df.iloc[0]['Revenue']) / df.iloc[0]['Revenue']\nsheet['C5'] = growth  # Hardcodes 0.15\n\n# Bad: Python calculation for average\navg = sum(values) / len(values)\nsheet['D20'] = avg  # Hardcodes 42.5\n```\n\n### ✅ CORRECT - Using Excel Formulas\n```python\n# Good: Let Excel calculate the sum\nsheet['B10'] = '=SUM(B2:B9)'\n\n# Good: Growth rate as Excel formula\nsheet['C5'] = '=(C4-C2)/C2'\n\n# Good: Average using Excel function\nsheet['D20'] = '=AVERAGE(D2:D19)'\n```\n\nThis applies to ALL calculations - totals, percentages, ratios, differences, etc. The spreadsheet should be able to recalculate when source data changes.\n\n## Common Workflow\n1. **Choose tool**: pandas for data, openpyxl for formulas/formatting\n2. **Create/Load**: Create new workbook or load existing file\n3. **Modify**: Add/edit data, formulas, and formatting\n4. **Save**: Write to file\n5. **Recalculate formulas (MANDATORY IF USING FORMULAS)**: Use the scripts/recalc.py script\n   ```bash\n   python scripts/recalc.py output.xlsx\n   ```\n6. **Verify and fix any errors**: \n   - The script returns JSON with error details\n   - If `status` is `errors_found`, check `error_summary` for specific error types and locations\n   - Fix the identified errors and recalculate again\n   - Common errors to fix:\n     - `#REF!`: Invalid cell references\n     - `#DIV/0!`: Division by zero\n     - `#VALUE!`: Wrong data type in formula\n     - `#NAME?`: Unrecognized formula name\n\n### Creating new Excel files\n\n```python\n# Using openpyxl for formulas and formatting\nfrom openpyxl import Workbook\nfrom openpyxl.styles import Font, PatternFill, Alignment\n\nwb = Workbook()\nsheet = wb.active\n\n# Add data\nsheet['A1'] = 'Hello'\nsheet['B1'] = 'World'\nsheet.append(['Row', 'of', 'data'])\n\n# Add formula\nsheet['B2'] = '=SUM(A1:A10)'\n\n# Formatting\nsheet['A1'].font = Font(bold=True, color='FF0000')\nsheet['A1'].fill = PatternFill('solid', start_color='FFFF00')\nsheet['A1'].alignment = Alignment(horizontal='center')\n\n# Column width\nsheet.column_dimensions['A'].width = 20\n\nwb.save('output.xlsx')\n```\n\n### Editing existing Excel files\n\n```python\n# Using openpyxl to preserve formulas and formatting\nfrom openpyxl import load_workbook\n\n# Load existing file\nwb = load_workbook('existing.xlsx')\nsheet = wb.active  # or wb['SheetName'] for specific sheet\n\n# Working with multiple sheets\nfor sheet_name in wb.sheetnames:\n    sheet = wb[sheet_name]\n    print(f\"Sheet: {sheet_name}\")\n\n# Modify cells\nsheet['A1'] = 'New Value'\nsheet.insert_rows(2)  # Insert row at position 2\nsheet.delete_cols(3)  # Delete column 3\n\n# Add new sheet\nnew_sheet = wb.create_sheet('NewSheet')\nnew_sheet['A1'] = 'Data'\n\nwb.save('modified.xlsx')\n```\n\n## Recalculating formulas\n\nExcel files created or modified by openpyxl contain formulas as strings but not calculated values. Use the provided `scripts/recalc.py` script to recalculate formulas:\n\n```bash\npython scripts/recalc.py <excel_file> [timeout_seconds]\n```\n\nExample:\n```bash\npython scripts/recalc.py output.xlsx 30\n```\n\nThe script:\n- Automatically sets up LibreOffice macro on first run\n- Recalculates all formulas in all sheets\n- Scans ALL cells for Excel errors (#REF!, #DIV/0!, etc.)\n- Returns JSON with detailed error locations and counts\n- Works on both Linux and macOS\n\n## Formula Verification Checklist\n\nQuick checks to ensure formulas work correctly:\n\n### Essential Verification\n- [ ] **Test 2-3 sample references**: Verify they pull correct values before building full model\n- [ ] **Column mapping**: Confirm Excel columns match (e.g., column 64 = BL, not BK)\n- [ ] **Row offset**: Remember Excel rows are 1-indexed (DataFrame row 5 = Excel row 6)\n\n### Common Pitfalls\n- [ ] **NaN handling**: Check for null values with `pd.notna()`\n- [ ] **Far-right columns**: FY data often in columns 50+ \n- [ ] **Multiple matches**: Search all occurrences, not just first\n- [ ] **Division by zero**: Check denominators before using `/` in formulas (#DIV/0!)\n- [ ] **Wrong references**: Verify all cell references point to intended cells (#REF!)\n- [ ] **Cross-sheet references**: Use correct format (Sheet1!A1) for linking sheets\n\n### Formula Testing Strategy\n- [ ] **Start small**: Test formulas on 2-3 cells before applying broadly\n- [ ] **Verify dependencies**: Check all cells referenced in formulas exist\n- [ ] **Test edge cases**: Include zero, negative, and very large values\n\n### Interpreting scripts/recalc.py Output\nThe script returns JSON with error details:\n```json\n{\n  \"status\": \"success\",           // or \"errors_found\"\n  \"total_errors\": 0,              // Total error count\n  \"total_formulas\": 42,           // Number of formulas in file\n  \"error_summary\": {              // Only present if errors found\n    \"#REF!\": {\n      \"count\": 2,\n      \"locations\": [\"Sheet1!B5\", \"Sheet1!C10\"]\n    }\n  }\n}\n```\n\n## Best Practices\n\n### Library Selection\n- **pandas**: Best for data analysis, bulk operations, and simple data export\n- **openpyxl**: Best for complex formatting, formulas, and Excel-specific features\n\n### Working with openpyxl\n- Cell indices are 1-based (row=1, column=1 refers to cell A1)\n- Use `data_only=True` to read calculated values: `load_workbook('file.xlsx', data_only=True)`\n- **Warning**: If opened with `data_only=True` and saved, formulas are replaced with values and permanently lost\n- For large files: Use `read_only=True` for reading or `write_only=True` for writing\n- Formulas are preserved but not evaluated - use scripts/recalc.py to update values\n\n### Working with pandas\n- Specify data types to avoid inference issues: `pd.read_excel('file.xlsx', dtype={'id': str})`\n- For large files, read specific columns: `pd.read_excel('file.xlsx', usecols=['A', 'C', 'E'])`\n- Handle dates properly: `pd.read_excel('file.xlsx', parse_dates=['date_column'])`\n\n## Code Style Guidelines\n**IMPORTANT**: When generating Python code for Excel operations:\n- Write minimal, concise Python code without unnecessary comments\n- Avoid verbose variable names and redundant operations\n- Avoid unnecessary print statements\n\n**For Excel files themselves**:\n- Add comments to cells with complex formulas or important assumptions\n- Document data sources for hardcoded values\n- Include notes for key calculations and model sections\n</yakaai_skills>"}