← 返回 Skills 市场
tonbistudio

Birdfolio

作者 tonbi · GitHub ↗ · v1.0.0
cross-platform ⚠ suspicious
688
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install birdfolio
功能描述
Bird identification, life list tracking, and trading card generation. Use this skill when the user: sends a bird photo to identify, says "set up my Birdfolio...
使用说明 (SKILL.md)

Birdfolio

Birdfolio turns bird photos into a personal life list. Users photograph birds in the wild, send the photo to you, and you identify the species with Vision. You.com provides real-time rarity and regional data. Each sighting is logged to a life list with a Pokémon-inspired rarity tier (Common / Rare / Super Rare) and gets a visual trading card sent back via Telegram.

Data lives in: Railway PostgreSQL (via API) + local birdfolio/ folder (cards, birds, config) Scripts live in: {baseDir}/scripts/ API: https://api-production-d0e2.up.railway.app (also saved to birdfolio/config.json after init) Schema reference: {baseDir}/references/data-schema.md Search queries: {baseDir}/references/you-search-queries.md

Note on --workspace & --api-url: Every data script accepts --workspace (absolute path to birdfolio/) and --api-url (API base URL). After init_birdfolio.py runs, both the API URL and Telegram ID are saved to birdfolio/config.json and read automatically — subsequent scripts only need --workspace.

Telegram ID: Read from the inbound message metadata (sender_id). Pass as --telegram-id to init_birdfolio.py on first setup.


1. Setup Flow

Trigger: User says "Set up my Birdfolio", "set my region", or sends a photo before setup exists.

Check first: If birdfolio/config.json exists in your workspace, setup is already done — skip to the relevant flow.

Steps:

  1. Ask: "What's your home region? (e.g. California, Texas, United Kingdom)"

  2. Run to create the workspace folder structure and register the user in the API:

    exec: python {baseDir}/scripts/init_birdfolio.py \
      --telegram-id {senderTelegramId} \
      --region "{region}" \
      --api-url "https://api-production-d0e2.up.railway.app" \
      --workspace \x3Cabsolute path to birdfolio/ in your workspace>
    
  3. Search You.com (run all three):

    "{region} most common backyard birds eBird species list"
    "{region} uncommon seasonal rare birds eBird checklist"
    "{region} rare vagrant endangered birds eBird"
    
  4. From results, build a checklist with 10 common, 5 rare, 1 super rare species. Use classification signals from {baseDir}/references/you-search-queries.md.

  5. Write the populated checklist to birdfolio/checklist.json in your workspace:

    {
      "{region}": {
        "common": [
          { "species": "American Robin", "slug": "american-robin", "found": false, "dateFound": null }
        ],
        "rare": [...],
        "superRare": [...]
      }
    }
    
  6. Reply with a welcome message and checklist preview:

    🦅 Birdfolio is set up for {region}!
    
    Your checklist:
    Common (10):  American Robin, House Sparrow, ...
    Rare (5):     Great Blue Heron, ...
    Super Rare:   California Condor
    
    Send me a bird photo to start collecting!
    

2. Bird Identification Flow

Trigger: User sends a photo.

Getting the photo file path: When a user sends a photo via Telegram, OpenClaw downloads it and makes the local file path available in the message attachment metadata. Capture this path — you'll need it for card generation in Step 5. If OpenClaw provides the image inline without a path, use exec to find the most recently downloaded file in OpenClaw's temp/media folder, or check %APPDATA%\openclaw\media\ on Windows. Save the photo to birdfolio/birds/{slug}-{timestamp}.jpg for permanent storage:

exec: copy "\x3Cattachment path>" "birdfolio/birds/\x3Cslug>-\x3Ctimestamp>.jpg"

Step 1 — Identify with Vision

