Zotero Todoist Reading Tasks
Turn a saved Zotero reading queue into one Todoist task per Zotero parent item.
Keep Zotero read-only and make each Todoist task a durable, directly linked
progress record.
Authority and tool routing
- Inspect Zotero and Todoist before writing. Do not mutate Zotero.
- Treat an explicit request to create, schedule, reconcile, or repair reading
tasks as authority only for the named Todoist project, collection, and tasks.
- A named Zotero item or collection request also authorizes at most one
create-or-reuse action per uniquely resolved Zotero parent through
$paper-read-draft. This bounded note authority is inherited from that named
request; it does not authorize any other PaperRead note work.
- An explicit request for
without Obsidian notes opts out of PaperRead work for
that run. On opt-out, perform no PaperRead note operation and preserve any
existing Obsidian line in a matched Todoist task.
- Require the exact task identity and an explicit deletion request before
deleting anything. Do not infer cleanup authority from a reconciliation.
- Prefer the connected Todoist app when it is available. Use the official hosted
Todoist MCP only as a fallback. Choose exactly one Todoist tool surface for the
request, never both.
- Do not create a project, section, or label unless the user explicitly asks for
that structure. Resolve existing targets before task changes.
- Route missing-paper imports, metadata repair, and attachment repair to
$paper-library-intake; this workflow only reads Zotero.
Resolve the reading set
- Identify the active Zotero library and resolve the requested collection by
its full path and key. For a group library, obtain the numeric group ID from
the live library listing; never guess it.
- Call
zotero_get_collection_items for the resolved collection and retain
top-level bibliographic items. Exclude child attachments, notes, and
annotations as task candidates.
- Preserve the collection or user-provided order. When the user explicitly asks
for a prerequisite-aware order, inspect saved titles and abstracts and rank
foundational work before dependent systems or applications. State that this
order is a recommendation.
- For two or more parents, call
zotero_get_items_children once with all parent
keys. Use the single-item child tool only for one parent.
Build Zotero desktop links
Use the parent item key for selection and the PDF attachment key for opening a
PDF. Never pass a parent key to open-pdf.
For the personal library:
zotero://select/library/items/<PARENT_KEY>
zotero://open-pdf/library/items/<ATTACHMENT_KEY>
For a group library:
zotero://select/groups/<GROUP_ID>/items/<PARENT_KEY>
zotero://open-pdf/groups/<GROUP_ID>/items/<ATTACHMENT_KEY>
When exactly one PDF child exists, use its PDF attachment key. When there is no
PDF child, create or repair only the Show item link and report that the PDF
link is unavailable. When there are multiple PDF children, use an authoritative
primary attachment only if Zotero exposes one; otherwise ask instead of guessing.
Render a personal-library task line as:
Zotero: [Open PDF](zotero://open-pdf/library/items/<ATTACHMENT_KEY>) · [Show item](zotero://select/library/items/<PARENT_KEY>)
For an item without a PDF, render:
Zotero: [Show item](zotero://select/library/items/<PARENT_KEY>)
Substitute the group-library forms when applicable.
Create or reuse the PaperRead draft
For each uniquely resolved parent, after Zotero identity resolution and before
any Todoist write, invoke $paper-read-draft exactly once per uniquely resolved
Zotero parent unless the user explicitly requested without Obsidian notes.
Pass only the resolved parent identity and observed metadata that the PaperRead
skill needs; it remains the sole owner of note identity, safe creation, and URI
generation. Complete this PaperRead action once per parent before that parent's
first Todoist write, then reuse the recorded result for all later writes.
Use only the URI returned by $paper-read-draft when its result is created
or reused. Do not independently infer a note filename or URI.
With a returned URI, the managed line is exactly:
Obsidian: [Open PaperRead note](obsidian://open?vault=<ENCODED_VAULT>&file=<ENCODED_NOTE_PATH>)
Render the returned URI verbatim in that line; the placeholders illustrate
only the encoded values already present in the returned URI. Do not construct
a new URI.
A canonical managed Obsidian line has this exact full-line grammar:
Obsidian: [Open PaperRead note](obsidian://open?vault=<ENCODED_VAULT>&file=<ENCODED_NOTE_PATH>).
It has the exact label and prefix, and an obsidian://open target with
exactly two non-empty query parameters in that order: vault, then file.
It has no additional query parameters, no fragment, and no extra line text.
This predicate is independent of a current PaperRead result. Do not require
an existing canonical URI to equal a newly returned URI. Only this managed
form is replaceable or removable. Preserve any other Obsidian: line or any
other obsidian:// content unchanged and report the task as ambiguous for
manual review, including content with reversed query parameter order, an
extra query parameter, a fragment, a different label, or another
noncanonical form.
Treat link-unavailable, skipped, an unavailable PaperRead call, or a
missing returned URI as note-missing. Continue valid Todoist work without
adding a stale Obsidian line, and record note-missing with the reason.
On explicit opt-out, do not call $paper-read-draft, do not add, remove, or
replace an Obsidian line, and do not report a note failure.
Reconcile task identity
Search only the requested Todoist project or section before creating tasks.
- Match an existing task by its parent-key select URI first. This is the stable
identity for one Todoist task per Zotero parent item.
- For an older task without a Zotero URI, strip an optional
Read: prefix and
compare the normalized title with the Zotero title. Reuse it only for a
unique one-to-one match.
- Treat multiple task candidates or multiple Zotero title candidates as unsafe;
stop on ambiguity and show the candidates.
- If no match exists, create
Read: <paper title> in the requested target.
Maintain exactly one managed Zotero: line and, when PaperRead returned a URI,
exactly one managed Obsidian: line in the task description. On repair, replace
existing lines that begin with Zotero: and contain a zotero:// URI. For an
authorized returned PaperRead URI, replace all canonical managed Obsidian:
lines with exactly one current managed line. For note-missing, remove all
canonical managed Obsidian lines so no stale link remains and preserve every
other description line unchanged and in order. If a zotero:// or obsidian://
URI appears outside a managed line, do not duplicate or rewrite it; report the
task as ambiguous for manual review.
Repeated runs are idempotent reconciliation, not continuous synchronization.
Never claim that later Zotero or Todoist changes will propagate automatically.
Schedule the reading
- Treat the planned reading day as the Todoist due date and the final cutoff as
deadlineDate. Never substitute one for the other.
- If the user supplies an inclusive date range but no daily allocation, preserve
reading order and distribute tasks evenly across the available calendar days.
Put any quotient remainder on earlier days to retain buffer before the final
deadline. If fewer papers than days exist, use the earliest days.
- If only a final deadline is supplied, start the available range today in the
Todoist account timezone. Honor any excluded weekdays or unavailable dates the
user specifies.
- Use
dueString when creating a task. Use reschedule-tasks when moving an
existing task so recurring rules and time-of-day are preserved.
- A link-only repair must not change scheduling. Otherwise preserve existing
titles, labels, priority, hierarchy, duration, due time, and deadline unless
the user explicitly requests a change.
Apply and verify
- Preview the resolved Zotero parents, attachment choice, Todoist target,
matches, planned dates, final deadline, planned PaperRead action or opt-out,
and any ambiguity that blocks a write.
- Before each parent's first Todoist write, complete the authorized PaperRead
action once and record its
created, reused, link-unavailable,
skipped, or note-missing result. Reuse that recorded result for all
later writes for the parent. Apply only the authorized Todoist creations or
updates. Use batch Todoist operations where the tool supports them.
- Read back every created or changed task. Confirm its project and section,
content, managed Zotero line, managed Obsidian line, planned due date, and
deadlineDate.
- Return a compact receipt grouped as
created, reused, repaired, and
skipped. For each item, include the PaperRead note status (created,
reused, opt-out, or note-missing with the reason) and the read-back
managed Obsidian line when one exists. For skipped items, state whether the
cause was a missing PDF, ambiguous attachment, ambiguous task match, missing
target, or unavailable service.
If Zotero cannot be read, do not infer the collection contents or keys. If
Todoist is unavailable, report that no task change was persisted. Never use
conversation history as the task database.
1---2name: zotero-todoist-reading-tasks3description: Use when a user wants to create, schedule, reconcile, or repair Todoist reading tasks from saved Zotero items or collections, with default PaperRead note links.4---56# Zotero Todoist Reading Tasks78Turn a saved Zotero reading queue into one Todoist task per Zotero parent item.9Keep Zotero read-only and make each Todoist task a durable, directly linked10progress record.1112## Authority and tool routing1314- Inspect Zotero and Todoist before writing. Do not mutate Zotero.15- Treat an explicit request to create, schedule, reconcile, or repair reading16 tasks as authority only for the named Todoist project, collection, and tasks.17- A named Zotero item or collection request also authorizes at most one18 create-or-reuse action per uniquely resolved Zotero parent through19 `$paper-read-draft`. This bounded note authority is inherited from that named20 request; it does not authorize any other PaperRead note work.21- An explicit request for `without Obsidian notes` opts out of PaperRead work for22 that run. On opt-out, perform no PaperRead note operation and preserve any23 existing Obsidian line in a matched Todoist task.24- Require the exact task identity and an explicit deletion request before25 deleting anything. Do not infer cleanup authority from a reconciliation.26- Prefer the connected Todoist app when it is available. Use the official hosted27 Todoist MCP only as a fallback. Choose exactly one Todoist tool surface for the28 request, never both.29- Do not create a project, section, or label unless the user explicitly asks for30 that structure. Resolve existing targets before task changes.31- Route missing-paper imports, metadata repair, and attachment repair to32 `$paper-library-intake`; this workflow only reads Zotero.3334## Resolve the reading set35361. Identify the active Zotero library and resolve the requested collection by37 its full path and key. For a group library, obtain the numeric group ID from38 the live library listing; never guess it.392. Call `zotero_get_collection_items` for the resolved collection and retain40 top-level bibliographic items. Exclude child attachments, notes, and41 annotations as task candidates.423. Preserve the collection or user-provided order. When the user explicitly asks43 for a prerequisite-aware order, inspect saved titles and abstracts and rank44 foundational work before dependent systems or applications. State that this45 order is a recommendation.464. For two or more parents, call `zotero_get_items_children` once with all parent47 keys. Use the single-item child tool only for one parent.4849## Build Zotero desktop links5051Use the parent item key for selection and the PDF attachment key for opening a52PDF. Never pass a parent key to `open-pdf`.5354For the personal library:5556```text57zotero://select/library/items/<PARENT_KEY>58zotero://open-pdf/library/items/<ATTACHMENT_KEY>59```6061For a group library:6263```text64zotero://select/groups/<GROUP_ID>/items/<PARENT_KEY>65zotero://open-pdf/groups/<GROUP_ID>/items/<ATTACHMENT_KEY>66```6768When exactly one PDF child exists, use its PDF attachment key. When there is no69PDF child, create or repair only the `Show item` link and report that the PDF70link is unavailable. When there are multiple PDF children, use an authoritative71primary attachment only if Zotero exposes one; otherwise ask instead of guessing.7273Render a personal-library task line as:7475```markdown76Zotero: [Open PDF](zotero://open-pdf/library/items/<ATTACHMENT_KEY>) · [Show item](zotero://select/library/items/<PARENT_KEY>)77```7879For an item without a PDF, render:8081```markdown82Zotero: [Show item](zotero://select/library/items/<PARENT_KEY>)83```8485Substitute the group-library forms when applicable.8687## Create or reuse the PaperRead draft8889For each uniquely resolved parent, after Zotero identity resolution and before90any Todoist write, invoke `$paper-read-draft` exactly once per uniquely resolved91Zotero parent unless the user explicitly requested `without Obsidian notes`.92Pass only the resolved parent identity and observed metadata that the PaperRead93skill needs; it remains the sole owner of note identity, safe creation, and URI94generation. Complete this PaperRead action once per parent before that parent's95first Todoist write, then reuse the recorded result for all later writes.9697- Use only the URI returned by `$paper-read-draft` when its result is `created`98 or `reused`. Do not independently infer a note filename or URI.99- With a returned URI, the managed line is exactly:100101 ```markdown102 Obsidian: [Open PaperRead note](obsidian://open?vault=<ENCODED_VAULT>&file=<ENCODED_NOTE_PATH>)103 ```104105 Render the returned URI verbatim in that line; the placeholders illustrate106 only the encoded values already present in the returned URI. Do not construct107 a new URI.108- A canonical managed Obsidian line has this exact full-line grammar:109 `Obsidian: [Open PaperRead note](obsidian://open?vault=<ENCODED_VAULT>&file=<ENCODED_NOTE_PATH>)`.110 It has the exact label and prefix, and an `obsidian://open` target with111 exactly two non-empty query parameters in that order: `vault`, then `file`.112 It has no additional query parameters, no fragment, and no extra line text.113 This predicate is independent of a current PaperRead result. Do not require114 an existing canonical URI to equal a newly returned URI. Only this managed115 form is replaceable or removable. Preserve any other `Obsidian:` line or any116 other `obsidian://` content unchanged and report the task as ambiguous for117 manual review, including content with reversed query parameter order, an118 extra query parameter, a fragment, a different label, or another119 noncanonical form.120- Treat `link-unavailable`, `skipped`, an unavailable PaperRead call, or a121 missing returned URI as `note-missing`. Continue valid Todoist work without122 adding a stale Obsidian line, and record `note-missing` with the reason.123- On explicit opt-out, do not call `$paper-read-draft`, do not add, remove, or124 replace an Obsidian line, and do not report a note failure.125126## Reconcile task identity127128Search only the requested Todoist project or section before creating tasks.1291301. Match an existing task by its parent-key select URI first. This is the stable131 identity for one Todoist task per Zotero parent item.1322. For an older task without a Zotero URI, strip an optional `Read:` prefix and133 compare the normalized title with the Zotero title. Reuse it only for a134 unique one-to-one match.1353. Treat multiple task candidates or multiple Zotero title candidates as unsafe;136 stop on ambiguity and show the candidates.1374. If no match exists, create `Read: <paper title>` in the requested target.138139Maintain exactly one managed `Zotero:` line and, when PaperRead returned a URI,140exactly one managed `Obsidian:` line in the task description. On repair, replace141existing lines that begin with `Zotero:` and contain a `zotero://` URI. For an142authorized returned PaperRead URI, replace all canonical managed `Obsidian:`143lines with exactly one current managed line. For `note-missing`, remove all144canonical managed Obsidian lines so no stale link remains and preserve every145other description line unchanged and in order. If a `zotero://` or `obsidian://`146URI appears outside a managed line, do not duplicate or rewrite it; report the147task as ambiguous for manual review.148149Repeated runs are idempotent reconciliation, not continuous synchronization.150Never claim that later Zotero or Todoist changes will propagate automatically.151152## Schedule the reading153154- Treat the planned reading day as the Todoist due date and the final cutoff as155 `deadlineDate`. Never substitute one for the other.156- If the user supplies an inclusive date range but no daily allocation, preserve157 reading order and distribute tasks evenly across the available calendar days.158 Put any quotient remainder on earlier days to retain buffer before the final159 deadline. If fewer papers than days exist, use the earliest days.160- If only a final deadline is supplied, start the available range today in the161 Todoist account timezone. Honor any excluded weekdays or unavailable dates the162 user specifies.163- Use `dueString` when creating a task. Use `reschedule-tasks` when moving an164 existing task so recurring rules and time-of-day are preserved.165- A link-only repair must not change scheduling. Otherwise preserve existing166 titles, labels, priority, hierarchy, duration, due time, and deadline unless167 the user explicitly requests a change.168169## Apply and verify1701711. Preview the resolved Zotero parents, attachment choice, Todoist target,172 matches, planned dates, final deadline, planned PaperRead action or opt-out,173 and any ambiguity that blocks a write.1742. Before each parent's first Todoist write, complete the authorized PaperRead175 action once and record its `created`, `reused`, `link-unavailable`,176 `skipped`, or `note-missing` result. Reuse that recorded result for all177 later writes for the parent. Apply only the authorized Todoist creations or178 updates. Use batch Todoist operations where the tool supports them.1793. Read back every created or changed task. Confirm its project and section,180 content, managed Zotero line, managed Obsidian line, planned due date, and181 `deadlineDate`.1824. Return a compact receipt grouped as `created`, `reused`, `repaired`, and183 `skipped`. For each item, include the PaperRead note status (`created`,184 `reused`, `opt-out`, or `note-missing` with the reason) and the read-back185 managed Obsidian line when one exists. For skipped items, state whether the186 cause was a missing PDF, ambiguous attachment, ambiguous task match, missing187 target, or unavailable service.188189If Zotero cannot be read, do not infer the collection contents or keys. If190Todoist is unavailable, report that no task change was persisted. Never use191conversation history as the task database.