Claude-Guardian
Claude Guardian는 계정 안전과 위험 방지를 위한 올인원 기능으로, 기기·계정 이력·네트워크·결제 옵션을 지능적으로 평가해 제공합니다
Zotero 참고문헌을 프로그래밍으로 관리하는 스킬로, 검색·추가·분류·주석·정리 기능을 제공합니다
A skill for managing Zotero references programmatically — search, add, classify, annotate, and organize literature.
스킬PythonGitHub @WenyuChiou직접 설치운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
개인 계정의 공개 저장소 소유자는 GitHub로 로그인해 운영자를 확인하고 소개를 직접 관리할 수 있습니다. 관리자 승인은 필요하지 않습니다.
로그인한 뒤 확인 파일을 만들어 이 저장소의 기본 브랜치에 30분 안에 커밋해 주세요. 다른 브랜치나 포크의 파일은 인정하지 않습니다. 파일을 올린 뒤 아래에서 확인하면 관리자 승인 없이 관리할 수 있습니다. 자격을 유지하려면 파일을 남겨 두세요.
로그인이 필요하면 로그인 화면으로 이동합니다. 로그인 후 이곳으로 돌아와 원하는 확인 버튼을 다시 눌러 주세요.
설치형 프로젝트는 배포 도메인 없이도 확인할 수 있습니다. 개인 저장소는 GitHub 로그인으로, 조직 저장소는 위의 저장소 확인 파일로 직접 확인해 주세요.
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Zotero Skills — AI Coding Assistant Skill for Zotero CRUD
Comprehensive Zotero library management via dual-API architecture (local read + web write). Works with any AI coding assistant that supports skills or custom instructions.
📚 Part of the agentic AI learning roadmap — a 7-stage curated path for building agentic AI, multilingual (zh-TW · zh-CN · English). This skill is referenced in §13 (research workflow skills).README 전문 보기 ↗Comprehensive Zotero library management via dual-API architecture (local read + web write). Works with any AI coding assistant that supports skills or custom instructions.
📚 Part of the agentic AI learning roadmap — a 7-stage curated path for building agentic AI, multilingual (zh-TW · zh-CN · English). This skill is referenced in §13 (research workflow skills).
A skill that gives AI coding assistants full CRUD access to your Zotero library. Search, add, classify, annotate, and organize references programmatically — all from your terminal.
See Features below for the full list.
Beyond standard CRUD, this skill does four things an AI agent often wrongly calls impossible:
~/.claude/.env, then config.json. Call credentials_status() to check which one is set (booleans and a source label only, never the value) instead of opening those files yourself.ZoteroDualClient.merge_duplicates() reproduces the core of a desktop merge (move every child, union collections/tags/relations, add a dc:replaces relation, then trash the duplicate, recoverable with restore_item()).attachment_simple fail silently. ZoteroDualClient.attach_pdf() copies to a short, safe, zot_-prefixed filename first and raises the failed-upload template pyzotero returns (it does not expose a deeper server reason) instead of staying silent.See the capability table in skills/zotero-skills/SKILL.md for the full list and what each one does not cover.
safe_api_call() wrapper prevents API quota violationszotero_client.py directly in any Python projectpip install pyzotero.env fileThe shared client resolves credentials in this order: environment variables → ~/.claude/.env → config.json. The simplest, safest way is a single file — create ~/.claude/.env and paste three lines:
ZOTERO_API_KEY=your_key_here
ZOTERO_LIBRARY_ID=your_library_id
ZOTERO_LIBRARY_TYPE=user
That's it — no code, works everywhere, and nothing to commit. (Setting the same three as shell environment variables works too.)
A stale OS-level credential overrides
~/.claude/.env. Diagnose the resolved source withcredentials_status(); never echo the API key, paste it into a chat, or open credential files for an agent. Review any change to credentials or persistent access yourself.
From the repository root (or the resolved marketplace plugin root), this read-only diagnostic prints presence and source labels without credential values:
python -c "from scripts.zotero_client import credentials_status; print(credentials_status())"
config.json still works but is deprecated — it emits a DeprecationWarning at runtime. It is gitignored so it is never committed. Prefer ~/.claude/.env; use this only if you cannot set env vars:
cp config.example.json config.json # then fill in your key + library id
{ "zotero_api_key": "YOUR_API_KEY", "zotero_library_id": "YOUR_LIBRARY_ID", "zotero_library_type": "user" }
Never commit credentials.
Install via the ai-research-skills Claude Code marketplace:
claude plugin marketplace add WenyuChiou/ai-research-skills
claude plugin install zotero-skills@ai-research-skills --scope user
Migrating from a previous
cp -r/git cloneinstall? SKILL.md moved from the repo root toskills/zotero-skills/SKILL.mdfor marketplace auto-discovery. The oldcp -r zotero-skills/ ~/.claude/skills/zotero-skills/layout no longer loads (Claude Code scans only one level deep). Remove the old copy (rm -rf ~/.claude/skills/zotero-skills) and run the marketplace install above.
This skill was developed for Claude Code but works with any AI assistant.
| CLI | How to load the skill |
|---|---|
| Claude Code | Place in ~/.claude/skills/ or .claude/skills/ — auto-loaded |
| Codex CLI | Load the inner skills/zotero-skills/SKILL.md through skills discovery or task context; -C / --cd selects the working directory, not a context file |
| Gemini CLI | Include SKILL.md in system prompt or project context |
| Cursor / Windsurf | Add SKILL.md to .cursor/rules or equivalent rules file |
| Any other tool | Paste relevant sections of SKILL.md into your system prompt |
zotero-skills/
├── .claude-plugin/plugin.json # Marketplace manifest
├── config.example.json # Template for API credentials
├── config.json # Your credentials (gitignored — never committed)
├── requirements.txt # pyzotero dependency
├── LICENSE # MIT
├── scripts/
│ ├── zotero_client.py # ZoteroDualClient + helpers
│ └── add_literature.py # Batch import script template
├── skills/zotero-skills/
│ ├── SKILL.md # Agent operating rules
│ └── references/ # api-setup, read/create/update/delete-operations,
│ └── ... # error-handling, endpoint-cheatsheet, api-reference, item-types
├── README.md # English
└── README_zh-TW.md # 繁體中文
Zotero exposes two APIs with different capabilities. This skill routes automatically.
Local API (localhost:23119) | Web API (api.zotero.org) | |
|---|---|---|
| Access | Requires Zotero desktop running | Works anywhere |
| Read | ✅ Fast, full-text search | ✅ Standard queries |
| Write | ❌ Not supported (501) | ✅ Full CRUD |
| Rate limit | None | ~100 req / 10 sec (dynamic; honor Backoff/Retry-After headers) |
| Auth | Zotero-Allowed-Request: true header | Zotero-API-Key: <key> header |
On initialization, ZoteroDualClient calls check_local_api() — a lightweight GET to localhost:23119.
from scripts.zotero_client import ZoteroDualClient
dual = ZoteroDualClient()
# dual.local_available → True if Zotero desktop running, False otherwise
results = dual.search("flood adaptation") # local API if available
dual.create_note("ITEM_KEY", "Section", "Notes...") # always web API
ZOTERO_LOCAL=true, its write tools will fail — use zotero_client.py for writesFrom scripts/zotero_client.py:
| Function | Description |
|---|---|
get_client() | Configured pyzotero.Zotero Web API instance |
get_collection(name) | Find collection key by display name from config.json |
add_note(zot, item_key, content) | Attach a child note to a library item |
check_duplicate(zot, title, doi) | Check if item with given title or DOI exists |
check_local_api(timeout, library_id) | Test if Zotero desktop local API is reachable |
ZoteroDualClient | Dual-API wrapper — local reads, web writes, auto-fallback |
safe_api_call(func) | API call wrapper with automatic rate-limit backoff |
Run from the repository/plugin root, which contains scripts/. A portable
SKILL.md copy alone does not include the shared client.
from scripts.zotero_client import ZoteroDualClient
dual = ZoteroDualClient()
print(f"Local API available: {dual.local_available}")
results = dual.search("flood risk perception")
dual.create_note("I3P2J58S", "Section 2", "<p>Discusses PMT framework.</p>")
from pyzotero import zotero
zot = zotero.Zotero("YOUR_LIBRARY_ID", "user", "YOUR_API_KEY")
template = zot.item_template("journalArticle")
template["title"] = "Deep Learning for NLP: A Survey"
template["creators"] = [{"creatorType": "author", "firstName": "Jane", "lastName": "Doe"}]
template["publicationTitle"] = "Nature Machine Intelligence"
template["date"] = "2025"
template["DOI"] = "10.1038/s42256-025-00001-1"
resp = zot.create_items([template])
items = zot.items(tag="machine-learning", limit=25)
for item in items:
print(f"{item['data']['title']} — {item['data'].get('date', 'n.d.')}")
MIT