Survey Researcher Papers
Build or expand a source-grounded researcher portfolio, archive it cleanly in Zotero, then analyze it in Obsidian. Treat selection, Zotero ingestion, PDF acquisition, attachment, and analysis as separately auditable phases.
Operating Rules
- Read raw source material before summarizing. Keep verbatim bibliographic fields and source URLs in an evidence ledger; place interpretations in separate fields.
- Never invent a paper, DOI, authorship, venue, citation count, abstract, access status, or research claim. Mark unresolved conflicts explicitly.
- Treat ten papers as a useful first-pass recommendation, not a fixed requirement. Respect any user-specified count; for repeated calls, add only enough new papers to address the requested depth or uncovered themes.
- Ask one concise question when the user's target area or weighting is unknown. Ask for research topics, industry/application preferences, and whether relevance, impact, or recency should dominate. Otherwise use the default ranking below.
- Prefer APIs, HTTP downloads, scripts, and isolated subagents. Never invoke Browser, Computer Use, Playwright, Selenium, or other UI automation in this workflow.
- When a write-capable Zotero Web API key is configured, prefer deterministic scripted creation of linked-file child attachments. Use Attanger's manual Match Attachment workflow only as a fallback; use a multi-file manual batch only after proving an unambiguous one-to-one title match.
- Treat
ZOTERO_API_KEY with personal-library read/write access as required for automated Zotero writes, including item/tag updates, attachment creation, and duplicate deletion. The local Zotero API is read-only for this workflow. Never ask the user to paste the key into chat; ask them to configure it as a user environment variable.
- Treat user assistance as required for closed-access papers when no lawful publisher, arXiv, institutional-repository, or author-manuscript copy can be retrieved. Do not bypass access controls or silently substitute another paper.
- Use only lawful full-text sources. Never bypass paywalls, access controls, CAPTCHAs, or institutional authentication.
- Preserve existing Zotero fields, tags, collections, attachments, and Obsidian notes unless a correction is verified and intentional.
1. Preflight
- Read references/local-setup.md. Re-check live paths and preferences because the file is a known-good snapshot, not an eternal assumption.
- Confirm the researcher identity using affiliation, department, ORCID, lab page, coauthors, and research topics. Do not merge namesakes.
- Confirm the user's interests. If absent, ask once; if the user does not specify weights, use:
- relevance to stated interests: 45%
- field- and age-aware impact: 25%
- recency/current lab direction: 20%
- portfolio representativeness: 10%
- Resolve the target Zotero collection with this precedence: explicit user instruction, invocation/manifest setting, relevant existing project collection, then the local default
SupervisorSearch. Confirm the resolved collection exists. Never redirect an explicitly named collection to the default.
- For any workflow that will modify Zotero, read
ZOTERO_API_KEY from the environment and verify GET https://api.zotero.org/keys/current returns the expected user ID and access.user.write: true. If the key is absent or read-only, stop automated writes and ask the user to configure or update it. Do not accept the secret in chat.
Run the read-only Attanger safety check against the configured source directory before staging:
python <SKILL_DIR>\scripts\attanger_preflight.py --expected-files 0
Require status: ready, a real linked_attachment_base_dir, and a non-null zotero_path_prefix. The prefix must be derived from Zotero's live baseAttachmentPath and Attanger's live destination. Never assume the Attanger destination itself is Zotero's base. For example, a base of ...\attachments plus a destination of ...\attachments\zotero requires attachments:zotero/..., not attachments:....
If the source directory already contains PDFs, reconcile every file first. Delete a source copy only when Zotero already has the correct child attachment, the final linked file exists, and SHA-256 proves the source and final files are identical. Leave all unverified files untouched and treat them as a stop condition.
2. Build the Evidence Ledger
Collect a candidate pool large enough to support the requested batch and distinguish it from papers already curated; roughly 25-50 candidates is a starting heuristic, not a cap. Start with the researcher's official profile, publication list, ORCID, and institutional repository; verify metadata through DOI/publisher pages, Crossref, OpenAlex, and arXiv. Use Google Scholar only as a discovery/secondary signal when primary records are insufficient.
For every candidate preserve:
- exact title, complete author list, year/date, venue, volume/issue/pages
- DOI and canonical publisher URL
- raw abstract or publisher-provided summary, with source URL
- citation count, source, and retrieval date when impact is considered
- open-access/full-text locations and version type
- concise evidence-based relevance note
- authorship confidence that the target researcher is the intended person
Do not copy entire copyrighted papers into the ledger. Raw content means necessary source text and metadata, not wholesale reproduction.
3. Rank and Select a Batch
Score candidates transparently, then apply judgment:
- Prefer papers directly aligned with the user's target problems and methods.
- Normalize citation evidence for publication age and field; do not treat raw citations or journal impact factor as universal quality measures.
- Include recent papers that reveal the researcher's current direction.
- Include influential or foundational papers that define the researcher's contribution.
- Avoid filling the batch with near-duplicates from one narrow project unless the user requests that depth.
- Down-rank papers where the target researcher is only tangentially connected unless that collaboration is strategically important.
First determine whether this is an initial survey or an expansion:
- Initial survey: if no count is specified, recommend about ten papers as a manageable starting set. Increase toward 10-20 when the researcher's portfolio is broad and the user requests comprehensive coverage.
- Expansion: audit existing
researcher:<slug> Zotero items, legacy supervisor:<slug> items from earlier runs, and completed literature notes; map covered topics/methods/periods, then select only new papers that fill explicit gaps. If no count is specified, size the batch from the number and importance of uncovered areas rather than repeating ten mechanically.
- Explicit count: select that many papers when the evidence pool supports it; explain if fewer defensible matches exist.
For a typical initial batch, balance directly relevant, influential/foundational, and recent/current work. Adapt the proportions to the user's purpose. A paper may satisfy multiple roles.
Before ingestion, present a compact table with batch rank, cumulative status (new/already curated), title, year, role, relevance evidence, impact evidence, DOI, and access status. Keep a reserve list for metadata conflicts or inaccessible papers; do not silently substitute a reserve paper after the user has seen the selection.
4. Upsert Zotero Records
Create a manifest following references/manifest-schema.md. Then validate and upsert it:
python <SKILL_DIR>\scripts\zotero_upsert.py --manifest <manifest.json> --validate-only
python <SKILL_DIR>\scripts\zotero_upsert.py --manifest <manifest.json> --apply
When the user specifies a destination, encode it in target_collection or pass --collection-key / --collection-name. Use the local default only when no destination was specified. Use --count only as an optional assertion, not as the source of batch size.
Use a write-capable Zotero Web API key through ZOTERO_API_KEY; never place the key in a command, manifest, note, or chat message. Ask the user to configure the environment variable when it is absent. The local Zotero API remains useful for reads and audits but must not be assumed writable.
Deduplicate across the entire Zotero library by normalized DOI first, then normalized title plus year. Add missing or matching items to the resolved target collection. Merge, never replace, existing collections or tags.
Apply these tags:
researcher-search
researcher:<researcher-slug>
selection:curated
selection-batch:<batch-id> and selection-rank:<batch-id>:NN when a batch ID exists
access:open, access:closed, or access:needs-user
priority:high, priority:medium, or priority:low
- concise topic/method/application tags grounded in the abstract or full text
Use selection:top-N only when the user explicitly requests a ranked top-N shortlist. After the web write, allow Zotero desktop to sync. Audit every parent item in the current batch before handling PDFs.
5. Acquire and Validate PDFs
Delegate each selected paper, in rank order, to the existing $acquire-paper-pdf skill. Pass the exact title, DOI, compatible authorship, canonical publisher URL, target directory, and expected filename from the evidence ledger.
That skill owns OA discovery, ordinary HTTP attempts, bounded retry behavior, PDF identity validation, and precise human handoff. Browser and Computer Use are disabled; do not duplicate or add UI automation here.
Handle its result contract as follows:
acquired: record the validated absolute path, SHA-256, source URL, and version; continue to attachment.
needs-user: continue processing other papers and add its exact requested action to the human-download list.
not-found: keep the Zotero parent metadata, mark access unresolved, and report routes checked.
identity-conflict: preserve the candidate for review outside the final attachment tree and do not attach it.
Do not treat a publisher landing page, browser-only viewer, abstract, supplementary file, or unvalidated PDF as acquired.
6. Attach PDFs
Preferred: Automated Linked Files
When ZOTERO_API_KEY has personal-library write access:
- Verify
/keys/current returns the expected user ID and access.user.write: true.
- Strictly validate each PDF first and record its SHA-256. Build the archive manifest described in references/manifest-schema.md, including the source, final absolute destination, parent key, optional existing attachment key, expected hash, and
identity_validated: true. Do not hand-write a Zotero attachments: path.
- Run the deterministic archive transaction:
python <SKILL_DIR>\scripts\zotero_archive.py --manifest <archive-manifest.json> --validate-only
python <SKILL_DIR>\scripts\zotero_archive.py --manifest <archive-manifest.json> --apply
- The script must read Zotero's live linked-attachment base and Attanger's live destination, prove the destination is inside both roots, and derive
attachments:<relative-path-from-live-base>. A null/mismatched base, destination outside the base, duplicate destination, unexpected PDF child, or hash mismatch is a stop condition.
- The archive transaction copies rather than moves the source, verifies the destination hash, creates or explicitly repairs the linked-file child, reads it back from the Web API, waits for desktop sync, resolves the local API path against the same live base, and verifies the final file/hash. Preserve both files on any failure.
- Use
--cleanup-source only when the user wants source copies removed. Cleanup happens after all verification and only for a byte-identical source; conversion artifacts under zotero_convert are always preserved. Delete superseded Zotero child records only in a separate, exact-key operation after the replacement has passed verification.
- Re-run strict DOI/title validation against the verified final path. Require exactly one intended valid linked-file child per target parent before reporting completion.
Do not bypass zotero_archive.py with an ad hoc Web API attachment payload, and do not run Attanger Match Attachment concurrently with this automated mode.
Fallback: Manual Attanger Matching
Attanger's matcher greedily chooses the nearest title among every PDF in its source directory and does not enforce a maximum-distance threshold. It may prefer embedded PDF metadata or an optically inferred page title over an exact source filename. Therefore:
- Keep Attanger's configured source directory; do not redirect it to a separate inbox. In the verified local setup this is
C:\Users\Yuanyuan\Downloads.
- Before staging, inspect every existing PDF/CAJ in that directory. Remove only byte-identical duplicate source copies whose correct final Zotero linked attachment has already been verified. Never remove an unrelated or unresolved user file.
- Move each validated batch PDF directly into the configured source directory so no extra copy remains elsewhere.
- Name each staged PDF from the exact Zotero title. Inspect its embedded
/Title; for a multi-file batch, normalize that field to the exact Zotero plain title when it is missing or misleading, then rerun strict DOI/title validation because rewriting metadata changes the file hash.
- Write the validated staged basenames to a temporary
expected-pdfs.txt, one per line. Run attanger_preflight.py --expected-list <expected-pdfs.txt> and require status: ready; delete the temporary list after checking.
- Use a multi-file batch only when every effective PDF title has one unique intended Zotero parent and the counts match exactly. If this cannot be proved, put only one PDF in the source directory and select only its one parent.
- Ask the user to select only the corresponding parent record or records in the resolved target collection; do not automate this UI action.
- Ask the user to invoke Attanger Match Attachment (
Ctrl+M in the verified local setup); do not automate the shortcut. Repeat one-file invocations when batch safety was not established.
- Let Attanger import, auto-move, and convert attachments to linked files under its configured destination.
- Immediately verify each PDF is a child of the correct parent, opens successfully, and resolves to an existing linked path. Check DOI/title and SHA-256 again after attachment.
- If any attachment is mismatched, preserve every physical file, identify it by hash/content rather than destination filename, remove the incorrect Zotero child through the Web API or explicit user action, and restage it before continuing.
- Search for remaining copies outside the final linked path. Delete a duplicate only after its SHA-256 matches the verified final attachment; preserve all nonmatching files.
7. Handle Closed Access
For every paper not acquired automatically, use the $acquire-paper-pdf result instead of starting an independent second download search. Keep the Zotero metadata record, set access:needs-user when appropriate, and ask the user for help with a precise list containing rank, title, DOI, publisher link, blocked step, and desired filename. The user may download through their institutional access.
When the user supplies a file, validate it and move it into Attanger's configured source directory. Never request credentials or ask the user to send an API key in chat.
For each paper requiring user-assisted download, provide the exact title, DOI, canonical publisher URL, and expected filename. Continue processing already available papers, but mark the inaccessible paper access:needs-user and do not claim full-text analysis until the supplied PDF passes strict identity validation.
8. Create Obsidian Literature Notes
Begin only after the Zotero metadata/tag stage is audited. Missing PDFs may remain explicitly blocked while available papers continue.
Do not run a multi-paper $analyze-paper batch in the main conversation. Delegate each paper to an isolated subagent and keep the main agent limited to scheduling, status records, and final integration. Read references/subagent-paper-analysis.md before dispatch.
- Resolve each item's Better BibTeX citekey and validated local PDF path from Zotero.
- Create one self-contained job manifest per citekey. Include the rank, DOI, PDF path and SHA-256, Zotero tags, user research interests, expected language, vault paths, and quality requirements. Never include secrets or unrelated conversation history.
- Resolve the existing
$analyze-paper skill path and SHA-256 before dispatch. Spawn one worker subagent per ready paper with fork_context: false and pass that skill as a required structured skill item. Reject a worker result that does not attest to the same skill path/hash. The worker owns only that citekey's conversion directory, figure directory, and literature note.
- Keep the worker on the inherited parent model and effort. Use subagents only when the spawning tool contract explicitly guarantees that omitted model and reasoning-effort overrides inherit the main agent. Omit both overrides, record
inherit-parent in the ledger, and never select a weaker model or lower effort. Set a higher effort only when the runtime explicitly confirms that the same inherited model supports it. If inheritance is not guaranteed, stop instead of silently analyzing in the main context or downgrading.
- Probe available RAM, free disk, and GPU/VRAM before dispatch. Allow resource-aware parallel waves: at most two concurrent workers when MinerU conversion is required and at most four when verified MinerU output already exists. Use one on CPU-only, unknown-capacity, or memory-constrained systems. On OOM, swapping, incomplete parse, or abrupt worker failure, stop the wave, reduce concurrency by one, clean only that job's incomplete output, and retry once serially.
- Require MinerU full-text parsing and the existing literature-note template. Do not summarize from an abstract when the task claims full-paper analysis. Preserve selection and topic tags through
$analyze-paper's tag merge behavior.
- After each worker finishes, dispatch an independent reviewer subagent with the same model/effort inheritance. The reviewer compares the note with the parsed full text and checks methods, equations, experiments, numerical results, limitations, figures, and unsupported claims.
- If review fails, send the findings back to the original worker for one focused revision, then review again. Keep the worker open until reviewer
pass or final needs-review; if the runtime cannot retain it, spawn a replacement revision worker with the identical job and write ownership. Do not silently accept an incomplete note.
- Bind worker and reviewer results to immutable artifact hashes: PDF, parsed full text, final note, and analyze-paper skill. Reviewers are read-only and must route every correction through a worker. A changed note requires a new review.
- Immediately before completion, recompute the live on-disk hashes for the PDF, parsed full text, note, and analyze-paper skill, then reconcile the selected set: every validated downloaded PDF must map to exactly one citekey, one worker job, one existing note, and reviewer
pass. Any missing, duplicate, stale, or hash-mismatched mapping keeps the overall workflow incomplete.
- Close worker and reviewer agents only after their final result is recorded and no revision remains. Record blocked citekeys separately.
Completion Report
Return one status table with rank, paper, DOI, Zotero parent status, tags, PDF source, Attanger attachment status, citekey, worker status, reviewer status, and Obsidian note status. Report exact blockers and the next human action; do not describe an inaccessible or unreviewed paper as analyzed.
1---2name: survey-researcher-papers3description: Research and iteratively curate any academic researcher's publication portfolio end to end: disambiguate the author, preserve raw evidence, select an adaptive batch of relevant/impactful/recent papers, add deduplicated records to a user-selected Zotero collection, delegate lawful PDF retrieval to $acquire-paper-pdf, attach validated files, and initialize reviewed Obsidian literature notes through $analyze-paper. Use for a first reading set or repeated expansion when deeper coverage of a researcher, topic, method, or period is needed.4---56# Survey Researcher Papers78Build or expand a source-grounded researcher portfolio, archive it cleanly in Zotero, then analyze it in Obsidian. Treat selection, Zotero ingestion, PDF acquisition, attachment, and analysis as separately auditable phases.910## Operating Rules1112- Read raw source material before summarizing. Keep verbatim bibliographic fields and source URLs in an evidence ledger; place interpretations in separate fields.13- Never invent a paper, DOI, authorship, venue, citation count, abstract, access status, or research claim. Mark unresolved conflicts explicitly.14- Treat ten papers as a useful first-pass recommendation, not a fixed requirement. Respect any user-specified count; for repeated calls, add only enough new papers to address the requested depth or uncovered themes.15- Ask one concise question when the user's target area or weighting is unknown. Ask for research topics, industry/application preferences, and whether relevance, impact, or recency should dominate. Otherwise use the default ranking below.16- Prefer APIs, HTTP downloads, scripts, and isolated subagents. Never invoke Browser, Computer Use, Playwright, Selenium, or other UI automation in this workflow.17- When a write-capable Zotero Web API key is configured, prefer deterministic scripted creation of linked-file child attachments. Use Attanger's manual Match Attachment workflow only as a fallback; use a multi-file manual batch only after proving an unambiguous one-to-one title match.18- Treat `ZOTERO_API_KEY` with personal-library read/write access as required for automated Zotero writes, including item/tag updates, attachment creation, and duplicate deletion. The local Zotero API is read-only for this workflow. Never ask the user to paste the key into chat; ask them to configure it as a user environment variable.19- Treat user assistance as required for closed-access papers when no lawful publisher, arXiv, institutional-repository, or author-manuscript copy can be retrieved. Do not bypass access controls or silently substitute another paper.20- Use only lawful full-text sources. Never bypass paywalls, access controls, CAPTCHAs, or institutional authentication.21- Preserve existing Zotero fields, tags, collections, attachments, and Obsidian notes unless a correction is verified and intentional.2223## 1. Preflight24251. Read [references/local-setup.md](references/local-setup.md). Re-check live paths and preferences because the file is a known-good snapshot, not an eternal assumption.262. Confirm the researcher identity using affiliation, department, ORCID, lab page, coauthors, and research topics. Do not merge namesakes.273. Confirm the user's interests. If absent, ask once; if the user does not specify weights, use:28 - relevance to stated interests: 45%29 - field- and age-aware impact: 25%30 - recency/current lab direction: 20%31 - portfolio representativeness: 10%324. Resolve the target Zotero collection with this precedence: explicit user instruction, invocation/manifest setting, relevant existing project collection, then the local default `SupervisorSearch`. Confirm the resolved collection exists. Never redirect an explicitly named collection to the default.335. For any workflow that will modify Zotero, read `ZOTERO_API_KEY` from the environment and verify `GET https://api.zotero.org/keys/current` returns the expected user ID and `access.user.write: true`. If the key is absent or read-only, stop automated writes and ask the user to configure or update it. Do not accept the secret in chat.3435Run the read-only Attanger safety check against the configured source directory before staging:3637```powershell38python <SKILL_DIR>\scripts\attanger_preflight.py --expected-files 039```4041Require `status: ready`, a real `linked_attachment_base_dir`, and a non-null `zotero_path_prefix`. The prefix must be derived from Zotero's live `baseAttachmentPath` and Attanger's live destination. Never assume the Attanger destination itself is Zotero's base. For example, a base of `...\attachments` plus a destination of `...\attachments\zotero` requires `attachments:zotero/...`, not `attachments:...`.4243If the source directory already contains PDFs, reconcile every file first. Delete a source copy only when Zotero already has the correct child attachment, the final linked file exists, and SHA-256 proves the source and final files are identical. Leave all unverified files untouched and treat them as a stop condition.4445## 2. Build the Evidence Ledger4647Collect a candidate pool large enough to support the requested batch and distinguish it from papers already curated; roughly 25-50 candidates is a starting heuristic, not a cap. Start with the researcher's official profile, publication list, ORCID, and institutional repository; verify metadata through DOI/publisher pages, Crossref, OpenAlex, and arXiv. Use Google Scholar only as a discovery/secondary signal when primary records are insufficient.4849For every candidate preserve:5051- exact title, complete author list, year/date, venue, volume/issue/pages52- DOI and canonical publisher URL53- raw abstract or publisher-provided summary, with source URL54- citation count, source, and retrieval date when impact is considered55- open-access/full-text locations and version type56- concise evidence-based relevance note57- authorship confidence that the target researcher is the intended person5859Do not copy entire copyrighted papers into the ledger. Raw content means necessary source text and metadata, not wholesale reproduction.6061## 3. Rank and Select a Batch6263Score candidates transparently, then apply judgment:6465- Prefer papers directly aligned with the user's target problems and methods.66- Normalize citation evidence for publication age and field; do not treat raw citations or journal impact factor as universal quality measures.67- Include recent papers that reveal the researcher's current direction.68- Include influential or foundational papers that define the researcher's contribution.69- Avoid filling the batch with near-duplicates from one narrow project unless the user requests that depth.70- Down-rank papers where the target researcher is only tangentially connected unless that collaboration is strategically important.7172First determine whether this is an initial survey or an expansion:7374- Initial survey: if no count is specified, recommend about ten papers as a manageable starting set. Increase toward 10-20 when the researcher's portfolio is broad and the user requests comprehensive coverage.75- Expansion: audit existing `researcher:<slug>` Zotero items, legacy `supervisor:<slug>` items from earlier runs, and completed literature notes; map covered topics/methods/periods, then select only new papers that fill explicit gaps. If no count is specified, size the batch from the number and importance of uncovered areas rather than repeating ten mechanically.76- Explicit count: select that many papers when the evidence pool supports it; explain if fewer defensible matches exist.7778For a typical initial batch, balance directly relevant, influential/foundational, and recent/current work. Adapt the proportions to the user's purpose. A paper may satisfy multiple roles.7980Before ingestion, present a compact table with batch rank, cumulative status (new/already curated), title, year, role, relevance evidence, impact evidence, DOI, and access status. Keep a reserve list for metadata conflicts or inaccessible papers; do not silently substitute a reserve paper after the user has seen the selection.8182## 4. Upsert Zotero Records8384Create a manifest following [references/manifest-schema.md](references/manifest-schema.md). Then validate and upsert it:8586```powershell87python <SKILL_DIR>\scripts\zotero_upsert.py --manifest <manifest.json> --validate-only88python <SKILL_DIR>\scripts\zotero_upsert.py --manifest <manifest.json> --apply89```9091When the user specifies a destination, encode it in `target_collection` or pass `--collection-key` / `--collection-name`. Use the local default only when no destination was specified. Use `--count` only as an optional assertion, not as the source of batch size.9293Use a write-capable Zotero Web API key through `ZOTERO_API_KEY`; never place the key in a command, manifest, note, or chat message. Ask the user to configure the environment variable when it is absent. The local Zotero API remains useful for reads and audits but must not be assumed writable.9495Deduplicate across the entire Zotero library by normalized DOI first, then normalized title plus year. Add missing or matching items to the resolved target collection. Merge, never replace, existing collections or tags.9697Apply these tags:9899- `researcher-search`100- `researcher:<researcher-slug>`101- `selection:curated`102- `selection-batch:<batch-id>` and `selection-rank:<batch-id>:NN` when a batch ID exists103- `access:open`, `access:closed`, or `access:needs-user`104- `priority:high`, `priority:medium`, or `priority:low`105- concise topic/method/application tags grounded in the abstract or full text106107Use `selection:top-N` only when the user explicitly requests a ranked top-N shortlist. After the web write, allow Zotero desktop to sync. Audit every parent item in the current batch before handling PDFs.108109## 5. Acquire and Validate PDFs110111Delegate each selected paper, in rank order, to the existing `$acquire-paper-pdf` skill. Pass the exact title, DOI, compatible authorship, canonical publisher URL, target directory, and expected filename from the evidence ledger.112113That skill owns OA discovery, ordinary HTTP attempts, bounded retry behavior, PDF identity validation, and precise human handoff. Browser and Computer Use are disabled; do not duplicate or add UI automation here.114115Handle its result contract as follows:116117- `acquired`: record the validated absolute path, SHA-256, source URL, and version; continue to attachment.118- `needs-user`: continue processing other papers and add its exact requested action to the human-download list.119- `not-found`: keep the Zotero parent metadata, mark access unresolved, and report routes checked.120- `identity-conflict`: preserve the candidate for review outside the final attachment tree and do not attach it.121122Do not treat a publisher landing page, browser-only viewer, abstract, supplementary file, or unvalidated PDF as acquired.123124## 6. Attach PDFs125126### Preferred: Automated Linked Files127128When `ZOTERO_API_KEY` has personal-library write access:1291301. Verify `/keys/current` returns the expected user ID and `access.user.write: true`.1312. Strictly validate each PDF first and record its SHA-256. Build the archive manifest described in [references/manifest-schema.md](references/manifest-schema.md), including the source, final absolute destination, parent key, optional existing attachment key, expected hash, and `identity_validated: true`. Do not hand-write a Zotero `attachments:` path.1323. Run the deterministic archive transaction:133134```powershell135python <SKILL_DIR>\scripts\zotero_archive.py --manifest <archive-manifest.json> --validate-only136python <SKILL_DIR>\scripts\zotero_archive.py --manifest <archive-manifest.json> --apply137```1381394. The script must read Zotero's live linked-attachment base and Attanger's live destination, prove the destination is inside both roots, and derive `attachments:<relative-path-from-live-base>`. A null/mismatched base, destination outside the base, duplicate destination, unexpected PDF child, or hash mismatch is a stop condition.1405. The archive transaction copies rather than moves the source, verifies the destination hash, creates or explicitly repairs the linked-file child, reads it back from the Web API, waits for desktop sync, resolves the local API path against the same live base, and verifies the final file/hash. Preserve both files on any failure.1416. Use `--cleanup-source` only when the user wants source copies removed. Cleanup happens after all verification and only for a byte-identical source; conversion artifacts under `zotero_convert` are always preserved. Delete superseded Zotero child records only in a separate, exact-key operation after the replacement has passed verification.1427. Re-run strict DOI/title validation against the verified final path. Require exactly one intended valid linked-file child per target parent before reporting completion.143144Do not bypass `zotero_archive.py` with an ad hoc Web API attachment payload, and do not run Attanger Match Attachment concurrently with this automated mode.145146### Fallback: Manual Attanger Matching147148Attanger's matcher greedily chooses the nearest title among every PDF in its source directory and does not enforce a maximum-distance threshold. It may prefer embedded PDF metadata or an optically inferred page title over an exact source filename. Therefore:1491501. Keep Attanger's configured source directory; do not redirect it to a separate inbox. In the verified local setup this is `C:\Users\Yuanyuan\Downloads`.1512. Before staging, inspect every existing PDF/CAJ in that directory. Remove only byte-identical duplicate source copies whose correct final Zotero linked attachment has already been verified. Never remove an unrelated or unresolved user file.1523. Move each validated batch PDF directly into the configured source directory so no extra copy remains elsewhere.1534. Name each staged PDF from the exact Zotero title. Inspect its embedded `/Title`; for a multi-file batch, normalize that field to the exact Zotero plain title when it is missing or misleading, then rerun strict DOI/title validation because rewriting metadata changes the file hash.1545. Write the validated staged basenames to a temporary `expected-pdfs.txt`, one per line. Run `attanger_preflight.py --expected-list <expected-pdfs.txt>` and require `status: ready`; delete the temporary list after checking.1556. Use a multi-file batch only when every effective PDF title has one unique intended Zotero parent and the counts match exactly. If this cannot be proved, put only one PDF in the source directory and select only its one parent.1567. Ask the user to select only the corresponding parent record or records in the resolved target collection; do not automate this UI action.1578. Ask the user to invoke Attanger **Match Attachment** (`Ctrl+M` in the verified local setup); do not automate the shortcut. Repeat one-file invocations when batch safety was not established.1589. Let Attanger import, auto-move, and convert attachments to linked files under its configured destination.15910. Immediately verify each PDF is a child of the correct parent, opens successfully, and resolves to an existing linked path. Check DOI/title and SHA-256 again after attachment.16011. If any attachment is mismatched, preserve every physical file, identify it by hash/content rather than destination filename, remove the incorrect Zotero child through the Web API or explicit user action, and restage it before continuing.16112. Search for remaining copies outside the final linked path. Delete a duplicate only after its SHA-256 matches the verified final attachment; preserve all nonmatching files.162163## 7. Handle Closed Access164165For every paper not acquired automatically, use the `$acquire-paper-pdf` result instead of starting an independent second download search. Keep the Zotero metadata record, set `access:needs-user` when appropriate, and ask the user for help with a precise list containing rank, title, DOI, publisher link, blocked step, and desired filename. The user may download through their institutional access.166167When the user supplies a file, validate it and move it into Attanger's configured source directory. Never request credentials or ask the user to send an API key in chat.168169For each paper requiring user-assisted download, provide the exact title, DOI, canonical publisher URL, and expected filename. Continue processing already available papers, but mark the inaccessible paper `access:needs-user` and do not claim full-text analysis until the supplied PDF passes strict identity validation.170171## 8. Create Obsidian Literature Notes172173Begin only after the Zotero metadata/tag stage is audited. Missing PDFs may remain explicitly blocked while available papers continue.174175Do not run a multi-paper `$analyze-paper` batch in the main conversation. Delegate each paper to an isolated subagent and keep the main agent limited to scheduling, status records, and final integration. Read [references/subagent-paper-analysis.md](references/subagent-paper-analysis.md) before dispatch.1761771. Resolve each item's Better BibTeX citekey and validated local PDF path from Zotero.1782. Create one self-contained job manifest per citekey. Include the rank, DOI, PDF path and SHA-256, Zotero tags, user research interests, expected language, vault paths, and quality requirements. Never include secrets or unrelated conversation history.1793. Resolve the existing `$analyze-paper` skill path and SHA-256 before dispatch. Spawn one worker subagent per ready paper with `fork_context: false` and pass that skill as a required structured skill item. Reject a worker result that does not attest to the same skill path/hash. The worker owns only that citekey's conversion directory, figure directory, and literature note.1804. Keep the worker on the inherited parent model and effort. Use subagents only when the spawning tool contract explicitly guarantees that omitted model and reasoning-effort overrides inherit the main agent. Omit both overrides, record `inherit-parent` in the ledger, and never select a weaker model or lower effort. Set a higher effort only when the runtime explicitly confirms that the same inherited model supports it. If inheritance is not guaranteed, stop instead of silently analyzing in the main context or downgrading.1815. Probe available RAM, free disk, and GPU/VRAM before dispatch. Allow resource-aware parallel waves: at most two concurrent workers when MinerU conversion is required and at most four when verified MinerU output already exists. Use one on CPU-only, unknown-capacity, or memory-constrained systems. On OOM, swapping, incomplete parse, or abrupt worker failure, stop the wave, reduce concurrency by one, clean only that job's incomplete output, and retry once serially.1826. Require MinerU full-text parsing and the existing literature-note template. Do not summarize from an abstract when the task claims full-paper analysis. Preserve selection and topic tags through `$analyze-paper`'s tag merge behavior.1837. After each worker finishes, dispatch an independent reviewer subagent with the same model/effort inheritance. The reviewer compares the note with the parsed full text and checks methods, equations, experiments, numerical results, limitations, figures, and unsupported claims.1848. If review fails, send the findings back to the original worker for one focused revision, then review again. Keep the worker open until reviewer `pass` or final `needs-review`; if the runtime cannot retain it, spawn a replacement revision worker with the identical job and write ownership. Do not silently accept an incomplete note.1859. Bind worker and reviewer results to immutable artifact hashes: PDF, parsed full text, final note, and analyze-paper skill. Reviewers are read-only and must route every correction through a worker. A changed note requires a new review.18610. Immediately before completion, recompute the live on-disk hashes for the PDF, parsed full text, note, and analyze-paper skill, then reconcile the selected set: every validated downloaded PDF must map to exactly one citekey, one worker job, one existing note, and reviewer `pass`. Any missing, duplicate, stale, or hash-mismatched mapping keeps the overall workflow incomplete.18711. Close worker and reviewer agents only after their final result is recorded and no revision remains. Record blocked citekeys separately.188189## Completion Report190191Return one status table with rank, paper, DOI, Zotero parent status, tags, PDF source, Attanger attachment status, citekey, worker status, reviewer status, and Obsidian note status. Report exact blockers and the next human action; do not describe an inaccessible or unreviewed paper as analyzed.