renkin 1.0.5 → 1.0.7

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.
Files changed (3) hide show
  1. package/README.md +96 -771
  2. package/package.json +1 -1
  3. package/renkin_bg.wasm +0 -0
package/README.md CHANGED
@@ -1,67 +1,45 @@
1
- # RENKIN — Retrosynthesis Engine for Knowledge-Informed Navigation
1
+ # RENKIN
2
2
 
3
- > **Computer-Aided Synthesis Planning (CASP) · Pure Rust · WebAssembly · Python**
4
- > Named after 錬金 (れんきん, *renkin*) — Japanese for alchemy: just as alchemists transformed base metals into gold, RENKIN transforms target molecules back into cheap starting materials.
3
+ Retrosynthesis planning and route auditing in Rust.
5
4
 
6
- <p>
7
- <a href="https://github.com/kent-tokyo/renkin/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/kent-tokyo/renkin/actions/workflows/ci.yml/badge.svg?branch=master"></a>
8
- <a href="https://github.com/kent-tokyo/renkin/actions/workflows/docs.yml"><img alt="Docs" src="https://github.com/kent-tokyo/renkin/actions/workflows/docs.yml/badge.svg?branch=master"></a>
9
- </p>
5
+ [![CI](https://github.com/kent-tokyo/renkin/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/kent-tokyo/renkin/actions/workflows/ci.yml)
6
+ [![Crates.io](https://img.shields.io/crates/v/renkin.svg)](https://crates.io/crates/renkin)
7
+ [![PyPI](https://img.shields.io/pypi/v/renkin.svg)](https://pypi.org/project/renkin/)
8
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
10
9
 
11
- <p>
12
- <a href="https://crates.io/crates/renkin"><img alt="Crates.io" src="https://img.shields.io/crates/v/renkin.svg"></a>
13
- <a href="https://docs.rs/renkin"><img alt="docs.rs" src="https://docs.rs/renkin/badge.svg"></a>
14
- <a href="https://pypi.org/project/renkin/"><img alt="PyPI" src="https://img.shields.io/pypi/v/renkin.svg"></a>
15
- <a href="https://pypi.org/project/renkin/"><img alt="Python" src="https://img.shields.io/pypi/pyversions/renkin.svg"></a>
16
- <a href="https://www.npmjs.com/package/renkin"><img alt="npm" src="https://img.shields.io/npm/v/renkin.svg"></a>
17
- <a href="LICENSE"><img alt="License: MIT" src="https://img.shields.io/badge/license-MIT-blue.svg"></a>
18
- </p>
10
+ [Documentation](https://kent-tokyo.github.io/renkin/) · [Playground](https://kent-tokyo.github.io/renkin/playground/) · [日本語版](README_ja.md) · [中文](README_zh.md)
19
11
 
20
- [日本語版 README](./README_ja.md) · [中文版 README](./README_zh.md) · [**Documentation**](https://kent-tokyo.github.io/renkin/) · [**Live Demo →**](https://kent-tokyo.github.io/renkin/playground/)
12
+ RENKIN has two uses:
21
13
 
22
- ---
14
+ - **Planner:** search retrosynthetic routes from a target molecule to building blocks.
15
+ - **Bridge:** audit routes from RENKIN, AiZynthFinder, Syntheseus, or SynPlanner.
23
16
 
24
- **Keep your planner. Audit every route.** Audit retrosynthesis routes from AiZynthFinder, Syntheseus, SynPlanner, or RENKIN — locally, reproducibly, and without sending molecular structures anywhere.
17
+ Auditing is local and reproducible. Reports include structural checks, stock
18
+ coverage, forward replay, provenance, and a verifiable audit manifest.
25
19
 
26
- [**Audit a route in your browser →**](https://kent-tokyo.github.io/renkin/playground/) · [**Python quick start ↓**](#audit-a-route) · [**Route planning engine ↓**](#quick-start)
20
+ Current release: **v1.0.7**. Public inputs are validated before execution;
21
+ WASM applies bounded search limits, and MCP numeric and element-filter
22
+ arguments fail closed when invalid. Standard MCP search also accepts an
23
+ optional cooperative `timeout_secs` budget.
27
24
 
28
- ---
25
+ The audit and private-stock policy layers are split into deterministic,
26
+ testable steps so their report schema and policy behavior remain stable.
29
27
 
30
- ## What is RENKIN?
31
-
32
- RENKIN Bridge is a tool-neutral **route auditor**: it checks structural integrity, stock coverage, and declared-reaction forward-replay for routes from **AiZynthFinder**, **Syntheseus**, **SynPlanner**, or RENKIN's own planner — the identical `pass`/`fail`/`partial` pipeline regardless of which tool produced the route, entirely local and reproducible (every audit records a verifiable [`audit_manifest`](https://kent-tokyo.github.io/renkin/guides/audit-reproducibility-contract/)), structures never leaving your machine unless you explicitly ask.
33
-
34
- RENKIN is also, in its own right, an open-source **retrosynthesis engine** for **computer-aided synthesis planning (CASP)** that automatically discovers chemical reaction routes from a target molecule back to cheap, commercially available starting materials.
35
-
36
- Built entirely in Rust with the [`chematic`](https://docs.rs/chematic/) cheminformatics crate — zero C/C++ dependencies, `#![forbid(unsafe_code)]` throughout. One codebase compiles to a native CLI, a Rust library, Python wheels (PyO3), and a WebAssembly module that runs entirely client-side in the browser.
37
-
38
- ---
39
-
40
- ## Installation
28
+ ## Install
41
29
 
42
30
  ```bash
43
- pip install renkin # Python
44
- cargo add renkin # Rust
45
- npm install renkin # JavaScript (browser / bundler -- see docs/api/wasm.md)
31
+ pip install renkin
32
+ cargo add renkin
33
+ npm install renkin
46
34
  ```
47
35
 
48
- Auditing Syntheseus routes needs one more, optional package:
49
- `pip install renkin[syntheseus]` (verified against Syntheseus `0.7.2` and
50
- `0.8.0`).
51
-
52
- ---
53
-
54
- ## Live Playground
55
-
56
- **[→ Try it now](https://kent-tokyo.github.io/renkin/playground/)** — runs entirely in WebAssembly: no installation, no server, no network calls.
36
+ For Syntheseus support:
57
37
 
58
- ---
59
-
60
- ## Audit a Route
61
-
62
- Bring a route from wherever you already plan them — every path below runs through the identical audit pipeline: the same `pass`/`fail`/`partial` verdict regardless of source tool, or whether you ran it from the CLI, Python, or a browser tab.
38
+ ```bash
39
+ pip install 'renkin[syntheseus]'
40
+ ```
63
41
 
64
- **AiZynthFinder**
42
+ ## Audit a route
65
43
 
66
44
  ```python
67
45
  import json
@@ -73,768 +51,115 @@ report = json.loads(
73
51
  print(report["summary"])
74
52
  ```
75
53
 
76
- For an evidence-boundary report, add `--chemical-review` to
77
- `renkin audit-route ... --output json`. The optional report is deterministic;
78
- missing conditions, selectivity, and substrate-scope evidence remain
79
- `not_evaluable`. See the [chemical review rubric](https://kent-tokyo.github.io/renkin/guides/chemical-review-rubric/).
54
+ Use `format="syntheseus"`, `format="synplanner"`, or `format="renkin"` for
55
+ other supported route formats. The same audit pipeline is used for every
56
+ source.
80
57
 
81
- **Syntheseus** (`pip install renkin[syntheseus]`)
82
-
83
- ```python
84
- import json
85
- import renkin
86
- from renkin.syntheseus_exporter import dumps_syntheseus_route_v1
87
-
88
- route_json = dumps_syntheseus_route_v1(my_synthesis_graph)
89
- report = json.loads(renkin.audit_route(route_json, format="syntheseus"))
90
- print(report["summary"])
58
+ ```bash
59
+ renkin audit-route route.json --format auto --output json
91
60
  ```
92
61
 
93
- **SynPlanner**
94
-
95
- ```python
96
- import json
97
- import renkin
62
+ Optional private stock and policy checks remain local:
98
63
 
99
- report = json.loads(
100
- renkin.audit_route(open("routes.json").read(), format="synplanner")
101
- )
102
- print(report["summary"])
64
+ ```bash
65
+ renkin audit-route route.json \
66
+ --private-stock private-vendors.csv \
67
+ --stock-policy private-policy.json --output json
103
68
  ```
104
69
 
105
- **In your browser** — no installation, no upload, no server: [**Try the Playground →**](https://kent-tokyo.github.io/renkin/playground/)
106
-
107
- Full walkthroughs with real output, end to end: [AiZynthFinder](https://kent-tokyo.github.io/renkin/guides/aizynthfinder-audit-demo/) · [Syntheseus](https://kent-tokyo.github.io/renkin/guides/syntheseus-audit-demo/) · [SynPlanner](https://kent-tokyo.github.io/renkin/guides/synplanner-audit-demo/).
108
-
109
- ---
70
+ See the [audit guide](https://kent-tokyo.github.io/renkin/guides/audit-reproducibility-contract/),
71
+ [private stock policy](https://kent-tokyo.github.io/renkin/guides/private-stock-policy/),
72
+ and [route interchange](https://kent-tokyo.github.io/renkin/guides/evidence-carrying-interchange/).
110
73
 
111
- ## Quick Start
112
-
113
- *Planning a route from scratch, not auditing one you already have — see [Audit a Route](#audit-a-route) above for that.*
74
+ ## Plan a route
114
75
 
115
76
  ```python
116
77
  import json
117
78
  import renkin
118
79
 
119
- result = json.loads(
120
- renkin.find_routes(
121
- target="CC(=O)Oc1ccccc1C(=O)O", # Aspirin
122
- depth=5,
123
- max_routes=3,
124
- )
125
- )
80
+ result = json.loads(renkin.find_routes(
81
+ target="CC(=O)Oc1ccccc1C(=O)O", # aspirin
82
+ depth=5,
83
+ max_routes=3,
84
+ ))
126
85
 
127
86
  for route in result["routes"]:
128
87
  for step in route["steps"]:
129
- print(f" {step['target']}{' + '.join(step['precursors'])} [{step['rule']}]")
88
+ print(step["target"], "", " + ".join(step["precursors"]))
130
89
  ```
131
90
 
132
- ```javascript
133
- import init, { find_routes } from './pkg/renkin.js';
134
- await init();
135
- const result = JSON.parse(find_routes("CC(=O)Oc1ccccc1C(=O)O", 5, 3, 0));
136
- ```
91
+ CLI:
137
92
 
138
93
  ```bash
139
- ./target/release/renkin --target "CC(=O)Oc1ccccc1C(=O)O" --depth 5 \
140
- --templates data/templates_extracted_5000.smi --format tree
141
- ```
142
-
143
- ```text
144
- Target: CC(=O)Oc1ccccc1C(=O)O
145
- Routes found: 3
146
-
147
- Route 1 [score=1.02, depth=1]
148
- OC(=O)c1ccccc1OC(=O)C
149
- └── [extracted_169]
150
- ├── OC(=O)C ✓ BB
151
- └── [OH]c1ccccc1C(=O)O ✓ BB
152
-
153
- Route 2 [score=1.02, depth=1]
154
- OC(=O)c1ccccc1OC(=O)C
155
- └── [extracted_145]
156
- ├── CC(=O)Cl ✓ BB
157
- └── [OH]c1ccccc1C(=O)O ✓ BB
158
-
159
- Route 3 [score=1.03, depth=1]
160
- OC(=O)c1ccccc1OC(=O)C
161
- └── [extracted_238]
162
- ├── c1cccc(c1O)C(O)=O ✓ BB
163
- └── C([OH])(=O)C ✓ BB
94
+ cargo run --release -- \
95
+ --target "CC(=O)Oc1ccccc1C(=O)O" \
96
+ --depth 5 --beam-width 100 --format tree
164
97
  ```
165
98
 
166
- Use `--format mermaid` for GitHub/Notion-compatible flowcharts.
167
-
168
- [![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/kent-tokyo/renkin/blob/master/examples/renkin_quickstart.ipynb)
169
-
170
- ---
171
-
172
- ## Current Limitations
99
+ The planner uses A*/AND-OR search, template indexing, beam limits,
100
+ stock-aware scoring, and forward validation. See the [API documentation](https://docs.rs/renkin)
101
+ and [retrosynthesis guide](https://kent-tokyo.github.io/renkin/guides/rust-retrosynthesis/).
173
102
 
174
- Current release: **v1.0.5**.
103
+ The following counts describe this checkout and may be invalidated by future
104
+ changes. The default planner includes 24 hand-crafted rules. The repository stock file
105
+ contains 402 compounds; installed users without that file use a compiled-in
106
+ 152-compound fallback. Additional extracted templates can be supplied with
107
+ `--templates`.
175
108
 
176
- ⚠️ The corrected 4,903-target v1.0.1 shared-stock comparison is complete. RENKIN
177
- recorded 591/4,903 primary successes (12.05%) versus AiZynthFinder 4.4.1's
178
- 200/4,903 (4.08%); the paired difference was +7.975 percentage points with 95%
179
- CI [+7.098, +8.852]. The full v1.0.1 arm passed integrity verification, so both
180
- the statistical and formal publication gates pass. This is a result for the
181
- declared shared-stock endpoint, not universal CASP superiority. Historical
182
- 78.0%/95.9%/81.8%(ChEMBL) figures
183
- elsewhere in this repo predate validator fixes and are invalidated. RENKIN does not predict yields, calibrated
184
- experimental success probabilities, or side reactions, and does not search
185
- the literature automatically (`success_probability` is a template-frequency
186
- search-ranking score, not a calibrated prediction — see
187
- [Benchmark](https://kent-tokyo.github.io/renkin/benchmark/) for the corrected
188
- historical baseline, full methodology, and known limitations — that page is a
189
- frozen, single-commit measurement, not a live number).
109
+ ## Components
190
110
 
191
- ---
111
+ | Component | Purpose |
112
+ | --- | --- |
113
+ | `renkin` | Planner, CLI, Python bindings, and WASM module |
114
+ | `renkin-forward` | Forward prediction, enumeration, hints, and validation |
115
+ | `renkin-kg` | Reaction knowledge-graph export |
116
+ | `renkin-mcp` | Local MCP server for search and audit |
192
117
 
193
- ## Why RENKIN?
118
+ The chemistry layer is [`chematic`](https://docs.rs/chematic/), with no
119
+ C/C++ dependency in the core.
194
120
 
195
- RENKIN is designed as a Rust-native synthesis planning stack:
196
-
197
- | | |
198
- |---|---|
199
- | **Fast** | A\* / AND-OR tree search with beam search and template frequency weighting |
200
- | **Portable** | Native CLI · Python wheels · npm/WASM · browser playground — one codebase |
201
- | **Explainable** | Per-step `confidence`, `atom_economy`, `route_cost`, and `procedure_hint` |
202
- | **Verifiable** | `renkin-forward` validates each retrosynthetic step by forward-applying templates |
203
- | **Benchmarkable** | USPTO-50k, PaRoutes-style evaluation, route diversity, and atom balance checks |
204
- | **Agent-ready** | MCP server exposes routes and validation to Claude Desktop and AI agents |
205
-
206
- ---
207
-
208
- ## Constraint-based Search
209
-
210
- Restrict routes by the element composition of their building blocks.
211
-
212
- **Default search** — all 5 routes for biphenyl:
121
+ ## MCP
213
122
 
214
123
  ```bash
215
- renkin --target "c1ccc(-c2ccccc2)cc1" --templates data/templates_extracted_5000.smi --format tree
124
+ cargo run --release --bin renkin-mcp
216
125
  ```
217
126
 
218
- ```text
219
- Routes found: 5
220
- Route 1 [score=1.00, depth=1] c1ccccc1Br + c1c(B(O)O)cccc1
221
- Route 2 [score=1.03, depth=1] c1ccccc1Br + c1c(B(O)O)cccc1
222
- Route 3 [score=1.06, depth=1] c1cc(Cl)ccc1 + c1c(B(O)O)cccc1
223
- Route 4 [score=1.08, depth=1] c1(I)ccccc1 + c1c(B(O)O)cccc1
224
- Route 5 [score=1.08, depth=1] c1ccccc1Br + c1(B2OC(C(C)(C)O2)(C)C)ccccc1
225
- ```
127
+ The MCP server communicates over stdio and exposes search, validation,
128
+ explanation, constraints, diagnostics, and audit receipts. See the [MCP guide](https://kent-tokyo.github.io/renkin/guides/mcp/).
226
129
 
227
- **Constrained search** — boronic-acid coupling, no Br or I starting materials:
130
+ ## Benchmark status
228
131
 
229
- ```bash
230
- renkin --target "c1ccc(-c2ccccc2)cc1" --templates data/templates_extracted_5000.smi \
231
- --require-elements "B" --avoid-elements "Br,I" --format tree
232
- ```
233
-
234
- ```text
235
- Routes found: 1
236
-
237
- Route 1 [score=1.06, depth=1]
238
- c1ccccc1-c2ccccc2
239
- └── [extracted_398]
240
- ├── c1cc(Cl)ccc1 ✓ BB
241
- └── c1c(B(O)O)cccc1 ✓ BB
242
- ```
132
+ The latest checked-in formal comparison uses a declared shared-stock endpoint.
133
+ Native route discovery reached 134/200 (67.0%) for both RENKIN and
134
+ AiZynthFinder 4.4.1. Under the common strict validator, RENKIN reached
135
+ 134/200 and AiZynthFinder 123/200; this fixed-cohort point estimate is not a
136
+ universal CASP superiority claim, and the formal paired gate remains pending.
137
+ Success rate, speed, stock definition, validation, and route quality must be
138
+ reported separately.
243
139
 
244
- Constraints compose freely and are enforced in two layers:
245
- - `--avoid-elements` **prunes expansions during search** when a BB precursor contains a forbidden element (no dead-end nodes added to the heap).
246
- - A final route-level post-filter is still applied for correctness.
247
- - `--require-elements` is a route-level post-filter only.
248
-
249
- Add `--verbose` to print search statistics (nodes expanded, elapsed time) to stderr. Performance counters are available in native builds only; disabled in WASM.
250
-
251
- Add `--search-diagnostics` to add a `search_diagnostics` block to JSON output (beam eviction counts/scores, cross-template duplicate precursor signatures, rule-application attempts, stock-terminal/non-stock candidate counts, depth-wise branching factor, hypothetical dedup-strategy counts) — diagnostics-only bookkeeping, off by default, does not affect search behavior ([Issue #101](https://github.com/kent-tokyo/renkin/issues/101)). Add `--candidate-trace-limit <N>` (implies `--search-diagnostics`) to also collect up to `N` per-candidate trace records (precursor signature, template provenance, beam rank/survival, whether it fed a returned route) — offline diagnostic use only, gated at collection time so the default no-trace path allocates nothing extra.
252
-
253
- ---
254
-
255
- ## Template Evidence Metadata
256
-
257
- Extracted templates only have a positional display name (`extracted_{i}`) that
258
- changes whenever the source `.smi` file is reordered or re-extracted, so
259
- external knowledge (a DOI, a reported yield, a known side reaction) can't be
260
- durably attached to one. Every template — hand-crafted and extracted — now
261
- has a stable `template_id` instead:
262
-
263
- - Hand-crafted rules: `rule:<rule_name>` (e.g. `rule:suzuki_retro`).
264
- - Extracted templates: `smirks-sha256:<hex>` — the SHA-256 hex digest of the
265
- *trimmed* SMIRKS string. Independent of file position, load order, and
266
- count; purely syntactic (no SMIRKS canonicalization — a semantically
267
- equivalent SMIRKS written differently gets a different ID).
268
-
269
- Run `renkin template ids <file.smi>` to list every template's `template_id`,
270
- display name, SMIRKS, and weight (TSV by default, `--format json` for JSON) —
271
- use this to look up the IDs you need when authoring a sidecar file.
272
-
273
- Attach curated evidence with `--template-metadata sidecar.json` (also
274
- available in Python as `find_routes(..., template_metadata_path=...)`),
275
- keyed by `template_id`:
276
-
277
- ```json
278
- {
279
- "schema_version": 1,
280
- "templates": {
281
- "smirks-sha256:ef8778a2888469d619c52cce7e74f6848e101049050dd1b765b78f32e3c94498": {
282
- "references": [
283
- { "id": "ref-1", "kind": "doi", "identifier": "10.xxxx/example" }
284
- ],
285
- "condition_candidates": [
286
- {
287
- "catalysts": ["Pd(PPh3)4"],
288
- "bases": ["K2CO3"],
289
- "solvents": ["EtOH", "water"],
290
- "temperature_c": { "min": 75.0, "max": 85.0 },
291
- "source": "literature",
292
- "scope": "template",
293
- "reference_ids": ["ref-1"]
294
- }
295
- ],
296
- "reported_yields": [
297
- {
298
- "percentage": { "min": 72.0, "max": 81.0 },
299
- "basis": "isolated",
300
- "source": "literature",
301
- "scope": "template",
302
- "reference_ids": ["ref-1"]
303
- }
304
- ],
305
- "warnings": [
306
- {
307
- "code": "possible_protodeboronation",
308
- "severity": "medium",
309
- "message": "Protodeboronation has been reported under prolonged aqueous heating.",
310
- "source": "literature",
311
- "scope": "template",
312
- "reference_ids": ["ref-1"]
313
- }
314
- ]
315
- }
316
- }
317
- }
318
- ```
319
-
320
- A matching step gets an `evidence` field with `condition_candidates`,
321
- `reported_yields`, `references`, and `warnings`; steps whose template has no
322
- sidecar entry get no `evidence` key at all. The sidecar is loaded and
323
- validated (schema version, duplicate/dangling reference IDs, yield range,
324
- range `min <= max`, non-empty DOI/patent identifiers) **before search
325
- starts** — malformed metadata is a hard error, and a `template_id` in the
326
- sidecar that matches no loaded rule prints a warning rather than failing
327
- silently.
328
-
329
- **What this is not:**
330
- - `reported_yields` is a curated record of what was reported externally —
331
- **not a RENKIN prediction**. `step_confidence`/`success_probability` are
332
- unaffected and keep meaning template-frequency-derived search-ranking
333
- scores, not experimental success rates.
334
- - `warnings` reflects only what's explicitly present in the sidecar you
335
- supply — **not** automatic side-reaction detection.
336
- - Templates without a matching sidecar entry get no fabricated evidence.
337
- Nothing is invented for missing data.
338
-
339
- Yield/success prediction and automatic literature search are explicitly out
340
- of scope for this phase — tracked as future work in
341
- [#41](https://github.com/kent-tokyo/renkin/issues/41).
342
-
343
- ### Substrate-specific examples (`schema_version: 2`)
344
-
345
- Everything above is *template-level*: it applies to every step using that
346
- template, regardless of the actual molecule. `schema_version: 2` adds
347
- `examples` — a per-template array where each entry is one curated record of
348
- *this exact reaction*, keyed by `target_smiles`/`precursor_smiles`:
349
-
350
- ```json
351
- {
352
- "schema_version": 2,
353
- "templates": {
354
- "smirks-sha256:...": {
355
- "references": [{ "id": "ref-1", "kind": "doi", "identifier": "10.xxxx/example" }],
356
- "examples": [{
357
- "id": "ex-1",
358
- "target_smiles": "c1ccc(-c2ccccc2)cc1",
359
- "precursor_smiles": ["Brc1ccccc1", "c1ccccc1"],
360
- "conditions": { "catalysts": ["Pd(PPh3)4"], "solvents": ["EtOH"], "source": "literature", "scope": "substrate_specific", "reference_ids": ["ref-1"] },
361
- "reported_yield": { "percentage": 78.0, "basis": "isolated", "source": "literature", "scope": "substrate_specific", "reference_ids": ["ref-1"] },
362
- "reference_ids": ["ref-1"]
363
- }]
364
- }
365
- }
366
- }
367
- ```
140
+ See the [benchmark documentation](https://kent-tokyo.github.io/renkin/benchmark/)
141
+ for the full measurements, methodology, confidence intervals, and limitations.
368
142
 
369
- `examples` requires `schema_version: 2` (a hard error under `1`); under
370
- `schema_version: 2`, reported yields must live under `examples[].reported_yield`
371
- too — a non-empty template-level `reported_yields` is a hard error there (it
372
- stays allowed under `schema_version: 1`), so a substrate-specific number can't
373
- leak onto every step using that template. Every condition/yield/warning
374
- nested inside an example must be scoped `substrate_specific`.
375
-
376
- A route step's `evidence.examples` are **resolved**, not just copied from the
377
- sidecar: matched against that step by canonical target SMILES plus the
378
- canonical, order-independent precursor set (reordering `precursor_smiles` in
379
- the sidecar changes nothing), with every exact-substrate match kept and
380
- same-template-different-substrate precedents capped at 3. Each resolved entry
381
- carries a `match_kind` (`exact_substrate`/`template_only`) in the JSON itself,
382
- plus a `template_examples_total` count — so JSON/Python consumers, not just
383
- `--format explain`, can tell "evidence for this exact reaction" apart from
384
- "literature precedent for a different substrate." `--format explain` shows
385
- exact-substrate matches first, each labeled either `Exact substrate example:`
386
- or *"different substrate; not a prediction"*, with `conditions`/
387
- `reported_yield`/`warnings` each showing their own cited references directly
388
- underneath (deduplicated when the same reference backs more than one part of
389
- an example). See [Reaction Evidence guide](docs/guides/reaction-evidence.md#substrate-specific-examples-schema_version-2)
390
- for full matching/validation semantics.
391
-
392
- **Importing evidence from ORD.** `renkin evidence match` (exact-set batch
393
- template matching, no fuzzy/similarity matching) and
394
- [`scripts/ord_evidence_audit.py`](scripts/README_ord_evidence.md) (offline,
395
- network-free) turn a locally-downloaded
396
- [Open Reaction Database](https://github.com/open-reaction-database/ord-data)
397
- corpus into a `schema_version: 2` sidecar — every accepted record is
398
- independently re-validated by RENKIN's own loader, and anything not uniquely
399
- matched, unambiguous, and provenanced is excluded and counted in an audit
400
- report rather than guessed at. RENKIN itself never fetches or searches the
401
- literature; reported yields are citations, not predictions. ORD's reaction
402
- data is CC-BY-SA-4.0, a different license from RENKIN's own MIT code — see
403
- [Reaction Evidence guide](docs/guides/reaction-evidence.md#importing-from-ord-open-reaction-database)
404
- for the full acceptance criteria and licensing split.
405
-
406
- ---
407
-
408
- ## Key Features
409
-
410
- | Feature | Detail |
411
- |---|---|
412
- | **Pure Safe Rust** | `#![forbid(unsafe_code)]` on all crates — compiler-enforced, zero C/C++ dependencies |
413
- | **Search engine** | A\*/AND-OR tree search (Retro\*-equivalent, pluggable `MoleculeValueEstimator`/`ReactionPrior`) with `--beam-width N` for memory-bounded exploration and `rayon` parallel rule application (sequential fallback on wasm32) |
414
- | **Up to 50k reaction templates** | Auto-extracted from USPTO-50k/MIT via rdchiral; frequency-weighted priority (optional pure-Rust `tract-onnx` NN scorer via `--scorer`, with ordering-only frequency blending via `--scorer-ordering-blend`); `--templates` for custom sets |
415
- | **Template quality tools** | `renkin template stats\|validate\|dedup\|explain\|coverage\|ids` — frequency distribution, validity, duplicates, per-template lookup, coverage rate, stable IDs |
416
- | **Stable template IDs + evidence sidecar** | Every template gets a stable `template_id` (`rule:<name>` / `smirks-sha256:<hex>`, independent of file order). Attach curated DOIs/patents, conditions, yields, and side-reaction warnings via a `--template-metadata sidecar.json`; matching steps get an `evidence` field — see [Template evidence metadata](#template-evidence-metadata) below. `schema_version: 2` sidecars can also attach `examples` (curated exact-substrate records, surfaced first in `--format explain`). Automatic yield/success prediction and literature search remain out of scope ([#41](https://github.com/kent-tokyo/renkin/issues/41)) |
417
- | **Ring-context safety guard** | `--ring-context-policy conservative --ring-context-sidecar <path>` — opt-in match-level filter that rejects an extracted template's ring-opening/closing disconnection when its historical training data never observed that bond as ring-forming/-breaking; default `disabled` (unchanged legacy behavior) — see [Issue #72](https://github.com/kent-tokyo/renkin/issues/72) |
418
- | **LightGBM candidate reranker** | `--reranker-model`/`--reranker-freq-table` (CLI) or `reranker_model_path`/`reranker_freq_table_path` (Python) — opt-in, ordering-only re-ranking via a frozen LightGBM model; never changes which candidates are generated, only their order, and reproduces legacy ordering byte-for-byte when off. Paired 100-target route-search gate: `route_to_configured_stock` 16→20 (+4/-0). `python3 scripts/fetch_reranker_model.py` fetches the frozen model (SHA-256-verified, not bundled in any package — see [Roadmap](#roadmap)) |
419
- | **Coverage mode** (opt-in) | `--search-mode coverage --coverage-templates <path>` (CLI) or `search_mode="coverage"`, `coverage_templates_path=...` (Python) — if the default template set finds no route, automatically escalates to a larger, separately loaded template set, cooperatively cancellable via `--coverage-timeout-secs`. Standard-mode output is byte-for-byte unchanged when not used. `python3 scripts/fetch_coverage_templates.py` fetches the frozen 2,000-template Stage-2 set (SHA-256-verified, not bundled in any package, same reasoning as the reranker model — see [Roadmap](#roadmap)) |
420
- | **Staged recovery** (opt-in, native) | `--search-mode recovery --beam-diversity-slots N` preserves a successful baseline and conditionally escalates element gating, diversity, depth, and caller-supplied narrow-to-broad coverage tiers. Every attempt is audit-visible; standard mode and its defaults are unchanged. See [staged recovery mode](docs/guides/staged-recovery.md) |
421
- | **Search budget profiles** (opt-in) | `--search-profile fast\|balanced\|deep` selects an explicit speed/coverage budget. Named-profile JSON records schema-versioned effective baseline/recovery settings; legacy output is unchanged when omitted. |
422
- | **RENKIN Bridge / `audit-route`** | `renkin audit-route route.json [--format auto\|renkin\|aizynthfinder\|syntheseus\|synplanner] [--stock stock.smi] [--output human\|json]` — tool-neutral route audit: structural integrity, stock, and declared-reaction forward-replay validation, each reported independently as `pass`/`fail`/`not_evaluable`, rolled up into a route-level `pass`/`fail`/`partial` verdict. Reads RENKIN-native route JSON (v0.25.0), real AiZynthFinder route JSON — single-target and gzip-compressed batch output, verified against AiZynthFinder 4.3.2, 4.4.0, and 4.4.1 specifically, not claimed for every version (v0.26.0, version matrix widened v0.32.0) — Syntheseus routes via the optional `renkin.syntheseus_exporter`'s `syntheseus-route-v1` interchange schema, since Syntheseus itself has no native route export (v0.30.0) — and real SynPlanner 1.6.0 `write_routes_json` exports directly, no exporter package needed (v0.34.0); `--format auto` detects the input shape and hard-errors rather than guessing on anything ambiguous. [AiZynthFinder walkthrough →](https://kent-tokyo.github.io/renkin/guides/aizynthfinder-audit-demo/) · [Syntheseus walkthrough →](https://kent-tokyo.github.io/renkin/guides/syntheseus-audit-demo/) · [SynPlanner walkthrough →](https://kent-tokyo.github.io/renkin/guides/synplanner-audit-demo/) |
423
- | **Route scoring & diagnostics** | Separate `confidence`, `success_probability`, cost, feasibility findings, building-block diversity, and template-proxy chemical-idea diversity; no aggregate laboratory-feasibility score is fabricated — see the caveat below and the [diagnostics](docs/guides/route-feasibility-diagnostics.md) / [diversity](docs/guides/route-set-diversity.md) guides |
424
- | **Step metadata provenance** | Each step reports `metadata_source`/`metadata_scope` so it's machine-readable whether `conditions`/`reaction_family` came from a rule-author default vs. something more grounded; absent (not fabricated) for extracted templates |
425
- | **Pareto multi-objective search** | `--format pareto` returns a Pareto front across `route_cost`/`success_probability`/`steps`; objectives configurable via `--objectives` |
426
- | **Constraint DSL** | `--constraints constraints.json` — element/building-block filters, step/cost limits, confidence thresholds, required/avoided/preferred reaction families; enables LLM → RENKIN pipelines |
427
- | **Output formats & diagnostics** | `--format json\|tree\|mermaid\|explain\|compare\|compare-json\|pareto`; zero-route JSON includes a `diagnostics` block with `likely_causes`/`suggestions` |
428
- | **`renkin-forward` toolkit** | `predict` (rank forward products), `enumerate` (bounded products from one reactant + partner library), `hints` (partner-free retrieval hints, no concrete product), `validate` (forward-verify each retro step) — see the [Forward guides](docs/guides/forward-retrieval-hints.md#predict--enumerate--hints-at-a-glance) |
429
- | **`renkin-bench`** | USPTO-50k/PaRoutes evaluation with `--plausibility` (forward-validated composite score), `--failure-taxonomy`, atom-balance checks (`target_MW > Σ precursor_MW`), and multi-stage `cascade` re-runs on unsolved targets — see [Benchmark](#benchmark) |
430
- | **Stock management** | `renkin stock stats\|validate\|coverage\|compile`; integrity-checked `.rstock` snapshots avoid reparsing large stocks, while the `vendor_stock` API supports source, price, lead-time, availability, and exact/parent/stereo/tautomer policy |
431
- | **MCP server** | `renkin-mcp` exposes 7 tools over stdio (`find_routes`, `validate_route`, `explain_route`, `find_pareto_routes`, `plan_with_constraints`, `estimate_diversity`, `diagnose_failure`) and supports the legacy `2024-11-05` and modern `2026-07-28` protocol revisions; see the [MCP guide](docs/guides/mcp.md) |
432
- | **`renkin-doctor`** | Environment diagnostic binary — templates, building blocks, Python import, tool versions, data integrity |
433
- | **`renkin-kg`** | Reaction knowledge graph builder — bipartite mol↔reaction graphs from routes, GraphML/Cypher export |
434
- | **Multi-target** | `pip install renkin` (pre-built wheels, Linux/macOS/Windows) · `npm install renkin` (~500 KB WASM, near-native browser speed) |
435
- | **Building blocks + stereo** | 402 unique compounds loaded from `data/building_blocks.smi` (aryl halides, boronic acids, heterocycles, amines, acids, amino acids — see [Benchmark](#benchmark)); full tetrahedral @/@@ and E/Z stereochemistry; `building_blocks` field in every route JSON (leaf starting-material SMILES, no manual parsing) |
436
-
437
- > **`step_confidence`/`success_probability` are not yields or measured success rates.**
438
- > They're template-frequency-derived search-ranking scores (`rule_weight / max_rule_weight`,
439
- > multiplied across a route's steps) used to order candidate disconnections during search —
440
- > not a calibrated probability of experimental success, and not an expected isolated yield.
441
- > Route-level experimental yield/success-rate reporting is not implemented.
442
-
443
- ---
444
-
445
- ## Pipeline Examples
143
+ ## Development
446
144
 
447
145
  ```bash
448
- # Route cost scoring with commercial prices
449
- renkin -t "Cc1ccc(-c2ccccc2)cc1" --bb-prices data/prices.csv --format json
450
-
451
- # Standalone forward prediction — no route search involved
452
- renkin-forward predict --reactants "Oc1ccccc1C(=O)O" "CCO" --report --max-results 5
453
-
454
- # Forward validation — pipe find_routes output directly
455
- renkin -t "CC(=O)Oc1ccccc1C(=O)O" --format json | renkin-forward validate
456
-
457
- # Faster template retrieval with bond-center index (~24% speedup)
458
- renkin -t "c1ccc(NC(=O)c2ccccc2)cc1" --templates data/templates_extracted_5000.smi --bond-index
459
-
460
- # Audit a real AiZynthFinder route export with RENKIN (see the full walkthrough:
461
- # https://kent-tokyo.github.io/renkin/guides/aizynthfinder-audit-demo/)
462
- renkin audit-route tests/fixtures/aizynthfinder/v4.4.1/single_trees.json \
463
- --format aizynthfinder \
464
- --stock data/building_blocks.smi \
465
- --output human
466
-
467
- # Same audit pipeline, either source — --format auto also detects both correctly
468
- renkin -t "CC(=O)Oc1ccccc1C(=O)O" --format json > /tmp/renkin-route.json
469
- renkin audit-route /tmp/renkin-route.json --format renkin
470
- renkin audit-route tests/fixtures/aizynthfinder/v4.4.1/single_trees.json --format aizynthfinder
146
+ cargo test --workspace
147
+ cargo clippy --workspace --all-targets -- -D warnings
148
+ cargo fmt --all -- --check
471
149
  ```
472
150
 
473
- ---
474
-
475
- ## Benchmark
476
-
477
- USPTO-50k test set (4,907 molecules, full evaluation):
151
+ Read [`AGENTS.md`](AGENTS.md), [`tasks/lessons.md`](tasks/lessons.md), and
152
+ the [roadmap](ROADMAP.md) before changing the chemistry or search core.
478
153
 
479
- > **Evaluation definition**: A molecule is *solved* if `find_routes` returns at least one route whose leaf precursors are all in the building block set, within depth=5 and beam=100. Ground-truth reactants from USPTO-50k are **not** checked — any commercially accessible route counts.
154
+ Important boundaries:
480
155
 
481
- ### Current formal 200-target comparison (2026-09-08)
482
-
483
- The frozen VAL-200 shared-stock rerun found native routes for **134/200
484
- (67.0%)** targets for both RENKIN and AiZynthFinder 4.4.1. Under the paired
485
- strict validator-plus-stock metric, RENKIN found **134/200 (67.0%)** and
486
- AiZynthFinder **123/200 (61.5%)**, a +5.5pp point estimate. This is a fixed
487
- cohort result, not a universal superiority or experimental-yield claim.
488
- [Full report](data/comparison/formal_v1.0.3_candidate_20260908/formal_200_native_rstock_combined_v2_20260908/FORMAL_BENCHMARK_REPORT.md)
489
-
490
- ### Formal v1.0.1 shared-stock comparison (4,903 paired targets)
491
-
492
- | Arm | Primary route-to-shared-stock successes | Rate |
493
- |---|---:|---:|
494
- | RENKIN v1.0.1 | 591 / 4,903 | 12.05% |
495
- | AiZynthFinder 4.4.1 | 200 / 4,903 | 4.08% |
496
-
497
- The paired RENKIN-minus-AiZynthFinder difference is **+7.975 percentage
498
- points**, with paired-bootstrap 95% CI **[+7.098, +8.852]**. The statistical
499
- and formal publication gates both **PASS**. The complete v1.0.1 arm passed
500
- target-set, manifest, schema, and route-hash integrity verification; all 591
501
- reported routes had parseable normalized trees terminating in the configured
502
- shared stock. The frozen v1.0.0 HOLD artifact remains preserved separately.
503
- This is a shared-stock route endpoint, not experimental yield or universal CASP
504
- superiority. [Protocol and status](docs/benchmark/formal-v1.0-competitor-comparison.md)
505
- · [corrected report](data/comparison/formal_v1.0.1/formal_report.md)
506
-
507
- ### Corrected baseline (commit `e20dc8c`, 2026-07-22)
508
-
509
- | Public label | Internal metric | Value |
510
- |---|---|---|
511
- | Search-to-stock rate | `raw_solved_rate` | **20.09%** (986/4,907) |
512
- | Atom-balance-filtered rate | `atom_balanced_solved_rate` | **15.41%** (756/4,907) — subset of search-to-stock |
513
- | Current-validator-confirmed rate | `provenance_validated_solved_rate` | **0.88%** (43/4,907) — subset of atom-balance-filtered |
514
-
515
- 402 building blocks (unique compounds actually loaded from `data/building_blocks.smi` — see below), 5,000 extracted templates, 28 handcrafted rules, depth=5, beam=100. These three rates are a nested series over the same 4,907 targets, not independent numbers, and none is an experimentally-verified synthesis success rate or a human-chemist-reviewed route-accuracy figure. `provenance_validated_solved_rate` is not a measured chemical-accuracy rate and not a proven lower bound on correctness — it only counts routes the current validator can positively confirm, and an unknown fraction of "invalid" verdicts may be validator false negatives rather than real chemistry or route errors (the split is unmeasured). Full methodology, per-rule breakdown, and reproduction command: [`tasks/phase31_final_remeasurement_run.md`](https://github.com/kent-tokyo/renkin/blob/master/tasks/phase31_final_remeasurement_run.md) · [Full benchmark details →](https://kent-tokyo.github.io/renkin/benchmark/)
516
-
517
- ### Historical progression (pre-fix, invalidated — see notice above)
518
-
519
- ⚠️ The figures in this subsection (78.0% single-pass, 95.9% cascade, 81.8% ChEMBL OOD) predate the 31.11/31.12 fixes, are invalidated, and have not been re-measured. Kept for continuity only — do not cite as current performance.
520
-
521
- > **Evaluation note**: All numbers use the standard USPTO-50k train/test split (same corpus). Templates are extracted from the training set and evaluated on the test set. Numbers reflect performance within the USPTO-50k domain; out-of-distribution generalization was separately evaluated via ChEMBL approved drugs (**81.8%**, 409/500, also not re-measured).
522
-
523
- | Config | Solved | Rate | BBs | Templates | depth | beam | ms/mol |
524
- |---|---|---|---|---|---|---|---|
525
- | v0.1.0 initial | 366/4907 | 7.5% | 463 | 31 | 3 | 50 | — |
526
- | + auto templates (top-300) | 1363/4907 | 27.8% | 463 | 222 | 3 | 50 | — |
527
- | + depth=5, top-500 templates | 2315/4907 | 47.2% | 463 | 314 | 5 | 50 | — |
528
- | + beam=100 | 2688/4907 | 54.8%* | 463 | 314 | 5 | 100 | — |
529
- | + Phase A (template freq. weighting) | 3540/4907 | 72.1%† | 463 | 314 | 5 | 100 | — |
530
- | + 5,000 templates, 480 BBs | 3826/4907 | 78.0% | 480 | 5,000 | 5 | 100 | 2,775 |
531
- | Phase A unlimited (beam=0) | 3832/4907 | 78.1% | 480 | 5,000 | 5 | 0 | — |
532
- | Phase B (NN scorer, tract-onnx) | 3826/4907 | 78.0% | 480 | 5,000 | 5 | 100 | 3,394 |
533
- | **+ diaryl sulfone rule, 509 BBs** | **3826/4907** | **78.0%** | **509** | **5,000** | **5** | **100** | **≈2,800** |
534
- | Cascade (stage2: depth=7, beam=300 on unsolved) | 4705/4907 | **95.9%** | 509 | 5,000 | 7 | 300 | — |
535
-
536
- \* 29/50 chunks, previous binary
537
- † 50/50 chunks — **72.1%** (3,540/4,907) confirmed
538
- BB counts in this historical table (463/480/509) are as originally documented at each point in time — legacy documentation values, not re-verified against `ChemEnv::bb_count()`. The corrected-baseline section above uses the actually-loaded count (402) for the current `data/building_blocks.smi`.
539
-
540
- *Note: LocalRetro (53.4%) and GLG (58.0%) report single-step top-1 prediction accuracy — a different metric, not directly comparable.*
541
-
542
- > **Benchmark scope note**: USPTO-50k is used here as a *standardized sanity benchmark*, not as proof of broad real-world synthesis performance. The corpus covers a narrow slice of reaction space (primarily C–C and C–N bond formations common in pharmaceutical synthesis), and reaction types with sparse USPTO representation are systematically underserved. Out-of-distribution performance on ChEMBL approved drugs (**81.8%**, 409/500, pre-fix, not re-measured) suggested the rule set generalizes beyond the test corpus, but neither historical number should be interpreted as a guarantee of route quality on arbitrary targets.
543
-
544
- ### PaRoutes compatibility
545
-
546
- RENKIN is compatible with the [PaRoutes](https://github.com/AstraZeneca/PaRoutes) multi-step benchmark. Download their stock compounds and target molecules, then pass them directly:
547
-
548
- ```bash
549
- renkin-bench \
550
- --input paroutes_n1_targets.smi \
551
- --building-blocks paroutes_stock.smi \
552
- --templates data/templates_extracted_5000.smi \
553
- --depth 5 --beam-width 100
554
- ```
555
-
556
- The JSON output includes `avg_nodes_expanded`, `avg_confidence`, `avg_convergency`, and `avg_success_prob` (Retro-prob style) alongside the standard solved/success_rate metrics.
557
-
558
- ---
559
-
560
- ## Competitive Landscape
561
-
562
- ⚠️ RENKIN's row below uses the corrected `raw_solved_rate` (20.09%, see notice near the top of this README) — the 95.9% cascade figure some earlier versions of this table cited is invalidated and not re-measured; it is not included here.
563
-
564
- | Tool | Language | License | WASM | Zero-dep | Algorithm | Template source | Stock |
565
- |---|---|---|---|---|---|---|---|
566
- | **ASKCOS** | Python | CC BY-NC | No | No (Docker, 64 GB) | MCTS + A\* | USPTO (ML) | ZINC |
567
- | **AiZynthFinder** | Python | MIT | No | No (conda + model) | MCTS | USPTO (ML, ~50k) | eMolecules (~6M) |
568
- | **SYNTHIA** | Closed | Proprietary | No | No | SMARTS + AND/OR | Manual curated | Sigma-Aldrich |
569
- | **IBM RXN** | Closed | Cloud SaaS | No | No | Transformer | USPTO | — |
570
- | **Retro\*** | Python | MIT | No | No (unmaintained) | A\* + AND/OR | USPTO (ML) | eMolecules |
571
- | **★ RENKIN** | **Rust** | **MIT** | **Yes** | **Yes** | **A\* + AND/OR** | Hand-curated + rdchiral (5k default; 50k via `--templates`) | 402+ |
572
-
573
- `raw_solved_rate` is the closest available RENKIN metric to the published route-finding success rates of the other planners above, but the figures are not directly comparable — stock size, template library, target set, search budget, and route-quality checks all differ across systems, and this table does not establish RENKIN as better or worse than the alternatives.
574
-
575
- **RENKIN's goal**: match state-of-the-art accuracy using only curated rules and auto-extracted SMIRKS templates — no GPU, no training data, no black boxes. Under RENKIN's benchmark setting (corrected baseline, commit `e20dc8c`, 2026-07-22), it reaches **20.09%** `raw_solved_rate` (986/4,907) single-pass — see the Benchmark section above for the full nested-metric series and why the stricter `provenance_validated_solved_rate` (0.88%) is not RENKIN's measured or bounded correctness rate. RENKIN runs anywhere: browser, CLI, Python — single `cargo build`.
576
-
577
- > ⚠️ The table above lists tools under different evaluation conditions. No matched-condition experiment against other tools has been performed.
578
-
579
- ---
580
-
581
- ## MCP Server
582
-
583
- `renkin-mcp` exposes retrosynthesis as an MCP tool so AI agents (Claude, etc.) can call it directly.
584
-
585
- **Setup** — add to `claude_desktop_config.json`:
586
-
587
- ```json
588
- {
589
- "mcpServers": {
590
- "renkin": { "command": "/path/to/renkin-mcp" }
591
- }
592
- }
593
- ```
594
-
595
- **Tools** (7):
596
-
597
- | Tool | Description |
598
- |---|---|
599
- | `find_routes` | Retrosynthesis: SMILES → routes with scoring |
600
- | `validate_route` | Forward-validate a retrosynthetic route |
601
- | `explain_route` | Human-readable strengths/weaknesses per route |
602
- | `find_pareto_routes` | Pareto-front multi-objective route search |
603
- | `plan_with_constraints` | Constraint-DSL planning (element/building-block filters, step/cost limits, confidence thresholds, required/avoided/preferred reaction families) |
604
- | `estimate_diversity` | Route diversity and coverage metrics |
605
- | `diagnose_failure` | Structured explanation of why a search found no route |
606
-
607
- `find_routes` also accepts `search_mode: "coverage"` with a required
608
- `coverage_templates` path. It runs the standard Stage 1 first and escalates
609
- to Stage 2 only when Stage 1 finds no route; the response reports the selected
610
- stage, timeout status, and per-stage elapsed time.
611
-
612
- The server auto-detects `data/building_blocks.smi` and the optional, locally
613
- generated `data/templates_extracted_5000.smi` in the working directory. It
614
- falls back to the embedded `DEFAULT_BUILDING_BLOCKS` / `default_rules()`
615
- defaults if they are not found (152 unique building blocks per
616
- `ChemEnv::bb_count()`, 23 handcrafted rules).
617
-
618
- ```bash
619
- cargo build --release
620
- # binary: target/release/renkin-mcp
621
- ```
622
-
623
- ---
624
-
625
- ## Architecture
626
-
627
- ### Workspace scope
628
-
629
- ```
630
- ┌──────────────────────────────────────────────────────────────────┐
631
- │ renkin workspace (this repository) │
632
- │ │
633
- │ renkin (retrosynthesis) renkin-forward │
634
- │ ────────────────────── ───────────────────────────── │
635
- │ target → precursors reactants → products │
636
- │ A* / AND-OR search template-based forward │
637
- │ route scoring & constraints (validates retro routes) │
638
- │ │ │ │
639
- │ └──────────────────┬─────────────────┘ │
640
- │ ▼ │
641
- │ chematic (molecular representation, │
642
- │ SMILES, substructure matching, reaction SMARTS) │
643
- └──────────────────────────────────────────────────────────────────┘
644
- ```
645
-
646
- ### Internal data flow (renkin crate)
647
-
648
- ```
649
- Target SMILES
650
-
651
-
652
- ┌─────────────────────────┐
653
- │ chem_env.rs │ ← chematic wrapper
654
- │ - SMILES parse │ canonical-SMILES FxHashSet BB lookup (O(1))
655
- │ - 23 built-in + up to 50k via --templates │ fragment sanitization + ring-leak filter
656
- │ - Building block check │ apply_retro memoization cache
657
- └────────────┬────────────┘
658
- │ par_iter (rayon / sequential on WASM)
659
-
660
- ┌─────────────────────────┐
661
- │ search.rs │ ← A* / AND-OR Tree Search
662
- │ - Priority queue │ SA Score heuristic + memoization
663
- │ - Closed list │ beam search (SmallVec frontier)
664
- │ - Arc<PathNode> paths │ O(1) path sharing per child
665
- └────────────┬────────────┘
666
-
667
-
668
- ┌─────────────────────────┐
669
- │ score.rs │ ← Heuristic / Cost Function
670
- │ - SA Score (chematic) │ h = Σ(1 + 0.5·(sa−1)/9)
671
- │ - MW step cost │ g = Σ(1 + total_mw/2000)
672
- └────────────┬────────────┘
673
-
674
-
675
- ┌─────────────────────────┐ (optional)
676
- │ scorer.rs │ ← Phase B: NN Template Scorer
677
- │ - tract-onnx │ Pure Rust ONNX inference
678
- │ - --scorer flag │ molecule-specific template ranking
679
- └────────────┬────────────┘
680
-
681
-
682
- JSON ← CLI / Python / WASM
683
- ```
684
-
685
- ---
686
-
687
- ## Project Structure
688
-
689
- ```
690
- renkin/ ← Cargo workspace root
691
- ├── Cargo.toml
692
- ├── src/ ← renkin crate (retrosynthesis)
693
- │ ├── lib.rs # public library
694
- │ ├── main.rs # CLI binary (--templates, --template-metadata, --scorer, --constraints, --objectives flags)
695
- │ ├── bin/benchmark.rs # renkin-bench binary (--plausibility flag)
696
- │ ├── bin/doctor.rs # renkin-doctor diagnostic binary
697
- │ ├── bin/fp.rs # renkin-fp ECFP4 fingerprint (nn-scoring feature)
698
- │ ├── bin/mcp.rs # renkin-mcp stdio launcher
699
- │ ├── mcp/ # Dual-era protocol + 7 tool handlers
700
- │ ├── chem_env.rs # retro rules + BB lookup + template loader
701
- │ ├── score.rs # SA Score heuristic + step cost
702
- │ ├── search.rs # A* / AND-OR tree engine + beam pruning
703
- │ ├── scorer.rs # Phase B: tract-onnx NN template scorer
704
- │ ├── candidate.rs # one-step candidate proposal (offline reranking foundation, not wired into search)
705
- │ ├── pool_export.rs # candidate-pool JSONL + reproducibility-manifest export
706
- │ ├── python.rs # PyO3 bindings (--features python)
707
- │ └── wasm.rs # wasm-bindgen bindings (cfg = wasm32)
708
- ├── crates/ ← sibling crates
709
- │ ├── renkin-forward/ # forward reaction prediction (reactants → products)
710
- │ └── renkin-kg/ # reaction knowledge graph builder (GraphML / Cypher export)
711
- ├── data/
712
- │ ├── building_blocks.smi # 402 curated commercial starting materials (loaded/deduplicated count)
713
- │ ├── templates_extracted_500.smi # 500 checked-in auto-extracted SMIRKS templates
714
- │ ├── benchmark_targets.smi # internal benchmark set
715
- │ └── bench_chunks/ # USPTO-50k per-chunk results
716
- ├── scripts/
717
- │ ├── extract_templates.py # rdchiral template extraction pipeline
718
- │ ├── run_benchmark_chunks.sh # resumable chunked benchmark runner
719
- │ ├── train_reranker.py # candidate reranker training/evaluation (dev tool, offline only)
720
- │ └── tests/ # unittest suite for train_reranker.py
721
- ├── docs/ # MkDocs source → kent-tokyo.github.io/renkin/
722
- └── mkdocs.yml
723
- ```
724
-
725
- ---
726
-
727
- ## Roadmap
728
-
729
- Full shipped history (every release, in order): [`CHANGELOG.md`](CHANGELOG.md).
730
- This section only tracks the current headline items and what's next —
731
- see "Earlier milestones" below for older shipped work.
732
-
733
- ### Recently shipped
734
-
735
- - [x] **SynPlanner Bridge** (`--format synplanner`, shipped v0.34.0) — *Keep SynPlanner. Audit its routes with RENKIN.* A fourth route adapter, and the first whose native export carries real, forward-replayable atom mapping: `renkin audit-route --format synplanner` (also auto-detected) reads real SynPlanner 1.6.0 `write_routes_json` exports directly, no exporter package needed. Confirmed against real SynPlanner output twice — hand-constructed reactions through SynPlanner's own exporter, and a real CPU-only MCTS-searched planning run through the real `synplan planning` CLI end to end — every one of 317 real reaction nodes across a 167-route real search carries a structurally valid atom map, and real routes reach a genuine `pass` verdict, not just `not_evaluable`. New 4-way (RENKIN-native/AiZynthFinder/Syntheseus/SynPlanner) structural and policy-verdict parity tests. The [browser playground](https://kent-tokyo.github.io/renkin/playground/)'s Audit tab gained SynPlanner as a fourth format option, with a one-click real-MCTS-output example. [5-minute walkthrough with real output →](https://kent-tokyo.github.io/renkin/guides/synplanner-audit-demo/)
736
- - [x] **Syntheseus Bridge** (`--format syntheseus`, shipped v0.30.0) — *Syntheseus has no route export. RENKIN built one — and audits it exactly like every other adapter.* A third route adapter alongside RENKIN-native and AiZynthFinder: the optional `renkin.syntheseus_exporter` (`pip install renkin[syntheseus]`) turns a real Syntheseus `SynthesisGraph` into the `syntheseus-route-v1` interchange schema, which `renkin audit-route --format syntheseus` (also auto-detected) consumes through the identical audit pipeline every adapter shares. Forward validation honestly reports `not_evaluable` for every real Syntheseus route today — `reaction_smiles` carries no atom mapping, never faked into a pass. The [browser playground](https://kent-tokyo.github.io/renkin/playground/)'s Audit tab gained Syntheseus as a third format option. [5-minute walkthrough with real output →](https://kent-tokyo.github.io/renkin/guides/syntheseus-audit-demo/)
737
- - [x] **Audit Policy Profiles** (`--policy informational|standard|strict`, shipped v0.29.0) — *One set of findings. Three ways to derive the verdict.* Audit the same route under `informational`, `standard`, or `strict` policy without ever hiding or changing the underlying findings — policy only changes how the overall pass/fail/partial verdict is derived from findings already collected, recorded in `audit_manifest.policy`. Consistent across every surface: `renkin audit-route --policy`, the Rust API, the first Python binding for route auditing (`renkin.audit_route()`), and a new WASM `audit_route_v2()` (the existing `audit_route()` stays as a `standard`-policy wrapper). The [browser playground](https://kent-tokyo.github.io/renkin/playground/)'s Audit tab gained a policy selector.
738
- - [x] **Audit Playground** (`[ Audit a Route ]` tab, shipped v0.28.0) — *Audit a route in your browser — the same pipeline, the same verdict, zero network calls.* The [browser playground](https://kent-tokyo.github.io/renkin/playground/) now audits a RENKIN or AiZynthFinder route export (single-route or Pandas batch) and an optional stock list entirely client-side, via a new `audit_route` WASM export that calls the identical report-building pipeline `renkin audit-route` uses — the same pass/fail/partial verdict either way, not a separately-maintained copy. Paste or upload, run off the main thread, download the JSON report.
739
- - [x] **Reproducible Route Audit** (`audit_manifest` on `renkin audit-route --output json`, shipped v0.27.0) — *Reproduce what was audited, from which input, with which stock and policy.* Every audit report now records RENKIN version, report schema version, source format/version, input/stock content SHA-256 hashes, and audit policy — tested for byte-identical determinism (auditing the same input twice), not just claimed. Adds a shared adapter conformance suite across RENKIN-native and AiZynthFinder route inputs, plus a written [reproducibility/compatibility contract](https://kent-tokyo.github.io/renkin/guides/audit-reproducibility-contract/) (verified-vs-supported versions, unknown-field tolerance, report-schema rules, adapter-fixture runbook). The [browser playground](https://kent-tokyo.github.io/renkin/playground/) also got a safety/UX pass this release: search runs off the main thread with cancel/time-budget support, structure rendering stays local by default (no third-party SMILES transmission), and search settings round-trip exactly through Copy CLI/Python.
740
- - [x] **RENKIN Bridge — Cross-Tool Route Audit** (`renkin audit-route`, RENKIN-native adapter shipped v0.25.0, AiZynthFinder adapter shipped v0.26.0) — *Keep AiZynthFinder. Audit its routes with RENKIN.* A tool-neutral route audit model: structural-integrity, stock, and declared-reaction forward-replay validation, each reported independently as `pass`/`fail`/`not_evaluable`, rolled up into a route-level `pass`/`fail`/`partial` verdict — never a silently force-passed boolean. v0.26.0 adds a real AiZynthFinder adapter (single-target and gzip batch JSON, verified against captured v4.4.1 output — see [`PROVENANCE.md`](tests/fixtures/aizynthfinder/v4.4.1/PROVENANCE.md)) plus `--format auto` detection, so both tools' routes run through the exact same audit pipeline; auditing the real fixtures also surfaced and fixed a shared forward-replay bug where precursor ordering, not just chemistry, affected the verdict. `renkin audit-route route.json --stock stock.smi --output json` audits every route in a file and aggregates the results into one machine-readable report, regardless of which tool produced it.
741
- - [x] Coverage mode (`--search-mode coverage`, [#101](https://github.com/kent-tokyo/renkin/issues/101), shipped v0.24.0) — opt-in Stage-1/Stage-2 template-count escalation, addressing the candidate-generation coverage gap below. Confirmed by a one-shot 500-target formal-TEST (`data/coverage_mode_formal_test/protocol_v2.md`): coverage +6.0pp, net gain +30, zero regressions, zero reranker failures, Stage-2 timeout rate 0.25% — all against pre-registered thresholds. See the Key Features table above for the shipped surface
742
- - [x] Reranker made actually usable: Python exposure (`find_routes()`'s `reranker_model_path`/`reranker_freq_table_path`) and batteries-included model distribution (`scripts/fetch_reranker_model.py`, SHA-256-verified fetch from the v0.22.0 GitHub Release's canonical assets) ([#101](https://github.com/kent-tokyo/renkin/issues/101), shipped v0.23.0) — v0.22.0 proved the reranker works; v0.23.0 is the usability/distribution unlock, not a new accuracy claim
743
- - [x] LightGBM candidate reranker, trained/gated offline and wired into route search ([#101](https://github.com/kent-tokyo/renkin/issues/101) Task 35, CLI shipped v0.22.0) — LambdaMART model trained on real USPTO-50k labels, passed its VAL screening gate (top1 +11.7pp, MRR +11.3pp, top10 +9.3pp, bootstrap-CI-confirmed) and a formal 4,903-target TEST evaluation against the frozen model exactly once (top1 +12.7pp, MRR +11.9pp, top10 +9.1pp — consistent magnitude with VAL, no overfitting signal), then wired into `find_routes` as an ordering-only rank bonus and confirmed with a paired 100-target route-search gate: `route_to_configured_stock` 16→20/100 (+4/-0). See the Key Features table above
744
- - [x] Formal 500-target RENKIN vs AiZynthFinder comparison ([#66](https://github.com/kent-tokyo/renkin/issues/66)) — under a fixed 500-target sample, shared 393-compound stock, and each tool's configured policy/budget, RENKIN Conservative's `route_to_shared_stock` outcome was 9.8 percentage points higher than AiZynthFinder's (73/500 vs 24/500). This is a protocol-specific paired result, not a general search-capability superiority claim; native-mode configurations use unmatched stocks and are not directly comparable.
745
- - [x] Ring-context safety guard for extracted templates ([#72](https://github.com/kent-tokyo/renkin/issues/72)/[#242](https://github.com/kent-tokyo/renkin/pull/242)) — opt-in `--ring-context-policy`/`--ring-context-sidecar`, catches extracted templates silently misapplying a ring-opening/closing disconnection their training data never saw; default remains `disabled` (unchanged legacy behavior)
746
- - [x] `atom_economy` no longer silently clamped to 100% when a route's represented precursor set can't account for the target's full mass ([#79](https://github.com/kent-tokyo/renkin/issues/79)) — a new `atom_economy_status` field (`normal`/`above_expected_range`/`not_evaluable`) reports this explicitly instead
747
-
748
- ### In progress
749
-
750
- - [ ] Candidate-generation coverage gap — 33.0% (1,618/4,903) of the formal TEST corpus has zero positive candidates in-pool, a ceiling reranking cannot fix by construction. Template-diversity scaling remains a strong mechanism; a first provenance-bounded radius-zero abstraction track is now implemented and disjoint-VAL gated ([#240](https://github.com/kent-tokyo/renkin/issues/240)), but its 4/22 targeted residual recovery is not a full-corpus remeasurement or a shipped default
751
- - [ ] Template retrieval index (element bitmask + bond-center prefilter) for the 50k template set
752
- - [ ] Calibrated route confidence (map `success_probability` to empirical solve rate)
753
-
754
- ### Next
755
-
756
- - [x] Graph rule expansion — sulfonamide and carbamate cleavage (one PR per family, with structural and atom-accounting gates; carbamate shipped v0.61.0)
757
- - [x] Urea cleavage — validated atom-balanced disconnection to isocyanate + amine; implemented locally as the next-version candidate (not published)
758
- - [ ] Stock-aware planning (price / hazard / availability re-ranking)
759
- - [x] Deterministic policy-aware vendor-offer selection (price, lead time,
760
- availability) for exact private-stock matches
761
- - [x] Optional local hazard labels and blocked-hazard policy decisions
762
- - [x] Route-level stock score and deterministic multi-route ranking metadata
763
- - [x] Constraint DSL route-cost cap (`max_route_cost`) with explicit route-cost semantics
764
- - [x] Exact canonical building-block exclusion (`avoid_building_blocks`) for private/constrained stock policies
765
- - [x] Exact canonical building-block requirement (`require_building_blocks`) for house-stock policies
766
-
767
- <details>
768
- <summary>Earlier milestones</summary>
769
-
770
- Percentage figures below are historical milestones at the time each was
771
- shipped, not current performance — several predate the validator-accuracy
772
- fix noted in [Current Limitations](#current-limitations) and are invalidated;
773
- see [Benchmark](#benchmark) for the corrected historical baseline.
774
-
775
- - [x] Reranker made actually usable: Python exposure + batteries-included model distribution ([#101](https://github.com/kent-tokyo/renkin/issues/101), v0.23.0) — see "Recently shipped" above for the current-cycle summary; full detail in [`CHANGELOG.md`](CHANGELOG.md)
776
- - [x] Stable `template_id` (`rule:<name>` / `smirks-sha256:<hex>`) + `--template-metadata` evidence sidecar + `renkin template ids` ([#41](https://github.com/kent-tokyo/renkin/issues/41) phase 1)
777
- - [x] Substrate-specific `examples` (`schema_version: 2`) — per-step exact-substrate vs. same-template-different-substrate resolution, surfaced in `--format explain` and as `match_kind` in JSON ([#41](https://github.com/kent-tokyo/renkin/issues/41) phase 2)
778
- - [x] Deterministic ORD (Open Reaction Database) evidence import — offline `renkin evidence match` exact-set batch template matcher + `scripts/ord_evidence_audit.py` audit/converter into `schema_version: 2` sidecars ([#41](https://github.com/kent-tokyo/renkin/issues/41) phase 3A)
779
- - [x] RETROSPECT-inspired offline candidate-reranking foundation — candidate proposal/selection separation, feature schema v1, manifest v2, leakage-safe train/val/test splitting, baseline arms + trained-ranker arm, paired bootstrap + offline gate tooling ([#59](https://github.com/kent-tokyo/renkin/pull/59))
780
- - [x] `renkin-forward enumerate` — bounded, template-guided forward enumeration from a single known reactant plus an explicit partner library ([#64](https://github.com/kent-tokyo/renkin/issues/64))
781
- - [x] `renkin-forward hints` — partner-free retrieval hints (matched template slots, missing-partner SMARTS, bond deltas) for patent/database search, no concrete product predicted ([#64](https://github.com/kent-tokyo/renkin/issues/64) phase 2)
782
- - [x] `renkin-forward` CLI hardening — versioned `ForwardPredictionReport`, deterministic candidate IDs/merge/provenance, reactant-order-independent matching, strict CLI/route-JSON validation
783
- - [x] `apply_retro`/`run_reactants` performance regression resolved — `chematic` moved to the published `0.8.0` release (upstream automorphism-orbit-pruned canonicalization, [chematic#193](https://github.com/kent-tokyo/chematic/pull/193)); zero correctness change
784
- - [x] `renkin-bench cascade` — multi-stage search (fast defaults → hard cases re-run deeper); only unsolved targets propagate to later stages
785
- - [x] `renkin-bench --failure-taxonomy` — classify unsolved targets by cause (beam limit / depth limit / template gap / stock near-miss)
786
- - [x] Graph-based ester cleavage — BFS-leakage-free `R-C(=O)-O-R' → RCOOH + R'OH`
787
- - [x] `--top-templates N` — frequency-rank filter: use the top-N most frequent templates for speed / less noise
788
- - [x] `raw / validated / practical` solved-rate metrics (`--plausibility --practical-max-steps N`)
789
- - [x] Retro cache hit-rate in `SearchStats` + `--verbose`
790
- - [x] Route cost scoring — `route_cost` field + `--bb-prices path.csv` / `--stock stock.csv`
791
- - [x] Cargo workspace — `crates/renkin-forward/` + `crates/renkin-kg/`
792
- - [x] `renkin-forward predict` / `validate` — forward prediction + route validation (stdin-pipe friendly)
793
- - [x] `renkin-doctor` — environment diagnostic binary (templates, BBs, Python, binaries)
794
- - [x] Failure diagnostics — zero-route output includes `likely_causes` + `suggestions` JSON block
795
- - [x] `--format explain|compare|compare-json` — human-readable and tabular route output
796
- - [x] `renkin stock stats|validate|coverage|compile` — stock inspection plus integrity-checked compiled `.rstock` snapshots
797
- - [x] Pareto multi-objective search — `--format pareto`, `--objectives`, `find_pareto_routes` MCP
798
- - [x] Constraint DSL — `--constraints JSON`, `plan_with_constraints` MCP tool
799
- - [x] `renkin template stats|validate|dedup|explain|coverage` — template quality tools
800
- - [x] `renkin-kg` — reaction knowledge graph (bipartite mol↔reaction, GraphML/Cypher export)
801
- - [x] MCP server (`renkin-mcp`) — 7 tools with legacy `2024-11-05` and modern `2026-07-28` stdio protocol support
802
- - [x] Core search engine foundation — SMIRKS retro-reaction rules + fragment sanitization, A\*/AND-OR tree search with closed list + degenerate-route filter, SA Score heuristic + beam search, `rayon` parallel rule application (sequential fallback on WASM), FxHashMap/SmallVec beam frontier/SA-Score-memoization/`Arc<PathNode>` path-sharing perf work
803
- - [x] Multi-target packaging — Python bindings (PyO3 + maturin, `pip install renkin`), WASM build (`npm install renkin`), published to crates.io/PyPI/npm with GitHub Actions CI/CD, WASM browser playground + i18n (EN/JA/ZH)
804
- - [x] Benchmark CLI (`renkin-bench`) + USPTO-50k evaluation, `--format tree|mermaid` visualization, MkDocs documentation site + GitHub Pages playground
805
- - [x] Graph-based biaryl cleavage · O(1) canonical-SMILES BB index
806
- - [x] Tetrahedral stereo @/@@ + E/Z double-bond stereo
807
- - [x] NN template scorer via `--scorer` flag (tract-onnx, Pure Rust ONNX)
808
- - [x] Constraint-based search (`--avoid-elements`, `--require-elements`) + `--verbose` search statistics
809
- - [x] `#![forbid(unsafe_code)]` — compiler-enforced Pure Safe Rust from the start
810
-
811
- </details>
812
-
813
- ---
814
-
815
- ## Citation
816
-
817
- If you use RENKIN in academic work, please cite it — see [`CITATION.cff`](CITATION.cff)
818
- for the canonical, version-tracked citation record. GitHub's "Cite this
819
- repository" button (top of the repo page) reads it directly and can export
820
- APA or BibTeX on demand.
821
-
822
- ---
823
-
824
- ## Security
825
-
826
- Report vulnerabilities via [GitHub Private vulnerability reporting](https://github.com/kent-tokyo/renkin/security/advisories/new). See [SECURITY.md](SECURITY.md).
827
-
828
- ---
156
+ - stock identity is exact standardized canonical-SMILES membership;
157
+ - route success is not experimental success;
158
+ - external model output is evidence or candidates, not automatic validity;
159
+ - comparison manifests bind the tool, configuration, input files, and checked
160
+ worktree state so resumed runs cannot silently mix configurations;
161
+ - benchmark claims must name the dataset, stock, versions, and endpoint.
829
162
 
830
163
  ## License
831
164
 
832
- MIT
833
-
834
- ---
835
-
836
- *GitHub Topics: `retrosynthesis` `cheminformatics` `wasm` `rust` `drug-discovery` `casp` `synthesis-planning` `computational-chemistry`*
837
-
838
- ---
839
-
840
- If RENKIN saves you time, a GitHub star helps others discover it.
165
+ MIT. See [LICENSE](LICENSE).
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "kent-tokyo <kent-tokyo@users.noreply.github.com>"
6
6
  ],
7
7
  "description": "Ultra-fast retrosynthesis engine for computer-aided synthesis planning (CASP) — pure Rust, WASM-ready, Python bindings via PyO3",
8
- "version": "1.0.5",
8
+ "version": "1.0.7",
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",
package/renkin_bg.wasm CHANGED
Binary file