diff --git a/.github/workflows/skill-review.yml b/.github/workflows/skill-review.yml new file mode 100644 index 0000000..aee21d6 --- /dev/null +++ b/.github/workflows/skill-review.yml @@ -0,0 +1,22 @@ +# Tessl Skill Review — runs on PRs that change any SKILL.md; posts scores as one PR comment. +# Docs: https://github.com/tesslio/skill-review +name: Tessl Skill Review + +on: + pull_request: + branches: [main] + paths: + - "**/SKILL.md" + +jobs: + review: + runs-on: ubuntu-latest + permissions: + pull-requests: write + contents: read + steps: + - uses: actions/checkout@v4 + - uses: tesslio/skill-review@main + # Optional quality gate (off by default — do not enable unless user asked): + # with: + # fail-threshold: 70 diff --git a/application/skills/book-search/SKILL.md b/application/skills/book-search/SKILL.md index 49ce398..5fdca77 100644 --- a/application/skills/book-search/SKILL.md +++ b/application/skills/book-search/SKILL.md @@ -1,75 +1,42 @@ --- name: book-search -description: Search for books using Kyobo Book Centre's online catalog. Use when users want to find books by keyword, title, author, or topic. Supports Korean and English search terms and returns book titles with direct purchase links. Perfect for book recommendations, finding specific titles, or discovering books on particular subjects. +description: "Search for books using Kyobo Book Centre's online catalog. Use when users want to find books by keyword, title, author, or topic. Supports Korean and English search terms and returns book titles with direct purchase links. Perfect for book recommendations, finding specific titles, or discovering books on particular subjects." --- # Book Search -Search for books using Kyobo Book Centre's comprehensive online catalog. +Search for books using Kyobo Book Centre's online catalog. -## Quick Start +## Script Location -Use the search script to find books by any keyword: +**IMPORTANT**: Always use the FULL path `skills/book-search/scripts/search_books.py` — do NOT shorten to `scripts/search_books.py`. + +## Quick Start ```python import subprocess -result = subprocess.run(['python', 'scripts/search_books.py', 'keyword'], - capture_output=True, text=True, cwd='book-search') +result = subprocess.run(['python', 'skills/book-search/scripts/search_books.py', 'keyword'], + capture_output=True, text=True) print(result.stdout) ``` -## Script Location - -The search script is located at `skills/book-search/scripts/search_books.py` relative to the application working directory. -**IMPORTANT**: Always use the FULL path `skills/book-search/scripts/search_books.py` — do NOT shorten to `scripts/search_books.py`. - -## Features - -- **Keyword Search**: Find books by title, author, topic, or any relevant term -- **Korean & English Support**: Search in both Korean and English -- **Top Results**: Returns up to 5 most relevant books -- **Direct Links**: Provides direct URLs to book pages for purchase -- **Error Handling**: Graceful handling of network issues and parsing errors - ## Usage Examples -### Basic Search ```python -# Search for programming books -result = subprocess.run(['python', 'scripts/search_books.py', '프로그래밍'], - capture_output=True, text=True, cwd='book-search') -``` +# Search by keyword (Korean) +subprocess.run(['python', 'skills/book-search/scripts/search_books.py', '프로그래밍'], capture_output=True, text=True) -### Author Search -```python -# Search by author name -result = subprocess.run(['python', 'scripts/search_books.py', '무라카미 하루키'], - capture_output=True, text=True, cwd='book-search') -``` +# Search by author +subprocess.run(['python', 'skills/book-search/scripts/search_books.py', '무라카미 하루키'], capture_output=True, text=True) -### Topic Search -```python -# Search by topic -result = subprocess.run(['python', 'scripts/search_books.py', 'artificial intelligence'], - capture_output=True, text=True, cwd='book-search') +# Search by topic (English) +subprocess.run(['python', 'skills/book-search/scripts/search_books.py', 'artificial intelligence'], capture_output=True, text=True) ``` -## Implementation Notes - -- Uses web scraping with proper User-Agent headers -- Handles URL encoding for special characters -- Returns formatted results with titles and purchase links -- Limited to top 5 results to avoid overwhelming output -- Includes error handling for network and parsing issues +Returns up to 5 results with titles and direct Kyobo purchase links. ## Dependencies -The script requires: -- `requests` - for HTTP requests -- `beautifulsoup4` - for HTML parsing -- `urllib.parse` - for URL encoding (built-in) - -Install dependencies: ```bash pip install requests beautifulsoup4 ``` \ No newline at end of file diff --git a/application/skills/notion/SKILL.md b/application/skills/notion/SKILL.md index f01d167..100afe4 100644 --- a/application/skills/notion/SKILL.md +++ b/application/skills/notion/SKILL.md @@ -1,12 +1,11 @@ --- name: notion -description: Notion API for creating and managing pages, databases, and blocks. -homepage: https://developers.notion.com +description: "Interact with Notion workspaces via the Notion API. Create, read, update, and search pages, databases (data sources), and blocks. Use when the user mentions Notion, wants to create or edit Notion pages, query Notion databases, manage workspace content, add blocks, update properties, or sync data with Notion. Triggers on terms like 'Notion', 'Notion page', 'Notion database', 'Notion doc', 'add to Notion', 'Notion workspace'. Requires NOTION_API_KEY." --- -# notion +# Notion API -Use the Notion API to create/read/update pages, data sources (databases), and blocks. +Create, read, update, and search pages, databases (data sources), and blocks via the Notion API. ## Setup @@ -15,18 +14,25 @@ Use the Notion API to create/read/update pages, data sources (databases), and bl 3. Set the environment variable `NOTION_API_KEY` 4. Share target pages/databases with your integration (click "..." → "Connect to" → your integration name) +**Verify connection:** + +```bash +curl -s "https://api.notion.com/v1/users/me" \ + -H "Authorization: Bearer $NOTION_API_KEY" \ + -H "Notion-Version: 2025-09-03" | python3 -c "import sys,json; print(json.load(sys.stdin).get('name','ERROR'))" +``` + ## API Basics -All requests need: +All requests require these headers: ```bash -curl -X GET "https://api.notion.com/v1/..." \ - -H "Authorization: Bearer $NOTION_API_KEY" \ - -H "Notion-Version: 2025-09-03" \ - -H "Content-Type: application/json" +-H "Authorization: Bearer $NOTION_API_KEY" \ +-H "Notion-Version: 2025-09-03" \ +-H "Content-Type: application/json" ``` -> **Note:** The `Notion-Version` header is required. This skill uses `2025-09-03` (latest). In this version, databases are called "data sources" in the API. +> **Note:** `Notion-Version: 2025-09-03` is the latest. In this version, databases are called "data sources" in the API. ## Common Operations @@ -40,20 +46,14 @@ curl -X POST "https://api.notion.com/v1/search" \ -d '{"query": "page title"}' ``` -**Get page:** +**Get page / page content:** ```bash curl "https://api.notion.com/v1/pages/{page_id}" \ - -H "Authorization: Bearer $NOTION_API_KEY" \ - -H "Notion-Version: 2025-09-03" -``` + -H "Authorization: Bearer $NOTION_API_KEY" -H "Notion-Version: 2025-09-03" -**Get page content (blocks):** - -```bash curl "https://api.notion.com/v1/blocks/{page_id}/children" \ - -H "Authorization: Bearer $NOTION_API_KEY" \ - -H "Notion-Version: 2025-09-03" + -H "Authorization: Bearer $NOTION_API_KEY" -H "Notion-Version: 2025-09-03" ``` **Create page in a data source:** @@ -152,9 +152,17 @@ Common property formats for database items: - **Parent in responses:** Pages show `parent.data_source_id` alongside `parent.database_id` - **Finding the data_source_id:** Search for the database, or call `GET /v1/data_sources/{data_source_id}` +## Troubleshooting + +| Error | Cause | Fix | +|-------|-------|-----| +| 401 Unauthorized | Bad or missing API key | Check `NOTION_API_KEY` is set and valid | +| 403 Forbidden | Page not shared with integration | Share page via "..." → "Connect to" | +| 404 Not Found | Wrong page/database ID | Verify UUID; try searching first | +| 429 Rate Limited | Too many requests (~3/sec avg) | Add delays between calls | + ## Notes - Page/database IDs are UUIDs (with or without dashes) - The API cannot set database view filters — that's UI-only -- Rate limit: ~3 requests/second average - Use `is_inline: true` when creating data sources to embed them in pages \ No newline at end of file diff --git a/application/skills/pdf/SKILL.md b/application/skills/pdf/SKILL.md index e7f0d42..23bdc3f 100644 --- a/application/skills/pdf/SKILL.md +++ b/application/skills/pdf/SKILL.md @@ -1,26 +1,30 @@ --- 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. +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." --- # PDF Processing Guide -## Overview - -This guide covers essential PDF processing operations using Python libraries. Use the `execute_code` tool to run the Python code shown below. All generated files should be saved to the `artifacts/` directory. -## 한국어 폰트 설정 (필수 — 모든 PDF 생성 코드에 포함할 것) +## Quick Reference -한국어가 포함된 PDF를 만들 때는 반드시 한국어 폰트를 등록해야 합니다. -아래 폰트 등록 코드를 **모든 PDF 생성 코드의 맨 앞에 반드시 포함**하세요. +| Task | Library | Key Function | +|------|---------|-------------| +| Create PDF | reportlab | SimpleDocTemplate / canvas | +| Read/Merge/Split PDF | pypdf | PdfReader / PdfWriter | +| Extract tables | pdfplumber | page.extract_tables() | +| Password protect | pypdf | writer.encrypt() | +| Rotate pages | pypdf | page.rotate() | + +## 한국어 폰트 설정 (필수) -**중요**: macOS의 AppleSDGothicNeo.ttc는 PostScript outlines이라 reportlab에서 사용할 수 없습니다. +한국어 PDF를 만들 때 반드시 이 함수를 호출하여 폰트를 등록한다. **모든 PDF 생성 코드의 맨 앞에 포함할 것.** -폰트 우선순위: -1. `assets/NanumGothic-Regular.ttf` (TTF 파일 — 가장 확실) -2. CID 폰트 `HYGothic-Medium` (reportlab 내장 — 별도 파일 불필요, 확실한 폴백) +- **절대 사용 금지**: macOS `AppleSDGothicNeo.ttc` (PostScript outlines — reportlab 비호환) +- 폰트 미등록 시 한국어가 깨지거나 빈 사각형(□)으로 표시됨 +- NEVER use Unicode subscript/superscript characters (₀₁₂₃₄₅₆₇₈₉) in ReportLab — use `` and `` tags instead ```python import os @@ -29,37 +33,30 @@ from reportlab.pdfbase.ttfonts import TTFont from reportlab.pdfbase.cidfonts import UnicodeCIDFont def register_korean_font(): - """한국어 폰트를 등록하고 폰트 이름을 반환한다. PDF 생성 전에 반드시 호출.""" - # 1순위: NanumGothic TTF - ttf_paths = [ - os.path.join("assets", "NanumGothic-Regular.ttf"), - "/usr/share/fonts/truetype/nanum/NanumGothic.ttf", - "/usr/share/fonts/nanum/NanumGothic.ttf", - "/Library/Fonts/NanumGothic.ttf", - ] - for path in ttf_paths: + """Register Korean font and return font name. Call before any PDF generation.""" + for path in [os.path.join("assets", "NanumGothic-Regular.ttf"), + "/usr/share/fonts/truetype/nanum/NanumGothic.ttf", + "/usr/share/fonts/nanum/NanumGothic.ttf", + "/Library/Fonts/NanumGothic.ttf"]: if os.path.exists(path): try: pdfmetrics.registerFont(TTFont("KoreanFont", path)) return "KoreanFont" except Exception: continue - - # 2순위: CID 폰트 (reportlab 내장, 별도 파일 불필요) try: pdfmetrics.registerFont(UnicodeCIDFont("HYGothic-Medium")) return "HYGothic-Medium" except Exception: - pass - - return "Helvetica" # 최후 폴백 (한국어 미지원) + return "Helvetica" font_name = register_korean_font() ``` ## Creating New PDFs (reportlab) -### Basic PDF Creation (영문 전용) +### Basic PDF (영문) + ```python from reportlab.lib.pagesizes import A4 from reportlab.pdfgen import canvas @@ -72,112 +69,57 @@ c.drawString(100, height - 100, "Hello World!") c.save() ``` -### 한국어 PDF 생성 (권장 패턴) +### 한국어 PDF (권장 패턴) + +Call `register_korean_font()` first (see above), then use `font_name` in styles: + ```python -import os from reportlab.lib.pagesizes import A4 from reportlab.lib.units import inch from reportlab.lib import colors from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle -from reportlab.pdfbase import pdfmetrics -from reportlab.pdfbase.ttfonts import TTFont -from reportlab.pdfbase.cidfonts import UnicodeCIDFont - -# 1) 한국어 폰트 등록 -font_name = "Helvetica" -for path in [os.path.join("assets", "NanumGothic-Regular.ttf"), - "/usr/share/fonts/truetype/nanum/NanumGothic.ttf"]: - if os.path.exists(path): - try: - pdfmetrics.registerFont(TTFont("KoreanFont", path)) - font_name = "KoreanFont" - break - except Exception: - continue -if font_name == "Helvetica": - try: - pdfmetrics.registerFont(UnicodeCIDFont("HYGothic-Medium")) - font_name = "HYGothic-Medium" - except Exception: - pass -# 2) 한국어 스타일 정의 +# Use font_name from register_korean_font() above styles = getSampleStyleSheet() -styles.add(ParagraphStyle("Title_KO", parent=styles["Title"], fontName=font_name, fontSize=20, spaceAfter=20, textColor=colors.HexColor("#1a1a2e"))) -styles.add(ParagraphStyle("H1_KO", parent=styles["Heading1"], fontName=font_name, fontSize=16, spaceAfter=14, textColor=colors.HexColor("#16213e"))) -styles.add(ParagraphStyle("H2_KO", parent=styles["Heading2"], fontName=font_name, fontSize=14, spaceAfter=12, textColor=colors.HexColor("#0f3460"))) -styles.add(ParagraphStyle("Normal_KO", parent=styles["Normal"], fontName=font_name, fontSize=10, leading=14, spaceAfter=8)) -styles.add(ParagraphStyle("Bullet_KO", parent=styles["Normal"], fontName=font_name, fontSize=10, leading=14, leftIndent=20, bulletIndent=10)) +styles.add(ParagraphStyle("Title_KO", parent=styles["Title"], fontName=font_name, fontSize=20, spaceAfter=20, textColor=colors.HexColor("#1a1a2e"))) +styles.add(ParagraphStyle("H1_KO", parent=styles["Heading1"], fontName=font_name, fontSize=16, spaceAfter=14, textColor=colors.HexColor("#16213e"))) +styles.add(ParagraphStyle("Normal_KO", parent=styles["Normal"], fontName=font_name, fontSize=10, leading=14, spaceAfter=8)) +styles.add(ParagraphStyle("Bullet_KO", parent=styles["Normal"], fontName=font_name, fontSize=10, leading=14, leftIndent=20, bulletIndent=10)) -# 3) PDF 빌드 os.makedirs("artifacts", exist_ok=True) doc = SimpleDocTemplate("artifacts/report.pdf", pagesize=A4, topMargin=0.8*inch, bottomMargin=0.8*inch, leftMargin=0.75*inch, rightMargin=0.75*inch) -story = [] -story.append(Paragraph("보고서 제목", styles["Title_KO"])) -story.append(Spacer(1, 16)) -story.append(Paragraph("1. 개요", styles["H1_KO"])) -story.append(Paragraph("이 보고서는 예시 내용을 담고 있습니다.", styles["Normal_KO"])) -story.append(Spacer(1, 8)) -story.append(Paragraph("2. 상세 내용", styles["H1_KO"])) -story.append(Paragraph("• 첫 번째 항목", styles["Bullet_KO"])) -story.append(Paragraph("• 두 번째 항목", styles["Bullet_KO"])) -story.append(PageBreak()) -story.append(Paragraph("3. 부록", styles["H1_KO"])) -story.append(Paragraph("추가 내용입니다.", styles["Normal_KO"])) - +story = [ + Paragraph("보고서 제목", styles["Title_KO"]), + Spacer(1, 16), + Paragraph("1. 개요", styles["H1_KO"]), + Paragraph("이 보고서는 예시 내용을 담고 있습니다.", styles["Normal_KO"]), +] doc.build(story) -print("PDF 생성 완료: artifacts/report.pdf") ``` -### 한국어 테이블이 포함된 PDF +### 한국어 테이블 PDF + +Call `register_korean_font()` first, then: + ```python -import os from reportlab.lib.pagesizes import A4 from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib import colors -from reportlab.pdfbase import pdfmetrics -from reportlab.pdfbase.ttfonts import TTFont -from reportlab.pdfbase.cidfonts import UnicodeCIDFont - -# 폰트 등록 -font_name = "Helvetica" -for path in [os.path.join("assets", "NanumGothic-Regular.ttf"), - "/usr/share/fonts/truetype/nanum/NanumGothic.ttf"]: - if os.path.exists(path): - try: - pdfmetrics.registerFont(TTFont("KoreanFont", path)) - font_name = "KoreanFont" - break - except Exception: - continue -if font_name == "Helvetica": - try: - pdfmetrics.registerFont(UnicodeCIDFont("HYGothic-Medium")) - font_name = "HYGothic-Medium" - except Exception: - pass styles = getSampleStyleSheet() -styles.add(ParagraphStyle("Title_KO", parent=styles["Title"], fontName=font_name, fontSize=18, textColor=colors.HexColor("#1a1a2e"))) -styles.add(ParagraphStyle("Normal_KO", parent=styles["Normal"], fontName=font_name, fontSize=10)) +styles.add(ParagraphStyle("Title_KO", parent=styles["Title"], fontName=font_name, fontSize=18, textColor=colors.HexColor("#1a1a2e"))) os.makedirs("artifacts", exist_ok=True) doc = SimpleDocTemplate("artifacts/table_report.pdf", pagesize=A4) -data = [ - ["항목", "설명", "비용"], - ["서버", "EC2 인스턴스", "$120"], - ["스토리지", "S3 버킷", "$45"], - ["데이터베이스", "RDS PostgreSQL", "$89"], -] +data = [["항목", "설명", "비용"], ["서버", "EC2 인스턴스", "$120"], ["스토리지", "S3 버킷", "$45"]] table = Table(data, colWidths=[120, 200, 80]) table.setStyle(TableStyle([ ("BACKGROUND", (0, 0), (-1, 0), colors.HexColor("#e8eaf6")), - ("TEXTCOLOR", (0, 0), (-1, 0), colors.HexColor("#1a1a2e")), ("FONTNAME", (0, 0), (-1, -1), font_name), ("FONTSIZE", (0, 0), (-1, -1), 10), ("GRID", (0, 0), (-1, -1), 0.5, colors.HexColor("#bdbdbd")), @@ -185,62 +127,45 @@ table.setStyle(TableStyle([ ("TOPPADDING", (0, 0), (-1, -1), 6), ("BOTTOMPADDING", (0, 0), (-1, -1), 6), ])) - -doc.build([ - Paragraph("비용 분석 보고서", styles["Title_KO"]), - Spacer(1, 16), - table -]) -print("PDF 생성 완료: artifacts/table_report.pdf") +doc.build([Paragraph("비용 분석 보고서", styles["Title_KO"]), Spacer(1, 16), table]) ``` -### Important Notes for reportlab -- **한국어 텍스트를 사용할 때는 반드시 위의 폰트 등록 코드를 포함하세요.** -- macOS의 `AppleSDGothicNeo.ttc`는 PostScript outlines이라 reportlab에서 사용할 수 없습니다. 절대 사용하지 마세요. -- TTF 폰트(`assets/NanumGothic-Regular.ttf`)가 없으면 CID 폰트 `HYGothic-Medium`을 사용하세요. -- 폰트를 등록하지 않으면 한국어가 깨지거나 빈 사각형(□)으로 표시됩니다. -- NEVER use Unicode subscript/superscript characters (₀₁₂₃₄₅₆₇₈₉) in ReportLab PDFs — use `` and `` tags instead. - ## Reading PDFs (pypdf) -### Extract Text ```python from pypdf import PdfReader reader = PdfReader("input.pdf") -text = "" -for page in reader.pages: - text += page.extract_text() -print(text) +text = "".join(page.extract_text() for page in reader.pages) ``` ### Merge PDFs + ```python from pypdf import PdfWriter, PdfReader writer = PdfWriter() for pdf_file in ["doc1.pdf", "doc2.pdf"]: - reader = PdfReader(pdf_file) - for page in reader.pages: + for page in PdfReader(pdf_file).pages: writer.add_page(page) - -with open("artifacts/merged.pdf", "wb") as output: - writer.write(output) +with open("artifacts/merged.pdf", "wb") as f: + writer.write(f) ``` ### Split PDF + ```python from pypdf import PdfReader, PdfWriter -reader = PdfReader("input.pdf") -for i, page in enumerate(reader.pages): +for i, page in enumerate(PdfReader("input.pdf").pages): writer = PdfWriter() writer.add_page(page) - with open(f"artifacts/page_{i+1}.pdf", "wb") as output: - writer.write(output) + with open(f"artifacts/page_{i+1}.pdf", "wb") as f: + writer.write(f) ``` ### Rotate Pages + ```python from pypdf import PdfReader, PdfWriter @@ -249,23 +174,21 @@ writer = PdfWriter() page = reader.pages[0] page.rotate(90) writer.add_page(page) - -with open("artifacts/rotated.pdf", "wb") as output: - writer.write(output) +with open("artifacts/rotated.pdf", "wb") as f: + writer.write(f) ``` ### Password Protection + ```python from pypdf import PdfReader, PdfWriter -reader = PdfReader("input.pdf") writer = PdfWriter() -for page in reader.pages: +for page in PdfReader("input.pdf").pages: writer.add_page(page) writer.encrypt("userpassword", "ownerpassword") - -with open("artifacts/encrypted.pdf", "wb") as output: - writer.write(output) +with open("artifacts/encrypted.pdf", "wb") as f: + writer.write(f) ``` ## Table Extraction (pdfplumber) @@ -275,19 +198,7 @@ import pdfplumber with pdfplumber.open("input.pdf") as pdf: for page in pdf.pages: - text = page.extract_text() - tables = page.extract_tables() - for table in tables: + for table in page.extract_tables(): for row in table: print(row) ``` - -## Quick Reference - -| Task | Library | Key Function | -|------|---------|-------------| -| Create PDF | reportlab | SimpleDocTemplate / canvas | -| Read/Merge/Split PDF | pypdf | PdfReader / PdfWriter | -| Extract tables | pdfplumber | page.extract_tables() | -| Password protect | pypdf | writer.encrypt() | -| Rotate pages | pypdf | page.rotate() | diff --git a/application/skills/skill-creator/SKILL.md b/application/skills/skill-creator/SKILL.md index 0467215..53c933e 100644 --- a/application/skills/skill-creator/SKILL.md +++ b/application/skills/skill-creator/SKILL.md @@ -1,26 +1,10 @@ --- name: skill-creator -description: Create or update AgentSkills. Use when designing, structuring, or packaging skills with scripts, references, and assets. +description: "Create, update, and package agent skills (SKILL.md files with scripts, references, and assets). Use when designing new skills, structuring skill directories, writing SKILL.md frontmatter and instructions, initializing skill templates, packaging .skill files, or iterating on existing skills. Triggers on 'create skill', 'new skill', 'SKILL.md', 'skill template', 'package skill', 'skill file', 'agent capability'." --- # Skill Creator -This skill provides guidance for creating effective skills. - -## About Skills - -Skills are modular, self-contained packages that extend the agent's capabilities by providing -specialized knowledge, workflows, and tools. Think of them as "onboarding guides" for specific -domains or tasks—they transform the agent from a general-purpose agent into a specialized agent -equipped with procedural knowledge that no model can fully possess. - -### What Skills Provide - -1. Specialized workflows - Multi-step procedures for specific domains -2. Tool integrations - Instructions for working with specific file formats or APIs -3. Domain expertise - Company-specific knowledge, schemas, business logic -4. Bundled resources - Scripts, references, and assets for complex and repetitive tasks - ## Core Principles ### Concise is Key diff --git a/application/skills/tavily-search/SKILL.md b/application/skills/tavily-search/SKILL.md index 00bc2ef..83fdd83 100644 --- a/application/skills/tavily-search/SKILL.md +++ b/application/skills/tavily-search/SKILL.md @@ -1,119 +1,60 @@ --- name: tavily-search -description: Web search using Tavily AI-powered search API. Returns AI-synthesized answers with citations and structured search results. Use when the user explicitly requests Tavily search, or when high-quality AI-synthesized answers with citations are needed for research, fact-checking, or comprehensive information gathering. Requires TAVILY_API_KEY. +description: "Web search using Tavily AI-powered search API. Returns AI-synthesized answers with citations and structured search results. Use when the user explicitly requests Tavily search, or when high-quality AI-synthesized answers with citations are needed for research, fact-checking, or comprehensive information gathering. Requires TAVILY_API_KEY." --- # Tavily Search AI-powered web search that returns synthesized answers with citations and structured results. -## When to Use - -- User explicitly requests "use Tavily" or "search with Tavily" -- Research tasks requiring comprehensive, cited answers -- Fact-checking with source verification -- Alternative to Brave/Perplexity when specifically requested - ## Requirements -- Python 3.6+ -- `tavily-python` package: `pip install tavily-python` -- `TAVILY_API_KEY` environment variable - -Get your API key at: https://tavily.com +- `pip install tavily-python` +- `TAVILY_API_KEY` environment variable (get key at https://tavily.com) ## Script Location -The search script is located at `skills/tavily-search/scripts/search.py` relative to the application working directory. **IMPORTANT**: Always use the FULL path `skills/tavily-search/scripts/search.py` — do NOT shorten to `scripts/search.py`. ## Quick Start -### Basic search - ```bash +# Basic search python skills/tavily-search/scripts/search.py "latest AI developments" -``` - -### Advanced search with more results -```bash +# Advanced search with more results python skills/tavily-search/scripts/search.py "quantum computing breakthroughs" --max-results 10 --depth advanced -``` - -### Text format output -```bash +# Text format output python skills/tavily-search/scripts/search.py "climate change news" --format text ``` -## Usage - -### Command-line options +## Command-Line Options -- `query` (required): Search query -- `--max-results N`: Maximum results (1-10, default: 5) -- `--depth [basic|advanced]`: Search depth (default: basic) - - `basic`: Fast, general search - - `advanced`: Deep, comprehensive search (slower, costs more) -- `--no-answer`: Exclude AI-generated answer -- `--raw-content`: Include full page content -- `--format [json|text]`: Output format (default: json) +| Option | Default | Description | +|--------|---------|-------------| +| `query` (required) | — | Search query | +| `--max-results N` | 5 | Maximum results (1-10) | +| `--depth [basic\|advanced]` | basic | `basic`: fast; `advanced`: deep, comprehensive (slower, costs more) | +| `--no-answer` | — | Exclude AI-generated answer | +| `--raw-content` | — | Include full page content | +| `--format [json\|text]` | json | Output format | -### Response format - -Tavily returns: +## Response Format - `answer`: AI-synthesized answer to the query -- `results`: Array of search results with: - - `title`: Page title - - `url`: Source URL - - `content`: Relevant excerpt - - `score`: Relevance score +- `results[]`: `title`, `url`, `content` (excerpt), `score` (relevance) - `query`: Original query - `response_time`: API response time -## Examples - -### Research query - -```bash -python skills/tavily-search/scripts/search.py "What are the latest developments in quantum computing?" --depth advanced -``` - -Returns comprehensive answer with 5-10 cited sources. - -### Quick fact check - -```bash -python skills/tavily-search/scripts/search.py "When was the Eiffel Tower built?" --max-results 3 -``` - -Fast answer with minimal sources. - -### News search - -```bash -python skills/tavily-search/scripts/search.py "breaking news today" --format text -``` - -Human-readable format with headlines and summaries. - -## Integration in OpenClaw - -When called by the agent, run the script and parse the JSON output. -**IMPORTANT**: The script path MUST be `skills/tavily-search/scripts/search.py` (full path from the application working directory). +## Agent Integration ```python -import subprocess -import json - -SEARCH_SCRIPT = "skills/tavily-search/scripts/search.py" +import subprocess, json result = subprocess.run( - ["python", SEARCH_SCRIPT, query, "--max-results", "5"], - capture_output=True, - text=True + ["python", "skills/tavily-search/scripts/search.py", query, "--max-results", "5"], + capture_output=True, text=True ) response = json.loads(result.stdout) ``` @@ -121,26 +62,5 @@ response = json.loads(result.stdout) ## Notes - **API key**: Set `TAVILY_API_KEY` in environment or `~/.openclaw/.env` -- **Rate limits**: Check Tavily pricing page for your plan's limits - **Search depth**: Use `basic` for most queries; `advanced` for research -- **Cost**: Advanced search costs more credits per query - -## Troubleshooting - -### Module not found - -```bash -pip install tavily-python -``` - -### Missing API key - -```bash -export TAVILY_API_KEY="tvly-xxx" -``` - -### Permission denied - -```bash -chmod +x skills/tavily-search/scripts/search.py -``` \ No newline at end of file +- **Rate limits**: Check Tavily pricing page for your plan's limits \ No newline at end of file