zotrm 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,58 @@
1
+ name: Bug report
2
+ description: Something isn't working as expected
3
+ labels: ["bug"]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: Thanks for taking the time to file a bug! Please remove any secrets (like your Zotero API key) from logs.
8
+ - type: textarea
9
+ id: what-happened
10
+ attributes:
11
+ label: What happened?
12
+ description: What did you do, and what went wrong?
13
+ placeholder: I ran `zotrm pull` and ...
14
+ validations:
15
+ required: true
16
+ - type: textarea
17
+ id: expected
18
+ attributes:
19
+ label: What did you expect to happen?
20
+ validations:
21
+ required: true
22
+ - type: textarea
23
+ id: repro
24
+ attributes:
25
+ label: Steps to reproduce
26
+ placeholder: |
27
+ 1. Run `zotrm ...`
28
+ 2. ...
29
+ validations:
30
+ required: true
31
+ - type: textarea
32
+ id: logs
33
+ attributes:
34
+ label: Output / logs
35
+ description: Paste the command output. Run with `--dry-run` if helpful. Remove your API key.
36
+ render: shell
37
+ - type: input
38
+ id: version
39
+ attributes:
40
+ label: zotrm version
41
+ description: Output of `zotrm --help` header or the installed version.
42
+ placeholder: "0.1.0"
43
+ validations:
44
+ required: true
45
+ - type: dropdown
46
+ id: os
47
+ attributes:
48
+ label: Operating system
49
+ options:
50
+ - macOS
51
+ - Linux
52
+ validations:
53
+ required: true
54
+ - type: input
55
+ id: rmapi
56
+ attributes:
57
+ label: rmapi version
58
+ description: Output of `rmapi version` (if relevant).
@@ -0,0 +1,5 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Question or usage help
4
+ url: https://github.com/dipta007/zotRm/discussions
5
+ about: Ask questions and share setups in Discussions instead of opening an issue.
@@ -0,0 +1,23 @@
1
+ name: Feature request
2
+ description: Suggest an idea or improvement
3
+ labels: ["enhancement"]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: What problem would this solve?
9
+ description: Describe the use case or pain point. "I'm always frustrated when ..."
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: Proposed solution
16
+ description: What would you like zotrm to do?
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: alternatives
21
+ attributes:
22
+ label: Alternatives considered
23
+ description: Any workarounds or other approaches you've thought about.
@@ -0,0 +1,15 @@
1
+ <!-- Thanks for contributing to zotrm! -->
2
+
3
+ ## What does this change?
4
+
5
+ <!-- A short summary of the change and why it's needed. Link any related issue. -->
6
+
7
+ Closes #
8
+
9
+ ## Checklist
10
+
11
+ - [ ] Tests added or updated for the change
12
+ - [ ] `uv run pytest` passes (100% coverage gate)
13
+ - [ ] `uv run ruff check .` and `uv run ruff format --check .` are clean
14
+ - [ ] `uv run mypy src` passes
15
+ - [ ] Docs updated if behavior changed (README / advanced-usage / CHANGELOG)
@@ -0,0 +1,38 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ checks:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ python-version: ["3.11", "3.12", "3.13"]
15
+
16
+ steps:
17
+ - uses: actions/checkout@v4
18
+
19
+ - name: Install uv
20
+ uses: astral-sh/setup-uv@v6
21
+ with:
22
+ enable-cache: true
23
+ python-version: ${{ matrix.python-version }}
24
+
25
+ - name: Install dependencies
26
+ run: uv sync --locked
27
+
28
+ - name: Lint (ruff)
29
+ run: uv run ruff check .
30
+
31
+ - name: Format check (ruff)
32
+ run: uv run ruff format --check .
33
+
34
+ - name: Type check (mypy)
35
+ run: uv run mypy src
36
+
37
+ - name: Tests + 100% coverage gate
38
+ run: uv run pytest
@@ -0,0 +1,40 @@
1
+ name: Release
2
+
3
+ # Publishes to PyPI when a version tag (e.g. v0.1.0) is pushed.
4
+ #
5
+ # Uses PyPI "trusted publishing" (OIDC) — no API token needed. One-time setup on PyPI:
6
+ # PyPI → your project → Settings → Publishing → Add a trusted publisher
7
+ # Owner: dipta007 | Repo: zotRm | Workflow: release.yml | Environment: pypi
8
+ # Then create a `pypi` environment in the repo settings.
9
+
10
+ on:
11
+ push:
12
+ tags: ["v*"]
13
+
14
+ jobs:
15
+ release:
16
+ runs-on: ubuntu-latest
17
+ environment: pypi
18
+ permissions:
19
+ id-token: write # required for trusted publishing
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Install uv
24
+ uses: astral-sh/setup-uv@v6
25
+ with:
26
+ enable-cache: true
27
+
28
+ - name: Verify the package before publishing
29
+ run: |
30
+ uv sync --locked
31
+ uv run ruff check .
32
+ uv run ruff format --check .
33
+ uv run mypy src
34
+ uv run pytest
35
+
36
+ - name: Build
37
+ run: uv build
38
+
39
+ - name: Publish to PyPI
40
+ uses: pypa/gh-action-pypi-publish@release/v1
zotrm-0.1.0/.gitignore ADDED
@@ -0,0 +1,22 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.egg-info/
5
+ .eggs/
6
+
7
+ # Build artifacts
8
+ dist/
9
+ build/
10
+
11
+ # uv / virtualenv
12
+ .venv/
13
+
14
+ # Caches
15
+ .mypy_cache/
16
+ .ruff_cache/
17
+ .pytest_cache/
18
+
19
+ # Coverage
20
+ .coverage
21
+ htmlcov/
22
+ coverage.xml
@@ -0,0 +1 @@
1
+ 3.11
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format is based on
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## [0.1.0] - 2026-06-23
10
+
11
+ ### Added
12
+
13
+ - `push`, `pull`, `status`, and `sync` commands to move PDFs between a Zotero collection
14
+ and a reMarkable Paper Pro, tracking state with Zotero tags (`rm:synced`,
15
+ `rm:annotated`).
16
+ - Sub-collection mirroring: Zotero sub-collections become nested folders on the tablet.
17
+ - `zotrm config` — interactive setup wizard with a live Zotero check and an `rmapi`
18
+ presence check; runs automatically on first use.
19
+ - `zotrm cron` — schedule an automatic sync (with `--remove` / `--show`).
20
+ - `--config` and `--dry-run` global flags.
21
+ - Full type hints (`mypy --strict`), `ruff` lint/format, and a test suite at 100%
22
+ coverage.
23
+
24
+ [Unreleased]: https://github.com/dipta007/zotRm/compare/v0.1.0...HEAD
25
+ [0.1.0]: https://github.com/dipta007/zotRm/releases/tag/v0.1.0
@@ -0,0 +1,55 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ We as members, contributors, and leaders pledge to make participation in our community a
6
+ harassment-free experience for everyone, regardless of age, body size, visible or invisible
7
+ disability, ethnicity, sex characteristics, gender identity and expression, level of
8
+ experience, education, socio-economic status, nationality, personal appearance, race,
9
+ religion, or sexual identity and orientation.
10
+
11
+ We pledge to act and interact in ways that contribute to an open, welcoming, diverse,
12
+ inclusive, and healthy community.
13
+
14
+ ## Our Standards
15
+
16
+ Examples of behavior that contributes to a positive environment include:
17
+
18
+ - Demonstrating empathy and kindness toward other people
19
+ - Being respectful of differing opinions, viewpoints, and experiences
20
+ - Giving and gracefully accepting constructive feedback
21
+ - Accepting responsibility and apologizing to those affected by our mistakes
22
+ - Focusing on what is best for the overall community
23
+
24
+ Examples of unacceptable behavior include:
25
+
26
+ - The use of sexualized language or imagery, and sexual attention or advances of any kind
27
+ - Trolling, insulting or derogatory comments, and personal or political attacks
28
+ - Public or private harassment
29
+ - Publishing others' private information without their explicit permission
30
+ - Other conduct which could reasonably be considered inappropriate in a professional setting
31
+
32
+ ## Enforcement Responsibilities
33
+
34
+ Community leaders are responsible for clarifying and enforcing our standards and will take
35
+ appropriate and fair corrective action in response to any behavior that they deem
36
+ inappropriate, threatening, offensive, or harmful.
37
+
38
+ ## Scope
39
+
40
+ This Code of Conduct applies within all community spaces, and also applies when an
41
+ individual is officially representing the community in public spaces.
42
+
43
+ ## Enforcement
44
+
45
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the
46
+ maintainer via <https://roydipta.com>. All complaints will be reviewed and investigated
47
+ promptly and fairly. Community leaders are obligated to respect the privacy and security of
48
+ the reporter of any incident.
49
+
50
+ ## Attribution
51
+
52
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1,
53
+ available at <https://www.contributor-covenant.org/version/2/1/code_of_conduct.html>.
54
+
55
+ [homepage]: https://www.contributor-covenant.org
@@ -0,0 +1,64 @@
1
+ # Contributing to zotrm
2
+
3
+ Thanks for your interest in improving zotrm! This project uses
4
+ [uv](https://docs.astral.sh/uv/) for everything.
5
+
6
+ ## Set up for development
7
+
8
+ ```sh
9
+ git clone https://github.com/dipta007/zotRm
10
+ cd zotrm
11
+ uv sync # creates .venv and installs deps + dev tools
12
+ uv pip install -e . # editable install, so `zotrm` reflects your edits
13
+ ```
14
+
15
+ ## Project layout
16
+
17
+ ```
18
+ src/zotrm/
19
+ cli.py # argparse, main(), command dispatch
20
+ config.py # config loading/validation + shared helpers
21
+ zotero.py # pyzotero wrapper: collection walk, tag helpers
22
+ remarkable.py # rmapi subprocess wrapper
23
+ wizard.py # interactive `zotrm config` setup wizard
24
+ cron.py # `zotrm cron` schedule builder + crontab management
25
+ __main__.py # enables `python -m zotrm`
26
+ tests/ # pytest suite (pyzotero + rmapi + questionary are mocked)
27
+ ```
28
+
29
+ ## Run the checks
30
+
31
+ All four must pass before a change is ready:
32
+
33
+ ```sh
34
+ uv run pytest # tests + 100% coverage gate
35
+ uv run ruff check . # lint
36
+ uv run ruff format . # format (use --check in CI)
37
+ uv run mypy src # type-check (strict)
38
+ ```
39
+
40
+ GitHub Actions runs these same four gates on every push and pull request, across
41
+ Python 3.11–3.13 (see [`.github/workflows/ci.yml`](.github/workflows/ci.yml)). The test
42
+ step enforces 100% coverage, so a change that drops coverage fails CI.
43
+
44
+ ## Code style
45
+
46
+ - **Formatting & linting:** `ruff`, line length 100. Run `ruff format` before committing.
47
+ - **Types:** full type hints; `mypy --strict` must pass on `src`. The live `pyzotero`
48
+ client is typed as `Any` (it ships no stubs); helpers pin down the slices we use.
49
+ - **Tests:** external systems are never hit. `pyzotero.Zotero`, the `rmapi`/`crontab`
50
+ subprocesses, and `questionary` prompts are all replaced with fakes (see
51
+ `tests/conftest.py`). Favor meaningful coverage over a coverage number.
52
+ - **Keep changes surgical.** Match the surrounding style; don't refactor unrelated code.
53
+
54
+ ## Making a change
55
+
56
+ 1. Branch off `main`.
57
+ 2. Add or update tests alongside your change.
58
+ 3. Make sure all four checks above are green.
59
+ 4. Open a pull request describing what changed and why.
60
+
61
+ ## Releasing
62
+
63
+ See [docs/advanced-usage.md](docs/advanced-usage.md#publishing-to-pypi-for-maintainers)
64
+ for how to publish a new version to PyPI.
zotrm-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Shubhashis Roy Dipta
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
zotrm-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,251 @@
1
+ Metadata-Version: 2.4
2
+ Name: zotrm
3
+ Version: 0.1.0
4
+ Summary: Bridge a Zotero collection to a reMarkable Paper Pro: push PDFs, pull annotations.
5
+ Project-URL: Homepage, https://roydipta.com
6
+ Project-URL: Repository, https://github.com/dipta007/zotRm
7
+ Author: Shubhashis Roy Dipta
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Keywords: annotations,pdf,remarkable,rmapi,zotero
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: End Users/Desktop
14
+ Classifier: Intended Audience :: Science/Research
15
+ Classifier: Operating System :: MacOS
16
+ Classifier: Operating System :: POSIX :: Linux
17
+ Classifier: Programming Language :: Python :: 3
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Programming Language :: Python :: 3.13
21
+ Classifier: Topic :: Scientific/Engineering
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.11
24
+ Requires-Dist: pyzotero>=1.5
25
+ Requires-Dist: questionary>=2.0
26
+ Description-Content-Type: text/markdown
27
+
28
+ # zotrm
29
+
30
+ [![CI](https://github.com/dipta007/zotRm/actions/workflows/ci.yml/badge.svg)](https://github.com/dipta007/zotRm/actions/workflows/ci.yml)
31
+ [![PyPI](https://img.shields.io/pypi/v/zotrm.svg)](https://pypi.org/project/zotrm/)
32
+ [![Python](https://img.shields.io/pypi/pyversions/zotrm.svg)](https://pypi.org/project/zotrm/)
33
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://github.com/dipta007/zotRm/blob/main/LICENSE)
34
+
35
+ Read your Zotero papers on a **reMarkable Paper Pro**, then get your handwritten
36
+ notes back into Zotero — with one command.
37
+
38
+ ## Demo
39
+
40
+ ![zotrm in action: push papers, annotate on the tablet, pull them back](https://raw.githubusercontent.com/dipta007/zotRm/main/docs/demo.gif)
41
+
42
+ > _Recording the GIF: see [how to record the demo](https://github.com/dipta007/zotRm/blob/main/docs/advanced-usage.md#recording-the-demo-gif)._
43
+
44
+ **What it does, in plain words:**
45
+
46
+ - **push** — sends the PDFs from one Zotero collection to your reMarkable tablet.
47
+ - **pull** — brings the marked-up PDFs back and attaches them to the same Zotero papers.
48
+ - **status** — shows which papers are waiting, on the tablet, or already done.
49
+ - **sync** — does a pull and then a push, together.
50
+
51
+ You never push or pull the same paper twice by mistake — the tool remembers what it has
52
+ done. It is safe to run again and again.
53
+
54
+ > **One honest limit (this is reMarkable's behavior, not a bug here):**
55
+ > Your highlights and handwriting come back as part of the PDF image — "painted onto"
56
+ > the page. They do **not** come back as clickable Zotero highlights.
57
+
58
+ ## Why zotrm?
59
+
60
+ If you read research papers on a reMarkable, getting them on and off the tablet is fiddly:
61
+ export each PDF, drag it into the reMarkable app, and later dig the annotated copy back
62
+ out and re-file it in Zotero. zotrm makes that **one command in each direction**, driven by
63
+ the collection you already curate in Zotero:
64
+
65
+ - **No manual file shuffling** — it reads your Zotero collection and uploads the PDFs for you.
66
+ - **Folders match your library** — Zotero sub-collections become nested folders on the tablet.
67
+ - **Nothing pushed or pulled twice** — progress is tracked with Zotero tags, so it's safe to
68
+ re-run or schedule with `zotrm cron`.
69
+ - **No extra database or account** — just your Zotero API key and the `rmapi` tool.
70
+
71
+ It's a small, focused CLI — not a sync daemon or a cloud service.
72
+
73
+ ---
74
+
75
+ ## Before you start (what you need)
76
+
77
+ 1. A **Zotero** account with some PDFs in it.
78
+ 2. A **reMarkable** tablet, turned on and connected to WiFi.
79
+ 3. A **reMarkable Connect** subscription — this is what lets files move to and from the
80
+ tablet over the internet. Without it, push and pull may not work.
81
+ 4. A computer (Mac or Linux) where you can open a **Terminal** (a window where you type
82
+ commands). On a Mac, open the app called **Terminal**.
83
+
84
+ You will copy and paste a few commands. That is all.
85
+
86
+ ---
87
+
88
+ ## Setup (about 10 minutes)
89
+
90
+ ### Step 1 — Install `uv`
91
+
92
+ `uv` installs this tool for you. Paste this into the Terminal and press Enter:
93
+
94
+ ```sh
95
+ curl -LsSf https://astral.sh/uv/install.sh | sh
96
+ ```
97
+
98
+ Close the Terminal and open it again so the change takes effect.
99
+
100
+ ### Step 2 — Install `rmapi` and connect it to your tablet
101
+
102
+ `rmapi` is a separate program that talks to your reMarkable:
103
+
104
+ ```sh
105
+ brew install rmapi
106
+ ```
107
+
108
+ (No Homebrew? See <https://github.com/ddvk/rmapi> for other ways. Use the **ddvk**
109
+ version — the original does not work with new tablets.)
110
+
111
+ Now connect it to your tablet **one time**:
112
+
113
+ ```sh
114
+ rmapi
115
+ ```
116
+
117
+ It shows a web address and asks for a code. Open
118
+ <https://my.remarkable.com/device/desktop>, copy the code shown there, and paste it into
119
+ the Terminal. Done — you won't do this again.
120
+
121
+ ### Step 3 — Install `zotrm`
122
+
123
+ ```sh
124
+ uv tool install zotrm
125
+ ```
126
+
127
+ ### Step 4 — Set up your account (answer a few questions)
128
+
129
+ Just run:
130
+
131
+ ```sh
132
+ zotrm config
133
+ ```
134
+
135
+ It asks you a few simple questions (use the arrow keys and Enter), then checks that your
136
+ details work. To answer the two Zotero questions:
137
+
138
+ - Open <https://www.zotero.org/settings/keys>.
139
+ - Your **library ID** is the number shown as "Your userID".
140
+ - Click **Create new private key**, allow read **and write**, and copy the key it gives
141
+ you.
142
+
143
+ > **Tip:** In Zotero, make a collection (for example named `reMarkable`) and drag the
144
+ > papers you want to read into it. Give that same name when the wizard asks for the
145
+ > collection.
146
+
147
+ That's it — your settings are saved automatically. (The very first time you run any
148
+ command, this wizard starts on its own if you haven't set up yet.)
149
+
150
+ ### Step 5 — Use it
151
+
152
+ Send your papers to the tablet:
153
+
154
+ ```sh
155
+ zotrm push
156
+ ```
157
+
158
+ Read and annotate them on the reMarkable. When you're done, bring them back:
159
+
160
+ ```sh
161
+ zotrm pull
162
+ ```
163
+
164
+ That's the whole loop. 🎉
165
+
166
+ ### Step 6 (optional) — Make it automatic
167
+
168
+ Want it to sync by itself on a schedule? Run:
169
+
170
+ ```sh
171
+ zotrm cron
172
+ ```
173
+
174
+ Pick how often (every hour, daily, etc.) and it sets everything up for you. Remove it
175
+ later with `zotrm cron --remove`.
176
+
177
+ ---
178
+
179
+ ## Everyday commands
180
+
181
+ ```sh
182
+ zotrm push # send waiting papers to the tablet
183
+ zotrm pull # bring marked-up papers back into Zotero
184
+ zotrm status # see what is waiting / on the tablet / done
185
+ zotrm sync # pull, then push, in one step
186
+
187
+ zotrm config # change your settings any time
188
+ zotrm cron # set up (or change) automatic syncing
189
+ ```
190
+
191
+ Not sure what a command will do? Add `--dry-run` to see without changing anything:
192
+
193
+ ```sh
194
+ zotrm --dry-run push
195
+ ```
196
+
197
+ ---
198
+
199
+ ## If something goes wrong
200
+
201
+ - **"rmapi not found"** → Step 2 was missed, or reopen the Terminal.
202
+ - **"config not found"** → Run `zotrm config` to set up your account.
203
+ - **"no Zotero collection named ..."** → The collection name in your settings doesn't
204
+ exactly match a collection in Zotero. Check spelling and capital letters
205
+ (`zotrm config --show` prints your current settings).
206
+ - **Pull finds nothing** → Make sure the tablet is online and finished syncing, and that
207
+ you have a reMarkable Connect subscription.
208
+
209
+ Run any command with `--dry-run` first if you're unsure — it changes nothing.
210
+
211
+ ---
212
+
213
+ ## FAQ
214
+
215
+ **Do I need a reMarkable Connect subscription?**
216
+ Yes, in practice. `zotrm` talks to the reMarkable **cloud** through `rmapi`, and two-way
217
+ document sync (uploading PDFs and downloading annotated ones) needs Connect.
218
+
219
+ **Why don't my highlights come back as real Zotero highlights?**
220
+ The reMarkable returns a flattened PDF — your marks are baked into the page image. That's a
221
+ reMarkable limitation, not something `zotrm` can change. You get a faithful annotated PDF
222
+ re-attached to the item, just not editable highlight objects.
223
+
224
+ **Does it duplicate files if I run it again?**
225
+ No. It tags items `rm:synced` once pushed and `rm:annotated` once pulled back, and skips
226
+ anything already done. Re-run it (or schedule it) freely.
227
+
228
+ **Can I use it with more than one Zotero library?**
229
+ Yes — keep separate config files and pass `--config`. See
230
+ [advanced usage](https://github.com/dipta007/zotRm/blob/main/docs/advanced-usage.md#global-flags).
231
+
232
+ **Does it work on Windows?**
233
+ Not currently. `zotrm` targets macOS and Linux (the `cron` scheduler is Unix-only).
234
+
235
+ **Is my Zotero API key safe?**
236
+ It's stored only in your local config file (`~/.config/zotrm/config.ini`) and never sent
237
+ anywhere except Zotero's own API. `zotrm config --show` masks it.
238
+
239
+ ---
240
+
241
+ ## More
242
+
243
+ - **[Advanced usage](https://github.com/dipta007/zotRm/blob/main/docs/advanced-usage.md)** —
244
+ editing the config file by hand, the full settings reference, how the scheduled sync
245
+ works, multiple configs, and deeper troubleshooting.
246
+ - **[Contributing](https://github.com/dipta007/zotRm/blob/main/CONTRIBUTING.md)** — set up
247
+ the project for development and run the tests.
248
+
249
+ ## License
250
+
251
+ MIT — see [LICENSE](https://github.com/dipta007/zotRm/blob/main/LICENSE).