{
  "schemaVersion": "1.0",
  "item": {
    "slug": "zotero",
    "name": "Zotero",
    "source": "tencent",
    "type": "skill",
    "category": "开发工具",
    "sourceUrl": "https://clawhub.ai/Terwox/zotero",
    "canonicalUrl": "https://clawhub.ai/Terwox/zotero",
    "targetPlatform": "OpenClaw"
  },
  "install": {
    "downloadMode": "redirect",
    "downloadUrl": "/downloads/zotero",
    "sourceDownloadUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=zotero",
    "sourcePlatform": "tencent",
    "targetPlatform": "OpenClaw",
    "installMethod": "Manual import",
    "extraction": "Extract archive",
    "prerequisites": [
      "OpenClaw"
    ],
    "packageFormat": "ZIP package",
    "includedAssets": [
      "EVAL.md",
      "SKILL.md",
      "references/troubleshooting.md",
      "scripts/zotero.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-05-07T17:22:31.273Z",
      "expiresAt": "2026-05-14T17:22:31.273Z",
      "httpStatus": 200,
      "finalUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
      "contentType": "application/zip",
      "probeMethod": "head",
      "details": {
        "probeUrl": "https://wry-manatee-359.convex.site/api/v1/download?slug=afrexai-annual-report",
        "contentDisposition": "attachment; filename=\"afrexai-annual-report-1.0.0.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/zotero"
    },
    "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/zotero",
    "agentPageUrl": "https://openagent3.xyz/skills/zotero/agent",
    "manifestUrl": "https://openagent3.xyz/skills/zotero/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/zotero/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": "Zotero Skill",
        "body": "Interact with Zotero personal or group libraries via the REST API v3."
      },
      {
        "title": "Setup",
        "body": "Requires two environment variables:\n\nZOTERO_API_KEY   — Create at https://www.zotero.org/settings/keys/new\nZOTERO_USER_ID   — Found on the same page (numeric, not username)\n\nFor group libraries, set ZOTERO_GROUP_ID instead of ZOTERO_USER_ID.\n\nOptional env var for CrossRef/Unpaywall polite pool (improves DOI lookup success rate):\n\nCROSSREF_EMAIL   — Your email (optional; uses fallback if unset)\n\nIf credentials are missing, tell the user what's needed and link them to the key creation page."
      },
      {
        "title": "CLI Script",
        "body": "All operations use scripts/zotero.py (Python 3, zero external dependencies).\n\npython3 scripts/zotero.py <command> [options]"
      },
      {
        "title": "Commands",
        "body": "CommandDescriptionExampleitemsList top-level itemszotero.py items --limit 50searchSearch by queryzotero.py search \"cognitive load\"getFull item details + attachmentszotero.py get ITEMKEYcollectionsList all collectionszotero.py collectionstagsList all tagszotero.py tagschildrenList attachments/notes for itemzotero.py children ITEMKEYadd-doiAdd item by DOI (dedup enabled)zotero.py add-doi 10.1234/exampleadd-isbnAdd item by ISBN (dedup enabled)zotero.py add-isbn 978-0-123456-78-9add-pmidAdd item by PubMed IDzotero.py add-pmid 12345678deleteMove items to trash (recoverable by default)zotero.py delete KEY1 KEY2 --yesupdateModify item metadata/tagszotero.py update KEY --add-tags \"new\"exportExport as BibTeX/RIS/CSL-JSONzotero.py export --format bibtexbatch-addAdd multiple items from filezotero.py batch-add dois.txt --type doicheck-pdfsReport which items have/lack PDFszotero.py check-pdfscrossrefMatch citations vs libraryzotero.py crossref bibliography.txtfind-doisFind & add missing DOIs via CrossRefzotero.py find-dois --limit 10fetch-pdfsFetch open-access PDFs for itemszotero.py fetch-pdfs --dry-run"
      },
      {
        "title": "Global Flags",
        "body": "--json — JSON output instead of human-readable (works with items, search, get)"
      },
      {
        "title": "Common Options",
        "body": "--limit N — Max items to return (default 25)\n--sort FIELD — Sort by dateModified, title, creator, date\n--direction asc|desc — Sort direction\n--collection KEY — Filter by or add to collection\n--type TYPE — Filter by item type (journalArticle, book, conferencePaper, etc.)\n--tags \"tag1,tag2\" — Add tags when creating items\n--force — Skip duplicate detection on add commands"
      },
      {
        "title": "Add a paper by DOI",
        "body": "python3 zotero.py add-doi \"10.1093/jamia/ocaa037\" --tags \"review\"\n# Warns if already in library. Use --force to override.\n\nDuplicate detection: translates DOI to metadata, searches library by first author, compares DOI fields."
      },
      {
        "title": "Bulk add from a file",
        "body": "# One identifier per line, # for comments\npython3 zotero.py batch-add dois.txt --type doi --tags \"imported\"\n\nSkips duplicates. Reports summary: added/skipped/failed."
      },
      {
        "title": "Export bibliography",
        "body": "python3 zotero.py export --format bibtex --output refs.bib\npython3 zotero.py export --format csljson --collection COLLKEY"
      },
      {
        "title": "Update tags/metadata",
        "body": "python3 zotero.py update ITEMKEY --add-tags \"important\" --remove-tags \"unread\"\npython3 zotero.py update ITEMKEY --title \"Corrected Title\" --date \"2024\"\npython3 zotero.py update ITEMKEY --doi \"10.1234/example\"\npython3 zotero.py update ITEMKEY --url \"https://example.com/paper\"\npython3 zotero.py update ITEMKEY --add-collection COLLKEY"
      },
      {
        "title": "Delete items",
        "body": "python3 zotero.py delete KEY1 KEY2 --yes           # Trash (recoverable, default)\npython3 zotero.py delete KEY1 --permanent --yes    # Permanent delete"
      },
      {
        "title": "Cross-reference citations",
        "body": "python3 zotero.py crossref my-paper.txt\n\nExtracts Author (Year) patterns from text and matches against library."
      },
      {
        "title": "Find missing DOIs",
        "body": "# Dry run (default) — show matches without writing anything\npython3 zotero.py find-dois --limit 20\n\n# Actually write DOIs to Zotero\npython3 zotero.py find-dois --apply\n\n# Filter by collection\npython3 zotero.py find-dois --collection COLLKEY --apply\n\nScans journalArticle and conferencePaper items missing DOIs, queries CrossRef, and matches\nby title similarity (>85%), exact year, and first author last name. Dry run by default — use\n--apply to write. Only patches the DOI field; never touches other metadata. 1s delay between\nCrossRef requests (polite pool with mailto)."
      },
      {
        "title": "Fetch open-access PDFs",
        "body": "# Dry run — show which PDFs are available and from where\npython3 zotero.py fetch-pdfs --dry-run --limit 10\n\n# Fetch and attach as linked URLs (no storage quota used)\npython3 zotero.py fetch-pdfs --limit 20\n\n# Also save PDFs locally\npython3 zotero.py fetch-pdfs --download-dir ./pdfs\n\n# Upload to Zotero storage instead of linked URL\npython3 zotero.py fetch-pdfs --upload --limit 10\n\n# Only try specific sources\npython3 zotero.py fetch-pdfs --sources unpaywall,semanticscholar\n\nTries three legal OA sources in order: Unpaywall → Semantic Scholar → DOI content negotiation.\nBy default creates linked URL attachments (no Zotero storage quota needed). Use --upload for\nfull S3 upload to Zotero storage. Use --download-dir to also save PDFs locally.\n\nSources: unpaywall, semanticscholar, doi (default: all three)\n\nRate limits: 1s between Unpaywall/Semantic Scholar requests, 2s between DOI requests."
      },
      {
        "title": "Scripting with JSON",
        "body": "python3 zotero.py --json items --limit 100 | jq '.items[].DOI'\npython3 zotero.py --json get ITEMKEY | jq '.title'"
      },
      {
        "title": "Notes",
        "body": "Zero dependencies — Python 3 stdlib only (urllib, json, argparse)\nWrite operations require an API key with write permissions\nIf Zotero translation server is down (503), DOI lookups fall back to CrossRef\nInput validation: DOIs must be 10.xxxx/... format. Item keys are 8-char alphanumeric (e.g., VNPN6FHT). ISBNs must be valid checksums.\ncheck-pdfs fetches all items; for large libraries (500+), this may be slow\nfetch-pdfs also processes all items — use --collection to scope for large libraries\nRate limits are generous; batch-add includes 1s delay between items\nFor common errors and troubleshooting, see references/troubleshooting.md"
      }
    ],
    "body": "Zotero Skill\n\nInteract with Zotero personal or group libraries via the REST API v3.\n\nSetup\n\nRequires two environment variables:\n\nZOTERO_API_KEY   — Create at https://www.zotero.org/settings/keys/new\nZOTERO_USER_ID   — Found on the same page (numeric, not username)\n\n\nFor group libraries, set ZOTERO_GROUP_ID instead of ZOTERO_USER_ID.\n\nOptional env var for CrossRef/Unpaywall polite pool (improves DOI lookup success rate):\n\nCROSSREF_EMAIL   — Your email (optional; uses fallback if unset)\n\n\nIf credentials are missing, tell the user what's needed and link them to the key creation page.\n\nCLI Script\n\nAll operations use scripts/zotero.py (Python 3, zero external dependencies).\n\npython3 scripts/zotero.py <command> [options]\n\nCommands\nCommand\tDescription\tExample\nitems\tList top-level items\tzotero.py items --limit 50\nsearch\tSearch by query\tzotero.py search \"cognitive load\"\nget\tFull item details + attachments\tzotero.py get ITEMKEY\ncollections\tList all collections\tzotero.py collections\ntags\tList all tags\tzotero.py tags\nchildren\tList attachments/notes for item\tzotero.py children ITEMKEY\nadd-doi\tAdd item by DOI (dedup enabled)\tzotero.py add-doi 10.1234/example\nadd-isbn\tAdd item by ISBN (dedup enabled)\tzotero.py add-isbn 978-0-123456-78-9\nadd-pmid\tAdd item by PubMed ID\tzotero.py add-pmid 12345678\ndelete\tMove items to trash (recoverable by default)\tzotero.py delete KEY1 KEY2 --yes\nupdate\tModify item metadata/tags\tzotero.py update KEY --add-tags \"new\"\nexport\tExport as BibTeX/RIS/CSL-JSON\tzotero.py export --format bibtex\nbatch-add\tAdd multiple items from file\tzotero.py batch-add dois.txt --type doi\ncheck-pdfs\tReport which items have/lack PDFs\tzotero.py check-pdfs\ncrossref\tMatch citations vs library\tzotero.py crossref bibliography.txt\nfind-dois\tFind & add missing DOIs via CrossRef\tzotero.py find-dois --limit 10\nfetch-pdfs\tFetch open-access PDFs for items\tzotero.py fetch-pdfs --dry-run\nGlobal Flags\n--json — JSON output instead of human-readable (works with items, search, get)\nCommon Options\n--limit N — Max items to return (default 25)\n--sort FIELD — Sort by dateModified, title, creator, date\n--direction asc|desc — Sort direction\n--collection KEY — Filter by or add to collection\n--type TYPE — Filter by item type (journalArticle, book, conferencePaper, etc.)\n--tags \"tag1,tag2\" — Add tags when creating items\n--force — Skip duplicate detection on add commands\nWorkflows\nAdd a paper by DOI\npython3 zotero.py add-doi \"10.1093/jamia/ocaa037\" --tags \"review\"\n# Warns if already in library. Use --force to override.\n\n\nDuplicate detection: translates DOI to metadata, searches library by first author, compares DOI fields.\n\nBulk add from a file\n# One identifier per line, # for comments\npython3 zotero.py batch-add dois.txt --type doi --tags \"imported\"\n\n\nSkips duplicates. Reports summary: added/skipped/failed.\n\nExport bibliography\npython3 zotero.py export --format bibtex --output refs.bib\npython3 zotero.py export --format csljson --collection COLLKEY\n\nUpdate tags/metadata\npython3 zotero.py update ITEMKEY --add-tags \"important\" --remove-tags \"unread\"\npython3 zotero.py update ITEMKEY --title \"Corrected Title\" --date \"2024\"\npython3 zotero.py update ITEMKEY --doi \"10.1234/example\"\npython3 zotero.py update ITEMKEY --url \"https://example.com/paper\"\npython3 zotero.py update ITEMKEY --add-collection COLLKEY\n\nDelete items\npython3 zotero.py delete KEY1 KEY2 --yes           # Trash (recoverable, default)\npython3 zotero.py delete KEY1 --permanent --yes    # Permanent delete\n\nCross-reference citations\npython3 zotero.py crossref my-paper.txt\n\n\nExtracts Author (Year) patterns from text and matches against library.\n\nFind missing DOIs\n# Dry run (default) — show matches without writing anything\npython3 zotero.py find-dois --limit 20\n\n# Actually write DOIs to Zotero\npython3 zotero.py find-dois --apply\n\n# Filter by collection\npython3 zotero.py find-dois --collection COLLKEY --apply\n\n\nScans journalArticle and conferencePaper items missing DOIs, queries CrossRef, and matches by title similarity (>85%), exact year, and first author last name. Dry run by default — use --apply to write. Only patches the DOI field; never touches other metadata. 1s delay between CrossRef requests (polite pool with mailto).\n\nFetch open-access PDFs\n# Dry run — show which PDFs are available and from where\npython3 zotero.py fetch-pdfs --dry-run --limit 10\n\n# Fetch and attach as linked URLs (no storage quota used)\npython3 zotero.py fetch-pdfs --limit 20\n\n# Also save PDFs locally\npython3 zotero.py fetch-pdfs --download-dir ./pdfs\n\n# Upload to Zotero storage instead of linked URL\npython3 zotero.py fetch-pdfs --upload --limit 10\n\n# Only try specific sources\npython3 zotero.py fetch-pdfs --sources unpaywall,semanticscholar\n\n\nTries three legal OA sources in order: Unpaywall → Semantic Scholar → DOI content negotiation. By default creates linked URL attachments (no Zotero storage quota needed). Use --upload for full S3 upload to Zotero storage. Use --download-dir to also save PDFs locally.\n\nSources: unpaywall, semanticscholar, doi (default: all three)\n\nRate limits: 1s between Unpaywall/Semantic Scholar requests, 2s between DOI requests.\n\nScripting with JSON\npython3 zotero.py --json items --limit 100 | jq '.items[].DOI'\npython3 zotero.py --json get ITEMKEY | jq '.title'\n\nNotes\nZero dependencies — Python 3 stdlib only (urllib, json, argparse)\nWrite operations require an API key with write permissions\nIf Zotero translation server is down (503), DOI lookups fall back to CrossRef\nInput validation: DOIs must be 10.xxxx/... format. Item keys are 8-char alphanumeric (e.g., VNPN6FHT). ISBNs must be valid checksums.\ncheck-pdfs fetches all items; for large libraries (500+), this may be slow\nfetch-pdfs also processes all items — use --collection to scope for large libraries\nRate limits are generous; batch-add includes 1s delay between items\nFor common errors and troubleshooting, see references/troubleshooting.md"
  },
  "trust": {
    "sourceLabel": "tencent",
    "provenanceUrl": "https://clawhub.ai/Terwox/zotero",
    "publisherUrl": "https://clawhub.ai/Terwox/zotero",
    "owner": "Terwox",
    "version": "1.0.0",
    "license": null,
    "verificationStatus": "Indexed source record"
  },
  "links": {
    "detailUrl": "https://openagent3.xyz/skills/zotero",
    "downloadUrl": "https://openagent3.xyz/downloads/zotero",
    "agentUrl": "https://openagent3.xyz/skills/zotero/agent",
    "manifestUrl": "https://openagent3.xyz/skills/zotero/agent.json",
    "briefUrl": "https://openagent3.xyz/skills/zotero/agent.md"
  }
}