Skip to content

Commit a575d79

Browse files
committed
Update docs
1 parent b0c7d95 commit a575d79

5 files changed

Lines changed: 168 additions & 40 deletions

File tree

AGENTS.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ The skill's tools live under `skills/bibtidy/tools/` in this repo. At runtime, d
3333
- Run `./tests/run_bibtidy_codex_tests.sh` for the Codex end-to-end path
3434
- Unit tests only: `uv run pytest tests/`
3535

36+
## Previewing README
37+
38+
Preview `README.md` (including Mermaid charts) locally with `gh markdown-preview README.md` (requires the `gh-markdown-preview` extension).
39+
3640
## Website (docs/)
3741

3842
`docs/index.html` is generated by `docs/build.py`. Never edit `index.html` directly. Make changes in `build.py`, then run `python docs/build.py` to regenerate.

README.md

Lines changed: 22 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -55,49 +55,46 @@ Start a new Codex session afterwards so the refreshed `SKILL.md` is loaded into
5555

5656
## bibtidy
5757

58+
In both Claude Code and Codex, use:
59+
5860
```text
59-
Use bibtidy to validate and fix refs.bib
61+
/bibtidy refs.bib
6062
```
6163

62-
Or in Claude Code, use the slash command: `/bibtidy refs.bib`
63-
6464
bibtidy verifies each entry against [Google Scholar](https://scholar.google.com/) and [CrossRef](https://search.crossref.org/), fixes errors, and upgrades stale preprints to published versions. Every change includes the original entry commented out above so you can compare or revert, plus one or more `% bibtidy:` URL lines for verification. We recommend using git to track changes. If using [Overleaf](https://www.overleaf.com/), this can be done with [git sync](https://docs.overleaf.com/integrations-and-add-ons/git-integration-and-github-synchronization). To remove bibtidy comments after review, ask your agent to remove all `bibtidy` comments from the file.
6565

66-
bibtidy's output is non-deterministic: the same `.bib` file can yield different fixes across runs, and Claude Code and Codex may reach different conclusions on the same entry. See the [FAQ](#bibtidy) for why, and always verify changes via the `% bibtidy:` URLs before accepting them.
66+
bibtidy's output is non-deterministic: the same `.bib` file can yield different fixes across runs, and Claude Code and Codex may reach different conclusions on the same entry. See the FAQ section below for more on why, and always verify changes via the `% bibtidy:` URLs before accepting them.
6767

6868
Note that bibtidy assumes standard brace-style BibTeX like `@article{...}`. Parenthesized forms like `@article(...)` are not supported. Special blocks such as `@string`, `@preamble`, and `@comment` are ignored by the parser.
6969

7070
### How it works
7171

72-
bibtidy walks each entry through a bounded state machine. Every entry has a **web-search budget of 1**, spent at most once across two possible waves:
72+
Each entry goes through the following pipeline. A web search is used at most once per entry to keep runs fast. Each entry ends in one of four states: Clean (no change, no comment), Fix (patch applied with URLs + explanation), Not found (hallucinated, entry commented out), or Review (budget spent, entry unchanged, comment added for human attention).
7373

7474
```mermaid
75-
flowchart TD
76-
P1["Phase 1: duplicates.py (exact/subset, lossless)"]
77-
P2["Phase 2: compare.py fetches CrossRef candidates"]
78-
HAS{"candidates?"}
79-
WA["Wave A web search<br/>(mandatory, budget spent)"]
80-
P3{"Phase 3: agent decides per entry"}
81-
BUDGET{"budget spent?"}
82-
WB["Wave B web search<br/>(budget spent)"]
83-
DECIDE2["decide again with combined info"]
84-
REVIEW["add '% bibtidy: REVIEW' comment<br/>with URLs, bib entry unchanged"]
85-
PATCH["build fix patch (or no-op)"]
86-
P4["Phase 4: duplicates.py (post-fix)<br/>+ manual near-duplicate review"]
75+
flowchart LR
76+
P1["Deduplicate"]
77+
P2["Query CrossRef"]
78+
HAS{"Found?"}
79+
WA["Web search"]
80+
P3{"Confident?"}
81+
BUDGET{"Web searched?"}
82+
WB["Web search"]
83+
PATCH["Patch or no-op"]
84+
REVIEW["Flag for review"]
85+
P4["Post-fix deduplicate"]
8786
8887
P1 --> P2 --> HAS
89-
HAS -- yes --> P3
90-
HAS -- no --> WA --> P3
91-
P3 -- confident --> PATCH
92-
P3 -- not confident --> BUDGET
93-
BUDGET -- no --> WB --> DECIDE2 --> PATCH
94-
BUDGET -- yes --> REVIEW
88+
HAS -- Y --> P3
89+
HAS -- N --> WA --> P3
90+
P3 -- Y --> PATCH
91+
P3 -- N --> BUDGET
92+
BUDGET -- N --> WB --> PATCH
93+
BUDGET -- Y --> REVIEW
9594
PATCH --> P4
9695
REVIEW --> P4
9796
```
9897

99-
Each entry ends in one of four states: **Clean** (no change, no comment), **Fix** (patch applied with URLs + explanation), **Not found** (hallucinated, entry commented out), or **Review** (budget spent, entry unchanged, comment added for human attention).
100-
10198
### Examples
10299

103100
<details>

docs/build.py

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -287,13 +287,12 @@ def build_html(cards_html: str) -> str:
287287
}}
288288
289289
.header {{
290-
border-bottom: 1px solid var(--border);
291-
padding: 2rem 0;
290+
padding: 2rem 0 0.5rem;
292291
text-align: center;
293292
}}
294293
295294
.header h1 {{ font-size: 2rem; font-weight: 600; margin-bottom: 0.5rem; }}
296-
.header p {{ color: var(--text-muted); font-size: 1.1rem; }}
295+
.header p {{ color: var(--text-muted); }}
297296
298297
.github-link {{
299298
display: inline-flex;
@@ -455,6 +454,43 @@ def build_html(cards_html: str) -> str:
455454
.stats .del-count {{ color: var(--del-line); }}
456455
457456
.diff-body a {{ color: var(--accent); }}
457+
458+
/* Tabs */
459+
.tabs {{
460+
display: flex;
461+
border-bottom: 1px solid var(--border);
462+
margin-bottom: 2rem;
463+
}}
464+
465+
.tab-btn {{
466+
background: none;
467+
border: none;
468+
border-bottom: 2px solid transparent;
469+
padding: 0.6rem 1.25rem;
470+
font-family: inherit;
471+
font-size: 0.95rem;
472+
font-weight: 500;
473+
color: var(--text-muted);
474+
cursor: pointer;
475+
transition: color 0.15s, border-color 0.15s;
476+
}}
477+
478+
.tab-btn:hover {{
479+
color: var(--text);
480+
}}
481+
482+
.tab-btn.active {{
483+
color: var(--accent);
484+
border-bottom-color: var(--accent);
485+
}}
486+
487+
.tab-panel {{
488+
display: none;
489+
}}
490+
491+
.tab-panel.active {{
492+
display: block;
493+
}}
458494
</style>
459495
</head>
460496
<body>
@@ -471,16 +507,21 @@ def build_html(cards_html: str) -> str:
471507
</div>
472508
473509
<div class="container">
474-
<p class="intro">bibtidy cross-checks BibTeX entries against Google Scholar, CrossRef, and conference/journal sites. It upgrades arXiv/bioRxiv preprints to published versions (even when the title changed upon publication), corrects metadata (authors, pages, venues), and flags duplicate entries.</p>
475510
476-
<p class="intro"><strong>Note:</strong> bibtidy's output is non-deterministic. The same <code>.bib</code> file can yield different fixes across runs, and Claude Code and Codex may reach different conclusions on the same entry, due to variability in search results, LLM sampling, and differences between the two agents' underlying models. Every change ships with <code>% bibtidy:</code> URLs for verification &mdash; treat the output as a reviewed first draft, not a final answer.</p>
511+
<div class="tabs">
512+
<button class="tab-btn active" data-tab="bibtidy" onclick="switchTab('bibtidy')">bibtidy</button>
513+
</div>
514+
515+
<div id="tab-bibtidy" class="tab-panel active">
477516
478517
<div class="section">
479518
<div class="demo">
480519
<img src="bibtidy_demo.gif" alt="bibtidy demo" width="1600" height="1200">
481520
</div>
482521
</div>
483522
523+
<p class="intro">bibtidy cross-checks BibTeX entries against Google Scholar, CrossRef, and conference/journal sites. It upgrades arXiv/bioRxiv preprints to published versions (even when the title changed upon publication), corrects metadata (authors, pages, venues), and flags duplicate entries.</p>
524+
484525
<div class="section">
485526
<h2 class="section-title">Install</h2>
486527
@@ -521,6 +562,18 @@ def build_html(cards_html: str) -> str:
521562
522563
</div>
523564
565+
<div class="section">
566+
<h2 class="section-title">Usage</h2>
567+
568+
<div class="install-step">
569+
<p>In both Claude Code and Codex, use:</p>
570+
<div class="code-block"><code>/bibtidy refs.bib</code><button class="copy-btn" type="button" onclick="copyCode(this)">Copy</button></div>
571+
</div>
572+
573+
<p class="intro">bibtidy's output is non-deterministic. The same <code>.bib</code> file can yield different fixes across runs, and Claude Code and Codex may reach different conclusions on the same entry, due to variability in search results, LLM sampling, and differences between the two agents' underlying models. Every change ships with <code>% bibtidy:</code> URLs for verification &mdash; treat the output as a reviewed first draft, not a final answer.</p>
574+
575+
</div>
576+
524577
<div class="section">
525578
<h2 class="section-title">Examples</h2>
526579
@@ -530,7 +583,16 @@ def build_html(cards_html: str) -> str:
530583
531584
</div>
532585
586+
</div>
587+
533588
<script>
589+
function switchTab(id) {{
590+
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
591+
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
592+
document.querySelector('.tab-btn[data-tab="' + id + '"]').classList.add('active');
593+
document.getElementById('tab-' + id).classList.add('active');
594+
}}
595+
534596
function copyCode(btn) {{
535597
const code = btn.previousElementSibling.textContent;
536598
navigator.clipboard.writeText(code).then(() => {{
@@ -554,11 +616,7 @@ def main() -> None:
554616

555617
input_entries = {e["key"]: e for e in parse_entries(input_text)}
556618
expected_entries = parse_entries(expected_text)
557-
558-
# Build a lookup for expected entries
559-
expected_by_key = {}
560-
for e in expected_entries:
561-
expected_by_key[e["key"]] = e
619+
expected_by_key = {e["key"]: e for e in expected_entries}
562620

563621
# Generate diff cards, separating by category
564622
notfound_cards = []

docs/index.html

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,13 +82,12 @@
8282
}
8383

8484
.header {
85-
border-bottom: 1px solid var(--border);
86-
padding: 2rem 0;
85+
padding: 2rem 0 0.5rem;
8786
text-align: center;
8887
}
8988

9089
.header h1 { font-size: 2rem; font-weight: 600; margin-bottom: 0.5rem; }
91-
.header p { color: var(--text-muted); font-size: 1.1rem; }
90+
.header p { color: var(--text-muted); }
9291

9392
.github-link {
9493
display: inline-flex;
@@ -250,6 +249,43 @@
250249
.stats .del-count { color: var(--del-line); }
251250

252251
.diff-body a { color: var(--accent); }
252+
253+
/* Tabs */
254+
.tabs {
255+
display: flex;
256+
border-bottom: 1px solid var(--border);
257+
margin-bottom: 2rem;
258+
}
259+
260+
.tab-btn {
261+
background: none;
262+
border: none;
263+
border-bottom: 2px solid transparent;
264+
padding: 0.6rem 1.25rem;
265+
font-family: inherit;
266+
font-size: 0.95rem;
267+
font-weight: 500;
268+
color: var(--text-muted);
269+
cursor: pointer;
270+
transition: color 0.15s, border-color 0.15s;
271+
}
272+
273+
.tab-btn:hover {
274+
color: var(--text);
275+
}
276+
277+
.tab-btn.active {
278+
color: var(--accent);
279+
border-bottom-color: var(--accent);
280+
}
281+
282+
.tab-panel {
283+
display: none;
284+
}
285+
286+
.tab-panel.active {
287+
display: block;
288+
}
253289
</style>
254290
</head>
255291
<body>
@@ -266,16 +302,21 @@ <h1>bibtools</h1>
266302
</div>
267303

268304
<div class="container">
269-
<p class="intro">bibtidy cross-checks BibTeX entries against Google Scholar, CrossRef, and conference/journal sites. It upgrades arXiv/bioRxiv preprints to published versions (even when the title changed upon publication), corrects metadata (authors, pages, venues), and flags duplicate entries.</p>
270305

271-
<p class="intro"><strong>Note:</strong> bibtidy's output is non-deterministic. The same <code>.bib</code> file can yield different fixes across runs, and Claude Code and Codex may reach different conclusions on the same entry, due to variability in search results, LLM sampling, and differences between the two agents' underlying models. Every change ships with <code>% bibtidy:</code> URLs for verification &mdash; treat the output as a reviewed first draft, not a final answer.</p>
306+
<div class="tabs">
307+
<button class="tab-btn active" data-tab="bibtidy" onclick="switchTab('bibtidy')">bibtidy</button>
308+
</div>
309+
310+
<div id="tab-bibtidy" class="tab-panel active">
272311

273312
<div class="section">
274313
<div class="demo">
275314
<img src="bibtidy_demo.gif" alt="bibtidy demo" width="1600" height="1200">
276315
</div>
277316
</div>
278317

318+
<p class="intro">bibtidy cross-checks BibTeX entries against Google Scholar, CrossRef, and conference/journal sites. It upgrades arXiv/bioRxiv preprints to published versions (even when the title changed upon publication), corrects metadata (authors, pages, venues), and flags duplicate entries.</p>
319+
279320
<div class="section">
280321
<h2 class="section-title">Install</h2>
281322

@@ -316,6 +357,18 @@ <h3 style="font-size: 1rem; font-weight: 600; margin: 1.5rem 0 0.75rem;">Codex</
316357

317358
</div>
318359

360+
<div class="section">
361+
<h2 class="section-title">Usage</h2>
362+
363+
<div class="install-step">
364+
<p>In both Claude Code and Codex, use:</p>
365+
<div class="code-block"><code>/bibtidy refs.bib</code><button class="copy-btn" type="button" onclick="copyCode(this)">Copy</button></div>
366+
</div>
367+
368+
<p class="intro">bibtidy's output is non-deterministic. The same <code>.bib</code> file can yield different fixes across runs, and Claude Code and Codex may reach different conclusions on the same entry, due to variability in search results, LLM sampling, and differences between the two agents' underlying models. Every change ships with <code>% bibtidy:</code> URLs for verification &mdash; treat the output as a reviewed first draft, not a final answer.</p>
369+
370+
</div>
371+
319372
<div class="section">
320373
<h2 class="section-title">Examples</h2>
321374

@@ -607,7 +660,16 @@ <h2 class="section-title">Examples</h2>
607660

608661
</div>
609662

663+
</div>
664+
610665
<script>
666+
function switchTab(id) {
667+
document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
668+
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
669+
document.querySelector('.tab-btn[data-tab="' + id + '"]').classList.add('active');
670+
document.getElementById('tab-' + id).classList.add('active');
671+
}
672+
611673
function copyCode(btn) {
612674
const code = btn.previousElementSibling.textContent;
613675
navigator.clipboard.writeText(code).then(() => {

tests/test_docs_build.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
assert _SPEC is not None and _SPEC.loader is not None
1111
_MODULE = module_from_spec(_SPEC)
1212
_SPEC.loader.exec_module(_MODULE)
13+
build_html = _MODULE.build_html
1314
linkify = _MODULE.linkify
1415

1516

@@ -23,3 +24,9 @@ def test_linkify_escapes_non_url_text() -> None:
2324
result = linkify('5 < 6 and "ok" https://example.com?a=1&b=2')
2425
assert "5 &lt; 6 and &quot;ok&quot;" in result
2526
assert 'href="https://example.com?a=1&amp;b=2"' in result
27+
28+
29+
def test_build_html_includes_shared_usage_example() -> None:
30+
result = build_html("")
31+
assert "<p>In both Claude Code and Codex, use:</p>" in result
32+
assert "<code>/bibtidy refs.bib</code>" in result

0 commit comments

Comments
 (0)