The submitted photo is directly visible in your context. Analyze it (or use the image tool if it's not inline):

Identify the bird species in this photo. Return JSON only:
{
  "commonName": "...",
  "scientificName": "...",
  "confidence": "high|medium|low",
  "features": ["visible feature 1", "visible feature 2"]
}

Rarity rules:

  • Bird IS on the checklist → use its tier: common, rare, or superRare
  • Bird is NOT on the checklist → use bonus (shows a neutral "Bonus Find" badge, no rarity assigned)

Confidence rules:

  • "high" → proceed automatically, no confirmation needed
  • "medium" → ask: "I think this might be a [species] — based on [features]. Does that look right to you?" → wait for confirmation before continuing
  • "low" → reply: "This photo isn't clear enough for me to be confident. Could you send a clearer shot?" → stop, do not log anything

Step 2 — Rarity lookup

Search You.com:

"{commonName} {homeRegion} eBird frequency how common rare"

Classify using these signals:

Tier Script value Signals
Common 🟢 common "abundant", "widespread", "year-round resident", >50% of checklists
Rare 🟡 rare "uncommon", "seasonal", "migratory", "occasional", 5–50% of checklists
Super Rare 🔴 superRare "rare", "vagrant", "accidental", "endangered", \x3C5% of checklists

When unsure → default to rare. Always use the script value (e.g. superRare, not Super Rare) when passing --rarity to any script.

Step 3 — Get a fun fact

Search You.com:

"{commonName} bird interesting facts habitat behavior"

Extract one punchy fact (1–2 sentences).

Step 4 — Log the sighting

Save the sighting to birdfolio/lifeList.json in your workspace:

exec: python {baseDir}/scripts/log_sighting.py \
  --species "{commonName}" \
  --scientific-name "{scientificName}" \
  --rarity "{rarity}" \
  --region "{homeRegion}" \
  --notes "" \
  --workspace \x3Cabsolute path to birdfolio/ in your workspace>

Capture from output: isLifer, totalSightings, totalSpecies.

Step 5 — Update checklist

Mark the species as found in birdfolio/checklist.json:

exec: python {baseDir}/scripts/update_checklist.py \
  --species "{commonName}" \
  --region "{homeRegion}" \
  --workspace \x3Cabsolute path to birdfolio/ in your workspace>

Step 6 — Generate trading card

The card is a two-column design: the user's photo fills the left panel (280px), a solid dark info panel sits on the right. Always use the user's actual submitted photo — not a stock image.

Step 6a — Detect bird position with Vision: Use the image tool on the submitted photo:

"Where is the bird positioned horizontally in this photo? Give me approximately what percentage from the left edge the bird's center is (0–100)."

Convert the answer to a CSS value: "40% center", "60% center", "center center", etc. Use this as --object-position.

Step 6b — Generate the card HTML with the embedded photo:

exec: python {baseDir}/scripts/generate_card.py \
  --species "{commonName}" \
  --scientific-name "{scientificName}" \
  --rarity "{rarity}" \
  --region "{homeRegion}" \
  --date "{YYYY-MM-DD}" \
  --fun-fact "{funFact}" \
  --image-path "\x3Cabsolute path to submitted photo>" \
  --object-position "{objectPosition}" \
  --life-count {totalSpecies} \
  --workspace \x3Cabsolute path to birdfolio/ in your workspace>

--image-path embeds the user's actual photo as base64 directly into the HTML. No separate embed step needed.

Fallback if photo path is unavailable: omit --image-path and pass --image-url "\x3Cstock photo URL>" instead (find a URL via You.com: "{commonName} bird photo wildlife").

Capture cardPath from output.

Step 6c — Screenshot, save, upload, and send: Run the screenshot script to render the card at 600×400 and save a PNG:

exec: node {baseDir}/scripts/screenshot_card.js "\x3CcardPath>"

Capture pngPath from output.

Upload to Cloudflare R2 and get a public URL:

exec: python {baseDir}/scripts/upload_card.py "\x3CpngPath>"

Capture url from output.

Update the sighting's card URL in the API (use the id from the log_sighting output):

PATCH /users/{telegram_id}/sightings/{sighting_id}/card
Body: {"card_png_url": "\x3Curl>"}

Send the PNG via Telegram:

message(action="send", media="\x3CpngPath>")

Step 7 — Reply

  • If isLifer is true: "🎉 New lifer! That's your first ever [commonName]! Bird #[totalSpecies] in your Birdfolio."

    If totalSpecies == 1 (this is their very first bird ever): also send their personal PWA link: "🦅 Your Birdfolio is live! Bookmark this link to see your life list: https://birdfolio.tonbistudio.com/app/[telegram_id]"

    The telegram_id is the sender's Telegram ID from the inbound message metadata (sender_id). This is also stored in birdfolio/config.json after init.

  • Otherwise: "[commonName] spotted! You've now seen [N] species in your Birdfolio."

Include: rarity badge emoji, the fun fact, checklist status (if species was on checklist, mention it).

Fallback if screenshot fails: Send a formatted text card:

🦅 [RARITY_EMOJI] [Common Name]
Scientific: [Scientific Name]
Region: [Region] | Spotted: [Date]
Rarity: [Rarity]
💡 [Fun Fact]
Bird #[N] in your Birdfolio

3. Checklist & Stats

Trigger: "How's my checklist?", "Birdfolio progress", "How many birds have I found?"

exec: python {baseDir}/scripts/get_stats.py \
  --workspace \x3Cabsolute path to birdfolio/ in your workspace>

Format response using checklistProgress from output:

📋 {region} Checklist

Common     ✅✅✅⬜⬜⬜⬜⬜⬜⬜  3/10
Rare       ✅⬜⬜⬜⬜              1/5
Super Rare ⬜                      0/1

🐦 {totalSpecies} species | {totalSightings} total sightings
📍 Last spotted: {mostRecentSighting.commonName} on {date}
🏆 Rarest find: {rarestBird.commonName} ({rarity})

Use ✅ for found, ⬜ for not found. One box per species.

Optional visual checklist card: Generate a visual HTML checklist card and screenshot it:

exec: python {baseDir}/scripts/generate_checklist_card.py \
  --workspace \x3Cabsolute path to birdfolio/ in your workspace>

Then screenshot with screenshot_card.js and send the PNG.


4. Life List View

Trigger: "Show my Birdfolio", "Show my life list"

Read birdfolio/lifeList.json from your workspace.

Group lifers by rarity (Super Rare first, then Rare, then Common). Format as a text list or generate an HTML gallery, save it to birdfolio/my-birdfolio.html in your workspace, and screenshot it.


5. Species Lookup (no logging)

Trigger: "Tell me about [species]"

Search You.com:

"{species} bird facts habitat range behavior diet"
"{species} bird {homeRegion} eBird frequency resident or migratory"

Return a conversational summary. Do not log a sighting or generate a card.


6. Rarest Bird

Trigger: "What's my rarest bird?", "Show my best find"

exec: python {baseDir}/scripts/get_stats.py \
  --workspace \x3Cabsolute path to birdfolio/ in your workspace>

Read rarestBird from output and reply with species name, rarity, date spotted, and region.


Quick Reference

Script Key args Returns
init_birdfolio.py --telegram-id, --region, --api-url, --workspace {status, workspace, files_created, next}
log_sighting.py --species, --scientific-name, --rarity, --region, --date, --workspace {status, sighting, isLifer, totalSightings, totalSpecies}
update_checklist.py --species, --region, --workspace {status, tier, dateFound} or {status: not_on_checklist}
get_stats.py --workspace {totalSightings, totalSpecies, checklistProgress, mostRecentSighting, rarestBird}
generate_card.py --species, --scientific-name, --rarity, --region, --date, --fun-fact, --image-path (preferred) OR --image-url, --object-position, --life-count, --workspace {status, cardPath, filename}
generate_checklist_card.py --workspace {status, cardPath} — visual HTML checklist card
screenshot_card.js \x3CcardPath> [outputPath] {status, pngPath} — saves PNG to birdfolio/cards/
upload_card.py \x3CpngPath> [--secrets path] {status, url} — uploads to R2, returns public URL

All Python scripts output JSON to stdout. Always pass absolute --workspace path. screenshot_card.js uses OpenClaw's bundled playwright-core + system Chrome/Edge (no separate install needed). \r

安全使用建议
This skill implements a plausible bird-tracking workflow, but there are privacy and trust decisions to make before installing: - The skill will send your Telegram sender_id and every logged sighting to a remote API at https://api-production-d0e2.up.railway.app. If you don't control or trust that API, do not use the skill or review the server-side code/owner before giving it data. - Card uploads (upload_card.py) require an R2-style secrets JSON (access key/secret) stored in your workspace; the skill will read that file and use boto3 to upload images. Treat those credentials like any secret — only provide them if you trust the destination and want images publicly hosted. - The SKILL.md instructs the agent to inspect OpenClaw temp/media and %APPDATA% paths and to find the most-recent downloaded file if an inline path is not provided. That gives the skill the ability to read files outside birdfolio/. Run it in an isolated workspace or sandbox if you want to limit filesystem access. - The Node screenshot script attempts to load playwright-core from an OpenClaw-specific node_modules path and prefers system Chrome. This is brittle; ensure your environment has the required dependencies or run the Python card-generation flow without the screenshot step. If you plan to use the skill: (1) Verify the remote API owner and privacy policy; (2) avoid putting unrelated secrets in the workspace; (3) run in a dedicated environment or container to limit unintended file access; (4) consider reviewing the server-side API implementation or hosting your own API if you need stronger data control.
功能分析
Type: OpenClaw Skill Name: birdfolio Version: 1.0.0 The skill is classified as suspicious due to potential shell injection vulnerabilities in `SKILL.md` where user-controlled input (e.g., `{region}`, `<attachment path>`) is passed to `exec` without explicit sanitization, relying on the OpenClaw agent's robustness. Additionally, a clear Cross-Site Scripting (XSS) vulnerability exists in `scripts/generate_card.py` and `scripts/generate_checklist_card.py`, which embed unsanitized user/AI-generated text (e.g., `args.species`, `args.fun_fact`) directly into HTML templates. These vulnerable HTML files are then rendered by `scripts/screenshot_card.js` in a headless browser, allowing arbitrary JavaScript execution within that context. While the skill's functionality is aligned with its stated purpose, these flaws present significant attack surfaces.
能力评估
Purpose & Capability
Name/description align with the code and instructions: vision-based ID, local workspace files (checklist, lifeList, cards), and an API-backed persistent store. The included scripts implement identification logging, checklist sync, card generation (HTML→PNG), and optional upload. Nothing in the code appears to be unrelated to a bird-collection workflow.
Instruction Scope
Runtime instructions ask the agent to read message metadata for the Telegram sender_id and to capture a local photo path. They explicitly instruct the agent to look in OpenClaw temp/media and a Windows %APPDATA% path and, if necessary, to 'find the most recently downloaded file' — this requires reading files outside the skill workspace and gives broad filesystem access. The skill also instructs the agent to perform You.com searches and to POST user data (telegram id, sightings) to a remote API. Those behaviors are within the feature set but expand the agent's access to user metadata, local files, and a third-party endpoint and should be reviewed.
Install Mechanism
There is no install spec (instruction-only install), so nothing is pulled from arbitrary URLs. Scripts include a Node screenshot script that attempts to require playwright-core from an OpenClaw-specific node_modules path under APPDATA and prefers system Chrome binaries; this is brittle but not inherently malicious. No network downloads or remote executable installs are embedded in the skill package itself.
Credentials
The skill declares no required env vars/primary credentials, but it interacts with external services and expects credentials in local files: it contacts a hard-coded API base URL (https://api-production-d0e2.up.railway.app) and upload_card.py expects an R2 secrets JSON (workspace/secrets/r2-birdfolio.json) containing access_key_id/secret_access_key and endpoint. Those secrets are not declared in the skill manifest; providing them is optional but necessary for card uploads. The skill will transmit personal identifiers (Telegram sender_id) and sighting data to the remote API; ensure you trust that endpoint before use.
Persistence & Privilege
The skill is not always-enabled and does not request elevated platform privileges. It writes only to its own workspace (birdfolio/) and to whatever secrets file the user provides for uploads. It does not modify other skills or global agent settings. The ability to be invoked autonomously is default and not unusual here.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install birdfolio
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /birdfolio 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
Initial release — AI bird ID, life list tracking, trading cards, PWA, Cloudflare R2, Railway API
元数据
Slug birdfolio
版本 1.0.0
许可证
累计安装 0
当前安装数 0
历史版本数 1
常见问题

Birdfolio 是什么?

Bird identification, life list tracking, and trading card generation. Use this skill when the user: sends a bird photo to identify, says "set up my Birdfolio... 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 688 次。

如何安装 Birdfolio?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install birdfolio」即可一键安装,无需额外配置。

Birdfolio 是免费的吗?

是的,Birdfolio 完全免费(开源免费),可自由下载、安装和使用。

Birdfolio 支持哪些平台?

Birdfolio 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 Birdfolio?

由 tonbi(@tonbistudio)开发并维护,当前版本 v1.0.0。

💬 留言讨论