{
  "schemaVersion": "1.0",
  "item": {
    "slug": "birdfolio",
    "name": "Birdfolio",
    "source": "tencent",
    "type": "skill",
    "category": "内容创作",
    "sourceUrl": "https://clawhub.ai/tonbistudio/birdfolio",
    "canonicalUrl": "https://clawhub.ai/tonbistudio/birdfolio",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/birdfolio",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=birdfolio",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "assets/card-template.html",
      "references/data-schema.md",
      "references/you-search-queries.md",
      "scripts/generate_card.py",
      "scripts/generate_checklist_card.py",
      "scripts/get_stats.py"
    ],
    "primaryDoc": "SKILL.md",
    "quickSetup": [
      "Download the package from Yavira.",
      "Extract the archive and review SKILL.md first.",
      "Import or place the package into your OpenClaw setup."
    ],
    "agentAssist": {
      "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
      "steps": [
        "Download the package from Yavira.",
        "Extract it into a folder your agent can access.",
        "Paste one of the prompts below and point your agent at the extracted folder."
      ],
      "prompts": [
        {
          "label": "New install",
          "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
        },
        {
          "label": "Upgrade existing",
          "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
        }
      ]
    },
    "sourceHealth": {
      "source": "tencent",
      "status": "healthy",
      "reason": "direct_download_ok",
      "recommendedAction": "download",
      "checkedAt": "2026-04-23T16:43:11.935Z",
      "expiresAt": "2026-04-30T16:43:11.935Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=4claw-imageboard",
        "contentDisposition": "attachment; filename=\"4claw-imageboard-1.0.1.zip\"",
        "redirectLocation": null,
        "bodySnippet": null
      },
      "scope": "source",
      "summary": "Source download looks usable.",
      "detail": "Yavira can redirect you to the upstream package for this source.",
      "primaryActionLabel": "Download for OpenClaw",
      "primaryActionHref": "/downloads/birdfolio"
    },
    "validation": {
      "installChecklist": [
        "Use the Yavira download entry.",
        "Review SKILL.md after the package is downloaded.",
        "Confirm the extracted package contains the expected setup assets."
      ],
      "postInstallChecks": [
        "Confirm the extracted package includes the expected docs or setup files.",
        "Validate the skill or prompts are available in your target agent workspace.",
        "Capture any manual follow-up steps the agent could not complete."
      ]
    },
    "downloadPageUrl": "https://openagent3.xyz/downloads/birdfolio",
    "agentPageUrl": "https://openagent3.xyz/skills/birdfolio/agent",
    "manifestUrl": "https://openagent3.xyz/skills/birdfolio/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/birdfolio/agent.md"
  },
  "agentAssist": {
    "summary": "Hand the extracted package to your coding agent with a concrete install brief instead of figuring it out manually.",
    "steps": [
      "Download the package from Yavira.",
      "Extract it into a folder your agent can access.",
      "Paste one of the prompts below and point your agent at the extracted folder."
    ],
    "prompts": [
      {
        "label": "New install",
        "body": "I downloaded a skill package from Yavira. Read SKILL.md from the extracted folder and install it by following the included instructions. Tell me what you changed and call out any manual steps you could not complete."
      },
      {
        "label": "Upgrade existing",
        "body": "I downloaded an updated skill package from Yavira. Read SKILL.md from the extracted folder, compare it with my current installation, and upgrade it while preserving any custom configuration unless the package docs explicitly say otherwise. Summarize what changed and any follow-up checks I should run."
      }
    ]
  },
  "documentation": {
    "source": "clawhub",
    "primaryDoc": "SKILL.md",
    "sections": [
      {
        "title": "Birdfolio",
        "body": "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.\n\nData lives in: Railway PostgreSQL (via API) + local birdfolio/ folder (cards, birds, config)\nScripts live in: {baseDir}/scripts/\nAPI: https://api-production-d0e2.up.railway.app (also saved to birdfolio/config.json after init)\nSchema reference: {baseDir}/references/data-schema.md\nSearch queries: {baseDir}/references/you-search-queries.md\n\nNote 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.\nTelegram ID: Read from the inbound message metadata (sender_id). Pass as --telegram-id to init_birdfolio.py on first setup."
      },
      {
        "title": "1. Setup Flow",
        "body": "Trigger: User says \"Set up my Birdfolio\", \"set my region\", or sends a photo before setup exists.\n\nCheck first: If birdfolio/config.json exists in your workspace, setup is already done — skip to the relevant flow.\n\nSteps:\n\nAsk: \"What's your home region? (e.g. California, Texas, United Kingdom)\"\n\n\nRun to create the workspace folder structure and register the user in the API:\nexec: python {baseDir}/scripts/init_birdfolio.py \\\n  --telegram-id {senderTelegramId} \\\n  --region \"{region}\" \\\n  --api-url \"https://api-production-d0e2.up.railway.app\" \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\n\n\nSearch You.com (run all three):\n\"{region} most common backyard birds eBird species list\"\n\"{region} uncommon seasonal rare birds eBird checklist\"\n\"{region} rare vagrant endangered birds eBird\"\n\n\n\nFrom results, build a checklist with 10 common, 5 rare, 1 super rare species. Use classification signals from {baseDir}/references/you-search-queries.md.\n\n\nWrite the populated checklist to birdfolio/checklist.json in your workspace:\n{\n  \"{region}\": {\n    \"common\": [\n      { \"species\": \"American Robin\", \"slug\": \"american-robin\", \"found\": false, \"dateFound\": null }\n    ],\n    \"rare\": [...],\n    \"superRare\": [...]\n  }\n}\n\n\n\nReply with a welcome message and checklist preview:\n🦅 Birdfolio is set up for {region}!\n\nYour checklist:\nCommon (10):  American Robin, House Sparrow, ...\nRare (5):     Great Blue Heron, ...\nSuper Rare:   California Condor\n\nSend me a bird photo to start collecting!"
      },
      {
        "title": "2. Bird Identification Flow",
        "body": "Trigger: User sends a photo.\n\nGetting 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:\nexec: copy \"<attachment path>\" \"birdfolio/birds/<slug>-<timestamp>.jpg\""
      },
      {
        "title": "Step 1 — Identify with Vision",
        "body": "The submitted photo is directly visible in your context. Analyze it (or use the image tool if it's not inline):\n\nIdentify the bird species in this photo. Return JSON only:\n{\n  \"commonName\": \"...\",\n  \"scientificName\": \"...\",\n  \"confidence\": \"high|medium|low\",\n  \"features\": [\"visible feature 1\", \"visible feature 2\"]\n}\n\nRarity rules:\n\nBird IS on the checklist → use its tier: common, rare, or superRare\nBird is NOT on the checklist → use bonus (shows a neutral \"Bonus Find\" badge, no rarity assigned)\n\nConfidence rules:\n\n\"high\" → proceed automatically, no confirmation needed\n\"medium\" → ask: \"I think this might be a [species] — based on [features]. Does that look right to you?\" → wait for confirmation before continuing\n\"low\" → reply: \"This photo isn't clear enough for me to be confident. Could you send a clearer shot?\" → stop, do not log anything"
      },
      {
        "title": "Step 2 — Rarity lookup",
        "body": "Search You.com:\n\n\"{commonName} {homeRegion} eBird frequency how common rare\"\n\nClassify using these signals:\n\nTierScript valueSignalsCommon 🟢common\"abundant\", \"widespread\", \"year-round resident\", >50% of checklistsRare 🟡rare\"uncommon\", \"seasonal\", \"migratory\", \"occasional\", 5–50% of checklistsSuper Rare 🔴superRare\"rare\", \"vagrant\", \"accidental\", \"endangered\", <5% of checklists\n\nWhen unsure → default to rare. Always use the script value (e.g. superRare, not Super Rare) when passing --rarity to any script."
      },
      {
        "title": "Step 3 — Get a fun fact",
        "body": "Search You.com:\n\n\"{commonName} bird interesting facts habitat behavior\"\n\nExtract one punchy fact (1–2 sentences)."
      },
      {
        "title": "Step 4 — Log the sighting",
        "body": "Save the sighting to birdfolio/lifeList.json in your workspace:\n\nexec: python {baseDir}/scripts/log_sighting.py \\\n  --species \"{commonName}\" \\\n  --scientific-name \"{scientificName}\" \\\n  --rarity \"{rarity}\" \\\n  --region \"{homeRegion}\" \\\n  --notes \"\" \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\nCapture from output: isLifer, totalSightings, totalSpecies."
      },
      {
        "title": "Step 5 — Update checklist",
        "body": "Mark the species as found in birdfolio/checklist.json:\n\nexec: python {baseDir}/scripts/update_checklist.py \\\n  --species \"{commonName}\" \\\n  --region \"{homeRegion}\" \\\n  --workspace <absolute path to birdfolio/ in your workspace>"
      },
      {
        "title": "Step 6 — Generate trading card",
        "body": "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.\n\nStep 6a — Detect bird position with Vision:\nUse the image tool on the submitted photo:\n\n\"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).\"\n\nConvert the answer to a CSS value: \"40% center\", \"60% center\", \"center center\", etc. Use this as --object-position.\n\nStep 6b — Generate the card HTML with the embedded photo:\n\nexec: python {baseDir}/scripts/generate_card.py \\\n  --species \"{commonName}\" \\\n  --scientific-name \"{scientificName}\" \\\n  --rarity \"{rarity}\" \\\n  --region \"{homeRegion}\" \\\n  --date \"{YYYY-MM-DD}\" \\\n  --fun-fact \"{funFact}\" \\\n  --image-path \"<absolute path to submitted photo>\" \\\n  --object-position \"{objectPosition}\" \\\n  --life-count {totalSpecies} \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\n--image-path embeds the user's actual photo as base64 directly into the HTML. No separate embed step needed.\n\nFallback if photo path is unavailable: omit --image-path and pass --image-url \"<stock photo URL>\" instead (find a URL via You.com: \"{commonName} bird photo wildlife\").\n\nCapture cardPath from output.\n\nStep 6c — Screenshot, save, upload, and send:\nRun the screenshot script to render the card at 600×400 and save a PNG:\n\nexec: node {baseDir}/scripts/screenshot_card.js \"<cardPath>\"\n\nCapture pngPath from output.\n\nUpload to Cloudflare R2 and get a public URL:\n\nexec: python {baseDir}/scripts/upload_card.py \"<pngPath>\"\n\nCapture url from output.\n\nUpdate the sighting's card URL in the API (use the id from the log_sighting output):\n\nPATCH /users/{telegram_id}/sightings/{sighting_id}/card\nBody: {\"card_png_url\": \"<url>\"}\n\nSend the PNG via Telegram:\n\nmessage(action=\"send\", media=\"<pngPath>\")"
      },
      {
        "title": "Step 7 — Reply",
        "body": "If isLifer is true:\n\"🎉 New lifer! That's your first ever [commonName]! Bird #[totalSpecies] in your Birdfolio.\"\nIf totalSpecies == 1 (this is their very first bird ever): also send their personal PWA link:\n\"🦅 Your Birdfolio is live! Bookmark this link to see your life list:\nhttps://birdfolio.tonbistudio.com/app/[telegram_id]\"\nThe 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.\n\n\nOtherwise:\n\"[commonName] spotted! You've now seen [N] species in your Birdfolio.\"\n\nInclude: rarity badge emoji, the fun fact, checklist status (if species was on checklist, mention it).\n\nFallback if screenshot fails: Send a formatted text card:\n\n🦅 [RARITY_EMOJI] [Common Name]\nScientific: [Scientific Name]\nRegion: [Region] | Spotted: [Date]\nRarity: [Rarity]\n💡 [Fun Fact]\nBird #[N] in your Birdfolio"
      },
      {
        "title": "3. Checklist & Stats",
        "body": "Trigger: \"How's my checklist?\", \"Birdfolio progress\", \"How many birds have I found?\"\n\nexec: python {baseDir}/scripts/get_stats.py \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\nFormat response using checklistProgress from output:\n\n📋 {region} Checklist\n\nCommon     ✅✅✅⬜⬜⬜⬜⬜⬜⬜  3/10\nRare       ✅⬜⬜⬜⬜              1/5\nSuper Rare ⬜                      0/1\n\n🐦 {totalSpecies} species | {totalSightings} total sightings\n📍 Last spotted: {mostRecentSighting.commonName} on {date}\n🏆 Rarest find: {rarestBird.commonName} ({rarity})\n\nUse ✅ for found, ⬜ for not found. One box per species.\n\nOptional visual checklist card: Generate a visual HTML checklist card and screenshot it:\n\nexec: python {baseDir}/scripts/generate_checklist_card.py \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\nThen screenshot with screenshot_card.js and send the PNG."
      },
      {
        "title": "4. Life List View",
        "body": "Trigger: \"Show my Birdfolio\", \"Show my life list\"\n\nRead birdfolio/lifeList.json from your workspace.\n\nGroup 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."
      },
      {
        "title": "5. Species Lookup (no logging)",
        "body": "Trigger: \"Tell me about [species]\"\n\nSearch You.com:\n\n\"{species} bird facts habitat range behavior diet\"\n\"{species} bird {homeRegion} eBird frequency resident or migratory\"\n\nReturn a conversational summary. Do not log a sighting or generate a card."
      },
      {
        "title": "6. Rarest Bird",
        "body": "Trigger: \"What's my rarest bird?\", \"Show my best find\"\n\nexec: python {baseDir}/scripts/get_stats.py \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\nRead rarestBird from output and reply with species name, rarity, date spotted, and region."
      },
      {
        "title": "Quick Reference",
        "body": "ScriptKey argsReturnsinit_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 cardscreenshot_card.js<cardPath> [outputPath]{status, pngPath} — saves PNG to birdfolio/cards/upload_card.py<pngPath> [--secrets path]{status, url} — uploads to R2, returns public URL\n\nAll Python scripts output JSON to stdout. Always pass absolute --workspace path.\nscreenshot_card.js uses OpenClaw's bundled playwright-core + system Chrome/Edge (no separate install needed)."
      }
    ],
    "body": "Birdfolio\n\nBirdfolio 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.\n\nData 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\n\nNote 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.\n\nTelegram ID: Read from the inbound message metadata (sender_id). Pass as --telegram-id to init_birdfolio.py on first setup.\n\n1. Setup Flow\n\nTrigger: User says \"Set up my Birdfolio\", \"set my region\", or sends a photo before setup exists.\n\nCheck first: If birdfolio/config.json exists in your workspace, setup is already done — skip to the relevant flow.\n\nSteps:\n\nAsk: \"What's your home region? (e.g. California, Texas, United Kingdom)\"\n\nRun to create the workspace folder structure and register the user in the API:\n\nexec: python {baseDir}/scripts/init_birdfolio.py \\\n  --telegram-id {senderTelegramId} \\\n  --region \"{region}\" \\\n  --api-url \"https://api-production-d0e2.up.railway.app\" \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\n\nSearch You.com (run all three):\n\n\"{region} most common backyard birds eBird species list\"\n\"{region} uncommon seasonal rare birds eBird checklist\"\n\"{region} rare vagrant endangered birds eBird\"\n\n\nFrom results, build a checklist with 10 common, 5 rare, 1 super rare species. Use classification signals from {baseDir}/references/you-search-queries.md.\n\nWrite the populated checklist to birdfolio/checklist.json in your workspace:\n\n{\n  \"{region}\": {\n    \"common\": [\n      { \"species\": \"American Robin\", \"slug\": \"american-robin\", \"found\": false, \"dateFound\": null }\n    ],\n    \"rare\": [...],\n    \"superRare\": [...]\n  }\n}\n\n\nReply with a welcome message and checklist preview:\n\n🦅 Birdfolio is set up for {region}!\n\nYour checklist:\nCommon (10):  American Robin, House Sparrow, ...\nRare (5):     Great Blue Heron, ...\nSuper Rare:   California Condor\n\nSend me a bird photo to start collecting!\n\n2. Bird Identification Flow\n\nTrigger: User sends a photo.\n\nGetting 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:\n\nexec: copy \"<attachment path>\" \"birdfolio/birds/<slug>-<timestamp>.jpg\"\n\nStep 1 — Identify with Vision\n\nThe submitted photo is directly visible in your context. Analyze it (or use the image tool if it's not inline):\n\nIdentify the bird species in this photo. Return JSON only:\n{\n  \"commonName\": \"...\",\n  \"scientificName\": \"...\",\n  \"confidence\": \"high|medium|low\",\n  \"features\": [\"visible feature 1\", \"visible feature 2\"]\n}\n\n\nRarity rules:\n\nBird IS on the checklist → use its tier: common, rare, or superRare\nBird is NOT on the checklist → use bonus (shows a neutral \"Bonus Find\" badge, no rarity assigned)\n\nConfidence rules:\n\n\"high\" → proceed automatically, no confirmation needed\n\"medium\" → ask: \"I think this might be a [species] — based on [features]. Does that look right to you?\" → wait for confirmation before continuing\n\"low\" → reply: \"This photo isn't clear enough for me to be confident. Could you send a clearer shot?\" → stop, do not log anything\nStep 2 — Rarity lookup\n\nSearch You.com:\n\n\"{commonName} {homeRegion} eBird frequency how common rare\"\n\n\nClassify using these signals:\n\nTier\tScript value\tSignals\nCommon 🟢\tcommon\t\"abundant\", \"widespread\", \"year-round resident\", >50% of checklists\nRare 🟡\trare\t\"uncommon\", \"seasonal\", \"migratory\", \"occasional\", 5–50% of checklists\nSuper Rare 🔴\tsuperRare\t\"rare\", \"vagrant\", \"accidental\", \"endangered\", <5% of checklists\n\nWhen unsure → default to rare. Always use the script value (e.g. superRare, not Super Rare) when passing --rarity to any script.\n\nStep 3 — Get a fun fact\n\nSearch You.com:\n\n\"{commonName} bird interesting facts habitat behavior\"\n\n\nExtract one punchy fact (1–2 sentences).\n\nStep 4 — Log the sighting\n\nSave the sighting to birdfolio/lifeList.json in your workspace:\n\nexec: python {baseDir}/scripts/log_sighting.py \\\n  --species \"{commonName}\" \\\n  --scientific-name \"{scientificName}\" \\\n  --rarity \"{rarity}\" \\\n  --region \"{homeRegion}\" \\\n  --notes \"\" \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\n\nCapture from output: isLifer, totalSightings, totalSpecies.\n\nStep 5 — Update checklist\n\nMark the species as found in birdfolio/checklist.json:\n\nexec: python {baseDir}/scripts/update_checklist.py \\\n  --species \"{commonName}\" \\\n  --region \"{homeRegion}\" \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\nStep 6 — Generate trading card\n\nThe 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.\n\nStep 6a — Detect bird position with Vision: Use the image tool on the submitted photo:\n\n\"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).\"\n\nConvert the answer to a CSS value: \"40% center\", \"60% center\", \"center center\", etc. Use this as --object-position.\n\nStep 6b — Generate the card HTML with the embedded photo:\n\nexec: python {baseDir}/scripts/generate_card.py \\\n  --species \"{commonName}\" \\\n  --scientific-name \"{scientificName}\" \\\n  --rarity \"{rarity}\" \\\n  --region \"{homeRegion}\" \\\n  --date \"{YYYY-MM-DD}\" \\\n  --fun-fact \"{funFact}\" \\\n  --image-path \"<absolute path to submitted photo>\" \\\n  --object-position \"{objectPosition}\" \\\n  --life-count {totalSpecies} \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\n\n--image-path embeds the user's actual photo as base64 directly into the HTML. No separate embed step needed.\n\nFallback if photo path is unavailable: omit --image-path and pass --image-url \"<stock photo URL>\" instead (find a URL via You.com: \"{commonName} bird photo wildlife\").\n\nCapture cardPath from output.\n\nStep 6c — Screenshot, save, upload, and send: Run the screenshot script to render the card at 600×400 and save a PNG:\n\nexec: node {baseDir}/scripts/screenshot_card.js \"<cardPath>\"\n\n\nCapture pngPath from output.\n\nUpload to Cloudflare R2 and get a public URL:\n\nexec: python {baseDir}/scripts/upload_card.py \"<pngPath>\"\n\n\nCapture url from output.\n\nUpdate the sighting's card URL in the API (use the id from the log_sighting output):\n\nPATCH /users/{telegram_id}/sightings/{sighting_id}/card\nBody: {\"card_png_url\": \"<url>\"}\n\n\nSend the PNG via Telegram:\n\nmessage(action=\"send\", media=\"<pngPath>\")\n\nStep 7 — Reply\n\nIf isLifer is true: \"🎉 New lifer! That's your first ever [commonName]! Bird #[totalSpecies] in your Birdfolio.\"\n\nIf 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]\"\n\nThe 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.\n\nOtherwise: \"[commonName] spotted! You've now seen [N] species in your Birdfolio.\"\n\nInclude: rarity badge emoji, the fun fact, checklist status (if species was on checklist, mention it).\n\nFallback if screenshot fails: Send a formatted text card:\n\n🦅 [RARITY_EMOJI] [Common Name]\nScientific: [Scientific Name]\nRegion: [Region] | Spotted: [Date]\nRarity: [Rarity]\n💡 [Fun Fact]\nBird #[N] in your Birdfolio\n\n3. Checklist & Stats\n\nTrigger: \"How's my checklist?\", \"Birdfolio progress\", \"How many birds have I found?\"\n\nexec: python {baseDir}/scripts/get_stats.py \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\n\nFormat response using checklistProgress from output:\n\n📋 {region} Checklist\n\nCommon     ✅✅✅⬜⬜⬜⬜⬜⬜⬜  3/10\nRare       ✅⬜⬜⬜⬜              1/5\nSuper Rare ⬜                      0/1\n\n🐦 {totalSpecies} species | {totalSightings} total sightings\n📍 Last spotted: {mostRecentSighting.commonName} on {date}\n🏆 Rarest find: {rarestBird.commonName} ({rarity})\n\n\nUse ✅ for found, ⬜ for not found. One box per species.\n\nOptional visual checklist card: Generate a visual HTML checklist card and screenshot it:\n\nexec: python {baseDir}/scripts/generate_checklist_card.py \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\n\nThen screenshot with screenshot_card.js and send the PNG.\n\n4. Life List View\n\nTrigger: \"Show my Birdfolio\", \"Show my life list\"\n\nRead birdfolio/lifeList.json from your workspace.\n\nGroup 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.\n\n5. Species Lookup (no logging)\n\nTrigger: \"Tell me about [species]\"\n\nSearch You.com:\n\n\"{species} bird facts habitat range behavior diet\"\n\"{species} bird {homeRegion} eBird frequency resident or migratory\"\n\n\nReturn a conversational summary. Do not log a sighting or generate a card.\n\n6. Rarest Bird\n\nTrigger: \"What's my rarest bird?\", \"Show my best find\"\n\nexec: python {baseDir}/scripts/get_stats.py \\\n  --workspace <absolute path to birdfolio/ in your workspace>\n\n\nRead rarestBird from output and reply with species name, rarity, date spotted, and region.\n\nQuick Reference\nScript\tKey args\tReturns\ninit_birdfolio.py\t--telegram-id, --region, --api-url, --workspace\t{status, workspace, files_created, next}\nlog_sighting.py\t--species, --scientific-name, --rarity, --region, --date, --workspace\t{status, sighting, isLifer, totalSightings, totalSpecies}\nupdate_checklist.py\t--species, --region, --workspace\t{status, tier, dateFound} or {status: not_on_checklist}\nget_stats.py\t--workspace\t{totalSightings, totalSpecies, checklistProgress, mostRecentSighting, rarestBird}\ngenerate_card.py\t--species, --scientific-name, --rarity, --region, --date, --fun-fact, --image-path (preferred) OR --image-url, --object-position, --life-count, --workspace\t{status, cardPath, filename}\ngenerate_checklist_card.py\t--workspace\t{status, cardPath} — visual HTML checklist card\nscreenshot_card.js\t<cardPath> [outputPath]\t{status, pngPath} — saves PNG to birdfolio/cards/\nupload_card.py\t<pngPath> [--secrets path]\t{status, url} — uploads to R2, returns public URL\n\nAll 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)."
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/tonbistudio/birdfolio",
    "publisherUrl": "https://clawhub.ai/tonbistudio/birdfolio",
    "owner": "tonbistudio",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/birdfolio",
    "downloadUrl": "https://openagent3.xyz/downloads/birdfolio",
    "agentUrl": "https://openagent3.xyz/skills/birdfolio/agent",
    "manifestUrl": "https://openagent3.xyz/skills/birdfolio/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/birdfolio/agent.md"
  }
}