bibcite-cli 0.5.4__tar.gz → 0.6.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.
- bibcite_cli-0.6.0/.github/workflows/ci.yml +64 -0
- bibcite_cli-0.6.0/.github/workflows/publish.yml +74 -0
- bibcite_cli-0.6.0/PKG-INFO +213 -0
- bibcite_cli-0.6.0/Readme.md +200 -0
- bibcite_cli-0.6.0/assets/bibcite.svg +21 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/pyproject.toml +2 -1
- bibcite_cli-0.6.0/skills/bibcite/SKILL.md +80 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/src/bibcite/__init__.py +1 -1
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/src/bibcite/bibfile.py +4 -1
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/src/bibcite/cli.py +26 -8
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/src/bibcite/resolve.py +20 -9
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/src/bibcite/sources.py +23 -6
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/tests/test_bibfile.py +10 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/tests/test_bugfixes.py +13 -0
- bibcite_cli-0.6.0/tests/test_cli_status.py +124 -0
- bibcite_cli-0.6.0/tests/test_source_retries.py +143 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/uv.lock +31 -2
- bibcite_cli-0.5.4/PKG-INFO +0 -98
- bibcite_cli-0.5.4/Readme.md +0 -85
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/.gitignore +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/LICENSE +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/src/bibcite/cache.py +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/src/bibcite/data/strings.bib +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/src/bibcite/normalize.py +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/src/bibcite/venues.py +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/tests/test_entry_types.py +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/tests/test_normalize.py +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/tests/test_round2.py +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/tests/test_round3.py +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/tests/test_status_semantics.py +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/tests/test_strings_override.py +0 -0
- {bibcite_cli-0.5.4 → bibcite_cli-0.6.0}/tests/test_venues.py +0 -0
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
pull_request:
|
|
5
|
+
push:
|
|
6
|
+
branches:
|
|
7
|
+
- main
|
|
8
|
+
|
|
9
|
+
permissions:
|
|
10
|
+
contents: read
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
test:
|
|
14
|
+
name: Test on Python ${{ matrix.python-version }}
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
python-version:
|
|
20
|
+
- "3.10"
|
|
21
|
+
- "3.11"
|
|
22
|
+
- "3.12"
|
|
23
|
+
- "3.13"
|
|
24
|
+
- "3.14"
|
|
25
|
+
steps:
|
|
26
|
+
- name: Check out the repository
|
|
27
|
+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
28
|
+
|
|
29
|
+
- name: Install uv and Python
|
|
30
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
31
|
+
with:
|
|
32
|
+
python-version: ${{ matrix.python-version }}
|
|
33
|
+
enable-cache: true
|
|
34
|
+
|
|
35
|
+
- name: Install dependencies
|
|
36
|
+
run: uv sync --frozen --all-groups
|
|
37
|
+
|
|
38
|
+
- name: Run tests
|
|
39
|
+
run: uv run --frozen pytest -q
|
|
40
|
+
|
|
41
|
+
quality:
|
|
42
|
+
name: Lint and build
|
|
43
|
+
runs-on: ubuntu-latest
|
|
44
|
+
steps:
|
|
45
|
+
- name: Check out the repository
|
|
46
|
+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
47
|
+
|
|
48
|
+
- name: Install uv and Python
|
|
49
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
50
|
+
with:
|
|
51
|
+
python-version: "3.13"
|
|
52
|
+
enable-cache: true
|
|
53
|
+
|
|
54
|
+
- name: Install dependencies
|
|
55
|
+
run: uv sync --frozen --all-groups
|
|
56
|
+
|
|
57
|
+
- name: Run Ruff
|
|
58
|
+
run: uv run --frozen ruff check .
|
|
59
|
+
|
|
60
|
+
- name: Build distributions
|
|
61
|
+
run: uv build
|
|
62
|
+
|
|
63
|
+
- name: Smoke-test the wheel
|
|
64
|
+
run: uvx --from dist/*.whl bibcite --help
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
release:
|
|
5
|
+
types:
|
|
6
|
+
- published
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
build:
|
|
13
|
+
name: Build and verify distributions
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- name: Check out the release
|
|
17
|
+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
18
|
+
with:
|
|
19
|
+
ref: ${{ github.event.release.tag_name }}
|
|
20
|
+
|
|
21
|
+
- name: Install uv and Python
|
|
22
|
+
uses: astral-sh/setup-uv@08807647e7069bb48b6ef5acd8ec9567f424441b # v8.1.0
|
|
23
|
+
with:
|
|
24
|
+
python-version: "3.13"
|
|
25
|
+
|
|
26
|
+
- name: Verify the release tag matches the package version
|
|
27
|
+
run: |
|
|
28
|
+
package_version="$(uv version --short)"
|
|
29
|
+
if [ "${GITHUB_REF_NAME}" != "v${package_version}" ]; then
|
|
30
|
+
echo "Release tag ${GITHUB_REF_NAME} does not match package version ${package_version}."
|
|
31
|
+
exit 1
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
- name: Install dependencies
|
|
35
|
+
run: uv sync --frozen --all-groups
|
|
36
|
+
|
|
37
|
+
- name: Run tests
|
|
38
|
+
run: uv run --frozen pytest -q
|
|
39
|
+
|
|
40
|
+
- name: Run Ruff
|
|
41
|
+
run: uv run --frozen ruff check .
|
|
42
|
+
|
|
43
|
+
- name: Build distributions
|
|
44
|
+
run: uv build
|
|
45
|
+
|
|
46
|
+
- name: Smoke-test the wheel
|
|
47
|
+
run: uvx --from dist/*.whl bibcite --help
|
|
48
|
+
|
|
49
|
+
- name: Upload distributions
|
|
50
|
+
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
|
51
|
+
with:
|
|
52
|
+
name: python-package-distributions
|
|
53
|
+
path: dist/
|
|
54
|
+
if-no-files-found: error
|
|
55
|
+
|
|
56
|
+
publish:
|
|
57
|
+
name: Upload release to PyPI
|
|
58
|
+
needs: build
|
|
59
|
+
runs-on: ubuntu-latest
|
|
60
|
+
environment:
|
|
61
|
+
name: pypi
|
|
62
|
+
url: https://pypi.org/p/bibcite-cli
|
|
63
|
+
permissions:
|
|
64
|
+
contents: read
|
|
65
|
+
id-token: write
|
|
66
|
+
steps:
|
|
67
|
+
- name: Download distributions
|
|
68
|
+
uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7
|
|
69
|
+
with:
|
|
70
|
+
name: python-package-distributions
|
|
71
|
+
path: dist/
|
|
72
|
+
|
|
73
|
+
- name: Publish distributions to PyPI
|
|
74
|
+
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # v1.14.0
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bibcite-cli
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Resolve papers (arXiv id / DOI / title) to canonical, normalized BibTeX for agents and humans
|
|
5
|
+
Project-URL: Repository, https://github.com/leo1oel/bibcite
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: arxiv,bibliography,bibtex,citations,dblp
|
|
9
|
+
Requires-Python: >=3.10
|
|
10
|
+
Requires-Dist: bibtexparser<2,>=1.4
|
|
11
|
+
Requires-Dist: httpx>=0.27
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
<img src="assets/bibcite.svg" width="128" alt="bibcite logo">
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<h1 align="center">bibcite</h1>
|
|
19
|
+
|
|
20
|
+
<p align="center">
|
|
21
|
+
Turn an arXiv ID, DOI, or paper title into clean BibTeX, then keep the whole bibliography normalized and deduplicated.
|
|
22
|
+
</p>
|
|
23
|
+
|
|
24
|
+
<p align="center">
|
|
25
|
+
<a href="https://pypi.org/project/bibcite-cli/"><img alt="PyPI" src="https://img.shields.io/pypi/v/bibcite-cli?color=6366f1"></a>
|
|
26
|
+
<a href="https://pypi.org/project/bibcite-cli/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/bibcite-cli"></a>
|
|
27
|
+
<a href="LICENSE"><img alt="License" src="https://img.shields.io/github/license/leo1oel/bibcite"></a>
|
|
28
|
+
</p>
|
|
29
|
+
|
|
30
|
+
`bibcite` resolves a paper to its published record when one exists, preserves arXiv links, canonicalizes venue names, and writes the result into a `.bib` file without breaking existing citation keys.
|
|
31
|
+
It is built for both terminal use and coding agents that need a dependable alternative to editing BibTeX by hand.
|
|
32
|
+
|
|
33
|
+
## Quick start with an agent
|
|
34
|
+
|
|
35
|
+
Install the bundled skill so your coding agent knows how to manage citations with `bibcite`:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx -y skills add leo1oel/bibcite --skill bibcite --global --yes
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Install the CLI once as well, or let the agent install it on the first bibliography task:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
uv tool install bibcite-cli
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
You can then ask your agent to handle the bibliography in plain language:
|
|
48
|
+
|
|
49
|
+
```text
|
|
50
|
+
Add arXiv:1706.03762 to references.bib and cite it in main.tex.
|
|
51
|
+
Upgrade the arXiv entries in references.bib to their published versions.
|
|
52
|
+
Check and fix references.bib before submission.
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The skill tells the agent to call `bibcite` for every `.bib` change, read the citation key from its JSON output, and use that exact key in `\cite{...}`.
|
|
56
|
+
The agent never needs to guess a key or edit a BibTeX entry by hand.
|
|
57
|
+
|
|
58
|
+
## Use the CLI directly
|
|
59
|
+
|
|
60
|
+
Install the command from PyPI if you have not already done so:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv tool install bibcite-cli
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Resolve a paper and add it to your bibliography:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
bibcite add references.bib 1706.03762
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The command prints a machine-readable result, including the stable citation key:
|
|
73
|
+
|
|
74
|
+
```json
|
|
75
|
+
{
|
|
76
|
+
"query": "1706.03762",
|
|
77
|
+
"action": "added",
|
|
78
|
+
"key": "vaswani2017attention",
|
|
79
|
+
"title": "Attention is All you Need",
|
|
80
|
+
"venue": "Advances in Neural Information Processing Systems (NIPS)",
|
|
81
|
+
"published": true,
|
|
82
|
+
"source": "semanticscholar",
|
|
83
|
+
"file": "references.bib",
|
|
84
|
+
"tidied": true
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
You can now cite it as `\cite{vaswani2017attention}`.
|
|
89
|
+
Running the same command again is safe: `bibcite` detects the existing entry and does not add a duplicate.
|
|
90
|
+
|
|
91
|
+
When `add` writes a new entry, it runs [bibtex-tidy](https://github.com/FlamingTempura/bibtex-tidy) automatically unless you pass `--no-tidy`.
|
|
92
|
+
It uses a globally installed `bibtex-tidy` command when available and otherwise runs it through `npx --yes bibtex-tidy`.
|
|
93
|
+
`npx` downloads the formatter automatically on first use, so the agent-first setup does not require a separate `bibtex-tidy` installation.
|
|
94
|
+
The JSON result reports `"tidied": true` when formatting succeeds.
|
|
95
|
+
|
|
96
|
+
If neither `bibtex-tidy` nor `npx` is available, or if the formatter fails, the entry remains written but the command exits with code `1` and reports `"tidied": false`.
|
|
97
|
+
An `"action": "exists"` result also reports `"tidied": false` because no file change occurred, so `add` skips the formatting pass.
|
|
98
|
+
Run `bibcite tidy references.bib` or `bibcite fix references.bib` when you want to format an existing file.
|
|
99
|
+
|
|
100
|
+
You can also try a one-off command without installing `bibcite`:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
uvx --from bibcite-cli bibcite get "Attention is all you need"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## What it handles
|
|
107
|
+
|
|
108
|
+
- It accepts arXiv IDs and URLs, arXiv DOIs such as `10.48550/arXiv.1706.03762`, standard DOIs, and paper titles.
|
|
109
|
+
- It searches for a published version before falling back to an arXiv preprint, and it reports when source outages make that check incomplete.
|
|
110
|
+
- It canonicalizes journal, conference, and workshop names against the bundled venue table, including year-sensitive names such as NIPS and NeurIPS.
|
|
111
|
+
- It assigns the correct BibTeX entry type and field, such as `@inproceedings` with `booktitle` or `@article` with `journal`.
|
|
112
|
+
- It deduplicates by arXiv ID, DOI, exact title, and similar titles from the same first author.
|
|
113
|
+
- It upgrades preprints in place while preserving citation keys already used by your LaTeX source.
|
|
114
|
+
|
|
115
|
+
## Commands
|
|
116
|
+
|
|
117
|
+
| Command | Purpose |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| `bibcite get <query>` | Preview resolved BibTeX without writing a file. |
|
|
120
|
+
| `bibcite add <file> <query>` | Resolve, deduplicate, add, and tidy an entry. |
|
|
121
|
+
| `bibcite add <file> --bibtex "..."` | Normalize and add a raw BibTeX entry. |
|
|
122
|
+
| `bibcite add <file> --from ids.txt` | Add one query per line and tidy once at the end. |
|
|
123
|
+
| `bibcite upgrade <file>` | Replace arXiv entries with published records when available. |
|
|
124
|
+
| `bibcite check <file>` | Find missing fields, duplicates, preprints, and all-caps author names without changing the file. |
|
|
125
|
+
| `bibcite tidy <file>` | Apply the canonical `bibtex-tidy` formatting rules. |
|
|
126
|
+
| `bibcite fix <file>` | Upgrade preprints, tidy the file, and run the checks in one command. |
|
|
127
|
+
| `bibcite remove <file> <key>` | Remove an entry by citation key. |
|
|
128
|
+
|
|
129
|
+
### Common workflows
|
|
130
|
+
|
|
131
|
+
Preview a result as BibTeX or JSON:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
bibcite get 1706.03762
|
|
135
|
+
bibcite get 10.1109/CVPR52688.2022.01167 --json
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Add raw BibTeX from the clipboard:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
pbpaste | bibcite add references.bib --bibtex -
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
Replace a bad entry while keeping its current key:
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
bibcite add references.bib "correct paper title" --key existingKey
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
Check what would be upgraded without writing the file:
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
bibcite upgrade references.bib --dry-run
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
Mark a confirmed preprint-only entry with `pubstate = {preprint}` if you want `check` and `upgrade` to leave it alone.
|
|
157
|
+
|
|
158
|
+
## How resolution works
|
|
159
|
+
|
|
160
|
+
For arXiv IDs and titles, `bibcite` collects paper metadata and checks publication sources in a cascade derived from [PaperMemory](https://github.com/vict0rsch/PaperMemory): DBLP, Semantic Scholar, Google Scholar, Crossref, Unpaywall, and OpenAlex.
|
|
161
|
+
A published match must have the same normalized title or pass a guarded title-drift check, have a plausible publication year, and name a non-preprint venue.
|
|
162
|
+
|
|
163
|
+
Successful published matches are cached at `~/.cache/bibcite/published.json`.
|
|
164
|
+
Preprint-only results are never cached because a paper may be published later.
|
|
165
|
+
Use `--no-cache` or set `BIBCITE_NO_CACHE=1` to bypass the cache.
|
|
166
|
+
|
|
167
|
+
## Configuration
|
|
168
|
+
|
|
169
|
+
Set `BIBCITE_STRINGS=/path/to/strings.bib` to use your own venue table, or place one at `~/.config/bibcite/strings.bib`.
|
|
170
|
+
|
|
171
|
+
These optional environment variables improve source reliability:
|
|
172
|
+
|
|
173
|
+
| Variable | Effect |
|
|
174
|
+
| --- | --- |
|
|
175
|
+
| `OPENALEX_API_KEY` | Uses your OpenAlex quota instead of the anonymous shared pool. |
|
|
176
|
+
| `S2_API_KEY` | Uses a private Semantic Scholar quota. |
|
|
177
|
+
| `BIBCITE_MAILTO` | Sends your contact email to the Crossref, OpenAlex, and Unpaywall polite pools. |
|
|
178
|
+
| `BIBCITE_CORE_SOURCES` | Overrides the sources required for a trustworthy publication check. |
|
|
179
|
+
| `BIBCITE_NO_CACHE=1` | Disables the local publication cache. |
|
|
180
|
+
|
|
181
|
+
## Exit codes and agent use
|
|
182
|
+
|
|
183
|
+
`add`, `remove`, `upgrade`, `check`, and `fix` print JSON on standard output and send diagnostics to standard error.
|
|
184
|
+
This keeps their output easy to parse from scripts and agents.
|
|
185
|
+
|
|
186
|
+
| Code | Meaning |
|
|
187
|
+
| --- | --- |
|
|
188
|
+
| `0` | The command completed successfully. |
|
|
189
|
+
| `1` | A file, lint, or formatting problem remains. |
|
|
190
|
+
| `2` | The paper or requested entry could not be found. |
|
|
191
|
+
| `3` | Publication sources or an internal tool failed. |
|
|
192
|
+
|
|
193
|
+
Agents should call `bibcite add <file> <query>` and use the returned `key` in `\cite{...}`.
|
|
194
|
+
They should never modify `.bib` entries directly because doing so bypasses deduplication, venue normalization, and stable-key handling.
|
|
195
|
+
|
|
196
|
+
## Development
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
git clone https://github.com/leo1oel/bibcite.git
|
|
200
|
+
cd bibcite
|
|
201
|
+
uv sync --all-groups
|
|
202
|
+
uv run pytest
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
Install the checkout as an editable command while developing:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
uv tool install --editable .
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## License
|
|
212
|
+
|
|
213
|
+
`bibcite` is available under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/bibcite.svg" width="128" alt="bibcite logo">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">bibcite</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
Turn an arXiv ID, DOI, or paper title into clean BibTeX, then keep the whole bibliography normalized and deduplicated.
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<a href="https://pypi.org/project/bibcite-cli/"><img alt="PyPI" src="https://img.shields.io/pypi/v/bibcite-cli?color=6366f1"></a>
|
|
13
|
+
<a href="https://pypi.org/project/bibcite-cli/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/bibcite-cli"></a>
|
|
14
|
+
<a href="LICENSE"><img alt="License" src="https://img.shields.io/github/license/leo1oel/bibcite"></a>
|
|
15
|
+
</p>
|
|
16
|
+
|
|
17
|
+
`bibcite` resolves a paper to its published record when one exists, preserves arXiv links, canonicalizes venue names, and writes the result into a `.bib` file without breaking existing citation keys.
|
|
18
|
+
It is built for both terminal use and coding agents that need a dependable alternative to editing BibTeX by hand.
|
|
19
|
+
|
|
20
|
+
## Quick start with an agent
|
|
21
|
+
|
|
22
|
+
Install the bundled skill so your coding agent knows how to manage citations with `bibcite`:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npx -y skills add leo1oel/bibcite --skill bibcite --global --yes
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Install the CLI once as well, or let the agent install it on the first bibliography task:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
uv tool install bibcite-cli
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
You can then ask your agent to handle the bibliography in plain language:
|
|
35
|
+
|
|
36
|
+
```text
|
|
37
|
+
Add arXiv:1706.03762 to references.bib and cite it in main.tex.
|
|
38
|
+
Upgrade the arXiv entries in references.bib to their published versions.
|
|
39
|
+
Check and fix references.bib before submission.
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The skill tells the agent to call `bibcite` for every `.bib` change, read the citation key from its JSON output, and use that exact key in `\cite{...}`.
|
|
43
|
+
The agent never needs to guess a key or edit a BibTeX entry by hand.
|
|
44
|
+
|
|
45
|
+
## Use the CLI directly
|
|
46
|
+
|
|
47
|
+
Install the command from PyPI if you have not already done so:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
uv tool install bibcite-cli
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Resolve a paper and add it to your bibliography:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
bibcite add references.bib 1706.03762
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
The command prints a machine-readable result, including the stable citation key:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"query": "1706.03762",
|
|
64
|
+
"action": "added",
|
|
65
|
+
"key": "vaswani2017attention",
|
|
66
|
+
"title": "Attention is All you Need",
|
|
67
|
+
"venue": "Advances in Neural Information Processing Systems (NIPS)",
|
|
68
|
+
"published": true,
|
|
69
|
+
"source": "semanticscholar",
|
|
70
|
+
"file": "references.bib",
|
|
71
|
+
"tidied": true
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
You can now cite it as `\cite{vaswani2017attention}`.
|
|
76
|
+
Running the same command again is safe: `bibcite` detects the existing entry and does not add a duplicate.
|
|
77
|
+
|
|
78
|
+
When `add` writes a new entry, it runs [bibtex-tidy](https://github.com/FlamingTempura/bibtex-tidy) automatically unless you pass `--no-tidy`.
|
|
79
|
+
It uses a globally installed `bibtex-tidy` command when available and otherwise runs it through `npx --yes bibtex-tidy`.
|
|
80
|
+
`npx` downloads the formatter automatically on first use, so the agent-first setup does not require a separate `bibtex-tidy` installation.
|
|
81
|
+
The JSON result reports `"tidied": true` when formatting succeeds.
|
|
82
|
+
|
|
83
|
+
If neither `bibtex-tidy` nor `npx` is available, or if the formatter fails, the entry remains written but the command exits with code `1` and reports `"tidied": false`.
|
|
84
|
+
An `"action": "exists"` result also reports `"tidied": false` because no file change occurred, so `add` skips the formatting pass.
|
|
85
|
+
Run `bibcite tidy references.bib` or `bibcite fix references.bib` when you want to format an existing file.
|
|
86
|
+
|
|
87
|
+
You can also try a one-off command without installing `bibcite`:
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
uvx --from bibcite-cli bibcite get "Attention is all you need"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## What it handles
|
|
94
|
+
|
|
95
|
+
- It accepts arXiv IDs and URLs, arXiv DOIs such as `10.48550/arXiv.1706.03762`, standard DOIs, and paper titles.
|
|
96
|
+
- It searches for a published version before falling back to an arXiv preprint, and it reports when source outages make that check incomplete.
|
|
97
|
+
- It canonicalizes journal, conference, and workshop names against the bundled venue table, including year-sensitive names such as NIPS and NeurIPS.
|
|
98
|
+
- It assigns the correct BibTeX entry type and field, such as `@inproceedings` with `booktitle` or `@article` with `journal`.
|
|
99
|
+
- It deduplicates by arXiv ID, DOI, exact title, and similar titles from the same first author.
|
|
100
|
+
- It upgrades preprints in place while preserving citation keys already used by your LaTeX source.
|
|
101
|
+
|
|
102
|
+
## Commands
|
|
103
|
+
|
|
104
|
+
| Command | Purpose |
|
|
105
|
+
| --- | --- |
|
|
106
|
+
| `bibcite get <query>` | Preview resolved BibTeX without writing a file. |
|
|
107
|
+
| `bibcite add <file> <query>` | Resolve, deduplicate, add, and tidy an entry. |
|
|
108
|
+
| `bibcite add <file> --bibtex "..."` | Normalize and add a raw BibTeX entry. |
|
|
109
|
+
| `bibcite add <file> --from ids.txt` | Add one query per line and tidy once at the end. |
|
|
110
|
+
| `bibcite upgrade <file>` | Replace arXiv entries with published records when available. |
|
|
111
|
+
| `bibcite check <file>` | Find missing fields, duplicates, preprints, and all-caps author names without changing the file. |
|
|
112
|
+
| `bibcite tidy <file>` | Apply the canonical `bibtex-tidy` formatting rules. |
|
|
113
|
+
| `bibcite fix <file>` | Upgrade preprints, tidy the file, and run the checks in one command. |
|
|
114
|
+
| `bibcite remove <file> <key>` | Remove an entry by citation key. |
|
|
115
|
+
|
|
116
|
+
### Common workflows
|
|
117
|
+
|
|
118
|
+
Preview a result as BibTeX or JSON:
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
bibcite get 1706.03762
|
|
122
|
+
bibcite get 10.1109/CVPR52688.2022.01167 --json
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Add raw BibTeX from the clipboard:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pbpaste | bibcite add references.bib --bibtex -
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Replace a bad entry while keeping its current key:
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
bibcite add references.bib "correct paper title" --key existingKey
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Check what would be upgraded without writing the file:
|
|
138
|
+
|
|
139
|
+
```bash
|
|
140
|
+
bibcite upgrade references.bib --dry-run
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Mark a confirmed preprint-only entry with `pubstate = {preprint}` if you want `check` and `upgrade` to leave it alone.
|
|
144
|
+
|
|
145
|
+
## How resolution works
|
|
146
|
+
|
|
147
|
+
For arXiv IDs and titles, `bibcite` collects paper metadata and checks publication sources in a cascade derived from [PaperMemory](https://github.com/vict0rsch/PaperMemory): DBLP, Semantic Scholar, Google Scholar, Crossref, Unpaywall, and OpenAlex.
|
|
148
|
+
A published match must have the same normalized title or pass a guarded title-drift check, have a plausible publication year, and name a non-preprint venue.
|
|
149
|
+
|
|
150
|
+
Successful published matches are cached at `~/.cache/bibcite/published.json`.
|
|
151
|
+
Preprint-only results are never cached because a paper may be published later.
|
|
152
|
+
Use `--no-cache` or set `BIBCITE_NO_CACHE=1` to bypass the cache.
|
|
153
|
+
|
|
154
|
+
## Configuration
|
|
155
|
+
|
|
156
|
+
Set `BIBCITE_STRINGS=/path/to/strings.bib` to use your own venue table, or place one at `~/.config/bibcite/strings.bib`.
|
|
157
|
+
|
|
158
|
+
These optional environment variables improve source reliability:
|
|
159
|
+
|
|
160
|
+
| Variable | Effect |
|
|
161
|
+
| --- | --- |
|
|
162
|
+
| `OPENALEX_API_KEY` | Uses your OpenAlex quota instead of the anonymous shared pool. |
|
|
163
|
+
| `S2_API_KEY` | Uses a private Semantic Scholar quota. |
|
|
164
|
+
| `BIBCITE_MAILTO` | Sends your contact email to the Crossref, OpenAlex, and Unpaywall polite pools. |
|
|
165
|
+
| `BIBCITE_CORE_SOURCES` | Overrides the sources required for a trustworthy publication check. |
|
|
166
|
+
| `BIBCITE_NO_CACHE=1` | Disables the local publication cache. |
|
|
167
|
+
|
|
168
|
+
## Exit codes and agent use
|
|
169
|
+
|
|
170
|
+
`add`, `remove`, `upgrade`, `check`, and `fix` print JSON on standard output and send diagnostics to standard error.
|
|
171
|
+
This keeps their output easy to parse from scripts and agents.
|
|
172
|
+
|
|
173
|
+
| Code | Meaning |
|
|
174
|
+
| --- | --- |
|
|
175
|
+
| `0` | The command completed successfully. |
|
|
176
|
+
| `1` | A file, lint, or formatting problem remains. |
|
|
177
|
+
| `2` | The paper or requested entry could not be found. |
|
|
178
|
+
| `3` | Publication sources or an internal tool failed. |
|
|
179
|
+
|
|
180
|
+
Agents should call `bibcite add <file> <query>` and use the returned `key` in `\cite{...}`.
|
|
181
|
+
They should never modify `.bib` entries directly because doing so bypasses deduplication, venue normalization, and stable-key handling.
|
|
182
|
+
|
|
183
|
+
## Development
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
git clone https://github.com/leo1oel/bibcite.git
|
|
187
|
+
cd bibcite
|
|
188
|
+
uv sync --all-groups
|
|
189
|
+
uv run pytest
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Install the checkout as an editable command while developing:
|
|
193
|
+
|
|
194
|
+
```bash
|
|
195
|
+
uv tool install --editable .
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
`bibcite` is available under the [MIT License](LICENSE).
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" role="img" aria-labelledby="title description">
|
|
2
|
+
<title id="title">bibcite logo</title>
|
|
3
|
+
<desc id="description">A paper with citation marks and a verification check.</desc>
|
|
4
|
+
<defs>
|
|
5
|
+
<linearGradient id="background" x1="32" y1="24" x2="224" y2="232" gradientUnits="userSpaceOnUse">
|
|
6
|
+
<stop stop-color="#6366F1"/>
|
|
7
|
+
<stop offset="1" stop-color="#7C3AED"/>
|
|
8
|
+
</linearGradient>
|
|
9
|
+
<filter id="shadow" x="-20%" y="-20%" width="140%" height="150%">
|
|
10
|
+
<feDropShadow dx="0" dy="8" stdDeviation="8" flood-color="#312E81" flood-opacity="0.28"/>
|
|
11
|
+
</filter>
|
|
12
|
+
</defs>
|
|
13
|
+
<rect width="256" height="256" rx="56" fill="url(#background)"/>
|
|
14
|
+
<path d="M67 48h89l37 37v116c0 9.4-7.6 17-17 17H67c-9.4 0-17-7.6-17-17V65c0-9.4 7.6-17 17-17Z" fill="#FFFFFF" filter="url(#shadow)"/>
|
|
15
|
+
<path d="M156 48v28c0 9.4 7.6 17 17 17h20" fill="#E0E7FF"/>
|
|
16
|
+
<path d="m156 48 37 37h-28c-5 0-9-4-9-9V48Z" fill="#C7D2FE"/>
|
|
17
|
+
<path d="M81 112c-8 4-12 11-12 22v18h22v-20H80c0-5 3-9 9-12l-8-8Zm40 0c-8 4-12 11-12 22v18h22v-20h-11c0-5 3-9 9-12l-8-8Z" fill="#6366F1"/>
|
|
18
|
+
<rect x="70" y="172" width="69" height="10" rx="5" fill="#CBD5E1"/>
|
|
19
|
+
<circle cx="181" cy="184" r="35" fill="#14B8A6" stroke="#FFFFFF" stroke-width="8"/>
|
|
20
|
+
<path d="m165 184 11 11 22-25" fill="none" stroke="#FFFFFF" stroke-width="9" stroke-linecap="round" stroke-linejoin="round"/>
|
|
21
|
+
</svg>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "bibcite-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.6.0"
|
|
4
4
|
description = "Resolve papers (arXiv id / DOI / title) to canonical, normalized BibTeX for agents and humans"
|
|
5
5
|
readme = "Readme.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -20,6 +20,7 @@ bibcite = "bibcite.cli:main"
|
|
|
20
20
|
[dependency-groups]
|
|
21
21
|
dev = [
|
|
22
22
|
"pytest>=8",
|
|
23
|
+
"ruff>=0.15,<0.16",
|
|
23
24
|
]
|
|
24
25
|
|
|
25
26
|
[build-system]
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bibcite
|
|
3
|
+
description: Manage paper citations and .bib files through the bibcite CLI instead of hand-editing them. Use whenever a task involves adding a paper reference or \cite, resolving an arXiv ID, arXiv DOI, DOI, or title to BibTeX, cleaning or checking a bibliography, deduplicating entries, or upgrading arXiv preprints to published records.
|
|
4
|
+
compatibility: Requires bibcite or uv, network access for paper resolution, and Node.js with npx for automatic formatting.
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# bibcite
|
|
8
|
+
|
|
9
|
+
Route every `.bib` change through `bibcite` because the CLI resolves metadata, canonicalizes venues, deduplicates entries, preserves existing citation keys, and formats the file.
|
|
10
|
+
Never add, replace, or delete a `.bib` entry by editing the file directly.
|
|
11
|
+
|
|
12
|
+
If `bibcite` is not on `PATH`, install it with `uv tool install bibcite-cli`, then use the commands below.
|
|
13
|
+
|
|
14
|
+
## Choose the command
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
bibcite add refs.bib <arXiv ID | arXiv URL | arXiv DOI | DOI | title>
|
|
18
|
+
bibcite add refs.bib --bibtex '<complete BibTeX entry>'
|
|
19
|
+
bibcite add refs.bib --from queries.txt
|
|
20
|
+
bibcite add refs.bib <query> --replace
|
|
21
|
+
bibcite add refs.bib <query> --key existingKey
|
|
22
|
+
bibcite remove refs.bib <key>
|
|
23
|
+
bibcite get <query> [--json]
|
|
24
|
+
bibcite upgrade refs.bib [--dry-run]
|
|
25
|
+
bibcite check refs.bib
|
|
26
|
+
bibcite tidy refs.bib
|
|
27
|
+
bibcite fix refs.bib
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Use `get` only to preview a paper without changing a bibliography.
|
|
31
|
+
Use `add` for one paper, and pass an arXiv ID, an arXiv DOI such as `10.48550/arXiv.1706.03762`, a standard DOI, or an exact title.
|
|
32
|
+
Use `--from` for multiple papers because one process shares source throttling state and tidies the file once.
|
|
33
|
+
Use `--replace` only when the resolved paper should overwrite an automatically matched entry.
|
|
34
|
+
Use `--key` when title drift prevents automatic matching and a specific existing citation key must be replaced.
|
|
35
|
+
Use `upgrade --dry-run` before upgrading a large bibliography.
|
|
36
|
+
Use `fix` when the user asks to clean up a bibliography end to end.
|
|
37
|
+
|
|
38
|
+
## Use the returned citation key
|
|
39
|
+
|
|
40
|
+
File-changing commands print a JSON result on standard output and diagnostics on standard error.
|
|
41
|
+
Read the `key` from JSON after `add` and use that exact value in `\cite{...}` instead of guessing or reconstructing it.
|
|
42
|
+
After a write, confirm that `tidied` is `true` before reporting that formatting completed.
|
|
43
|
+
An `exists` result may have `tidied` set to `false` because the file was unchanged, so `add` skipped the formatting pass.
|
|
44
|
+
For any other `tidied: false` result, expect exit code `1` and retry once with `bibcite tidy <file>`.
|
|
45
|
+
`bibcite` downloads `bibtex-tidy` through `npx`, so do not install it separately.
|
|
46
|
+
If Node.js or `npx` is missing, ask before installing it and never format the file by hand.
|
|
47
|
+
|
|
48
|
+
Treat these `action` values as successful outcomes:
|
|
49
|
+
|
|
50
|
+
- `added` means a new entry was written.
|
|
51
|
+
- `exists` means the paper was already present and no duplicate was added.
|
|
52
|
+
- `upgraded` means a preprint was replaced by its published record while keeping the existing key.
|
|
53
|
+
- `replaced` means an explicitly targeted entry was overwritten while keeping its existing key.
|
|
54
|
+
|
|
55
|
+
For batch commands, inspect every item in `results` because one failed query does not invalidate successful entries.
|
|
56
|
+
|
|
57
|
+
## Handle publication uncertainty
|
|
58
|
+
|
|
59
|
+
An unmatched upgrade reports either `no_published_version` or `sources_unavailable`.
|
|
60
|
+
Treat `no_published_version` as a trustworthy miss.
|
|
61
|
+
Treat `sources_unavailable` as temporary because rate limits or outages prevented a complete check, so retry later without writing a replacement by hand.
|
|
62
|
+
|
|
63
|
+
A preprint result may include `published_check`.
|
|
64
|
+
Treat `complete` as a trustworthy publication check and `incomplete` as a reason to retry later.
|
|
65
|
+
|
|
66
|
+
An entry that is intentionally preprint-only can use `pubstate = {preprint}` to mute future `check` and `upgrade` warnings.
|
|
67
|
+
Submit the complete updated entry through `--bibtex` and target its existing key rather than editing the file directly.
|
|
68
|
+
|
|
69
|
+
## Handle exit codes
|
|
70
|
+
|
|
71
|
+
- Exit code `0` means the command completed successfully.
|
|
72
|
+
- Exit code `1` means a file, lint, or formatting problem remains.
|
|
73
|
+
Inspect `problems`, `remaining_problems`, and `tidied` before deciding what to do next.
|
|
74
|
+
- Exit code `2` means the paper or requested entry was not found.
|
|
75
|
+
Ask for a stronger identifier, preferably an arXiv ID or DOI, instead of fabricating an entry.
|
|
76
|
+
- Exit code `3` means publication sources or an internal tool failed.
|
|
77
|
+
Retry later and never fall back to hand-editing the bibliography.
|
|
78
|
+
|
|
79
|
+
`check` is read-only, but it returns exit code `1` when it finds problems.
|
|
80
|
+
`fix` also returns exit code `1` when unresolved lint issues remain or formatting fails.
|