1 line
165 KiB
JSON
1 line
165 KiB
JSON
{"repo": "atomflow-ai/molecode", "files": {"README.md": {"a4df3b04552b829ff816467b9620757a5dad765b": {"t": 1785747237.9117143, "n": 14395, "h": "72aa1f72300957a7", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\nOfficial repository for [**MoleCode unlocks structural intelligence in large language models**](https://arxiv.org/pdf/2605.16480).\n\n*Molecode presents molecules as code and enables LLMs to operate and reason on chemistry directly.*\n<br>*Instead of making language models reconstruct molecular structure from cryptic strings,*\n<br>*MoleCode lets them read, write, and edit directly on the structures.*\n\n[](https://arxiv.org/abs/2605.16480)\n[](https://arxiv.org/pdf/2605.16480)\n[](https://atomflow-ai.com/)\n[](https://github.com/AtomFlow-AI/MoleCode)\n<br>[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n<br>[](.claude/skills/molecode/)\n[](AGENTS.md)\n[](.claude/skills/molecode/SKILL.md)\n\n**English** | [中文](README.zh-CN.md)\n\n<br>\n<br>\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## Try our latest products on the official website!\nPlease visit the [AtomFlow website](https://atomflow-ai.com/).\n\n<p align=\"center\">\n <img src=\"docs/assets/demo_atomchat.png\" width=\"33%\" />\n <img src=\"docs/assets/demo_retro.png\" width=\"33%\" />\n <img src=\"docs/assets/demo_paper_read.png\" width=\"33%\" />\n</p>\n\n<br>\n \n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\npip install molecode # from PyPI — pulls in rdkit + networkx\n```\n\nOr from source (for the examples, the Agent Skill, and development):\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e .\n```\n\n> `pip install molecode` gives you the **library** (`molecode.molecule`,\n> `molecode.polymer`, `molecode.markush`, `molecode.prompts`, `molecode.llm`).\n> The runnable [`examples/`](examples) and the [Agent Skill](.claude/skills/molecode/)\n> live in the repository. Full API reference → [docs/api.md](docs/api.md).\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Works with your coding agent (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **[Agent Skill](https://docs.claude.com/en/docs/claude-code/skills)**,\nso coding agents can clone this repo and immediately reason over and edit\nmolecules at the explicit-graph level — no extra setup, no MCP server required.\n\n| Agent | How it picks MoleCode up |\n| --- | --- |\n| **Claude Code** | Auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/). Just ask it to understand or edit a molecule. |\n| **Codex** (and other agents) | Reads [`AGENTS.md`](AGENTS.md) at the repo root and uses the bundled CLI; interface metadata in [`agents/openai.yaml`](.claude/skills/molecode/agents/openai.yaml). |\n\nInstead of asking the model to hand-write SMILES — error-prone for anything\nnon-trivial — the skill has it **convert → inspect the named atoms/bonds → edit\nthe graph → validate**, all through one stable CLI:\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd # formula, counts, round-trip\npython .claude/skills/molecode/scripts/molecode_convert.py molecode-to-smiles --input edited.mmd\n```\n\nThe skill bundles the six conversion forms (SMILES / PSMILES / Markush ↔\nMoleCode) plus `validate`, `compare` (Markush-aware isomorphism) and `doctor`, a\nsyntax reference for hand-editing graphs, and a file-based edit workflow built\nfor large molecules. See [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\npython examples/08_image_to_molecode.py # OCSR: molecule image -> MoleCode (vision model)\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## About AtomFlow\n\nMoleCode is built and maintained by **[AtomFlow](https://atomflow-ai.com/)**.\n\nAtomFlow builds **LLM-native AI for chemistry** — letting language models operate\ndirectly on molecular structure rather than on opaque strings. Our work centers on\nmolecule-grounded applications, including:\n\n- **Molecular chat & interaction** — converse with a molecule; select atoms, bonds,\n or fragments and edit them in natural language.\n- **Structure-aware editing** — auditable, graph-level molecular edits.\n- **Retrosynthesis** — LLM-native synthesis planning over explicit structures.\n- **Literature reading & structure parsing** — extracting structures from papers\n and patents, including optical chemical structure recognition (OCSR).\n\nMoleCode is the open representation layer underneath these products — making\nmolecular structure explicit, editable, and auditable for LLMs.\n\n🌐 Learn more at **[atomflow-ai.com](https://atomflow-ai.com/)**.\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "b08803da710791e620ea70898835a59de5c4fa02": {"t": 1785771608.736666, "n": 14395, "h": "72aa1f72300957a7", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\nOfficial repository for [**MoleCode unlocks structural intelligence in large language models**](https://arxiv.org/pdf/2605.16480).\n\n*Molecode presents molecules as code and enables LLMs to operate and reason on chemistry directly.*\n<br>*Instead of making language models reconstruct molecular structure from cryptic strings,*\n<br>*MoleCode lets them read, write, and edit directly on the structures.*\n\n[](https://arxiv.org/abs/2605.16480)\n[](https://arxiv.org/pdf/2605.16480)\n[](https://atomflow-ai.com/)\n[](https://github.com/AtomFlow-AI/MoleCode)\n<br>[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n<br>[](.claude/skills/molecode/)\n[](AGENTS.md)\n[](.claude/skills/molecode/SKILL.md)\n\n**English** | [中文](README.zh-CN.md)\n\n<br>\n<br>\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## Try our latest products on the official website!\nPlease visit the [AtomFlow website](https://atomflow-ai.com/).\n\n<p align=\"center\">\n <img src=\"docs/assets/demo_atomchat.png\" width=\"33%\" />\n <img src=\"docs/assets/demo_retro.png\" width=\"33%\" />\n <img src=\"docs/assets/demo_paper_read.png\" width=\"33%\" />\n</p>\n\n<br>\n \n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\npip install molecode # from PyPI — pulls in rdkit + networkx\n```\n\nOr from source (for the examples, the Agent Skill, and development):\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e .\n```\n\n> `pip install molecode` gives you the **library** (`molecode.molecule`,\n> `molecode.polymer`, `molecode.markush`, `molecode.prompts`, `molecode.llm`).\n> The runnable [`examples/`](examples) and the [Agent Skill](.claude/skills/molecode/)\n> live in the repository. Full API reference → [docs/api.md](docs/api.md).\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Works with your coding agent (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **[Agent Skill](https://docs.claude.com/en/docs/claude-code/skills)**,\nso coding agents can clone this repo and immediately reason over and edit\nmolecules at the explicit-graph level — no extra setup, no MCP server required.\n\n| Agent | How it picks MoleCode up |\n| --- | --- |\n| **Claude Code** | Auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/). Just ask it to understand or edit a molecule. |\n| **Codex** (and other agents) | Reads [`AGENTS.md`](AGENTS.md) at the repo root and uses the bundled CLI; interface metadata in [`agents/openai.yaml`](.claude/skills/molecode/agents/openai.yaml). |\n\nInstead of asking the model to hand-write SMILES — error-prone for anything\nnon-trivial — the skill has it **convert → inspect the named atoms/bonds → edit\nthe graph → validate**, all through one stable CLI:\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd # formula, counts, round-trip\npython .claude/skills/molecode/scripts/molecode_convert.py molecode-to-smiles --input edited.mmd\n```\n\nThe skill bundles the six conversion forms (SMILES / PSMILES / Markush ↔\nMoleCode) plus `validate`, `compare` (Markush-aware isomorphism) and `doctor`, a\nsyntax reference for hand-editing graphs, and a file-based edit workflow built\nfor large molecules. See [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\npython examples/08_image_to_molecode.py # OCSR: molecule image -> MoleCode (vision model)\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## About AtomFlow\n\nMoleCode is built and maintained by **[AtomFlow](https://atomflow-ai.com/)**.\n\nAtomFlow builds **LLM-native AI for chemistry** — letting language models operate\ndirectly on molecular structure rather than on opaque strings. Our work centers on\nmolecule-grounded applications, including:\n\n- **Molecular chat & interaction** — converse with a molecule; select atoms, bonds,\n or fragments and edit them in natural language.\n- **Structure-aware editing** — auditable, graph-level molecular edits.\n- **Retrosynthesis** — LLM-native synthesis planning over explicit structures.\n- **Literature reading & structure parsing** — extracting structures from papers\n and patents, including optical chemical structure recognition (OCSR).\n\nMoleCode is the open representation layer underneath these products — making\nmolecular structure explicit, editable, and auditable for LLMs.\n\n🌐 Learn more at **[atomflow-ai.com](https://atomflow-ai.com/)**.\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "27a26519985dc0c3f379f055825361392bf7b881": {"t": 1785771610.0778072, "n": 13964, "h": "f1a8462ed8e3485c", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\nOfficial repository for [**MoleCode unlocks structural intelligence in large language models**](https://arxiv.org/pdf/2605.16480).\n\n*Molecode presents molecules as code and enables LLMs to operate and reason on chemistry directly.*\n<br>*Instead of making language models reconstruct molecular structure from cryptic strings,*\n<br>*MoleCode lets them read, write, and edit directly on the structures.*\n\n[](https://arxiv.org/abs/2605.16480)\n[](https://arxiv.org/pdf/2605.16480)\n[](https://atomflow-ai.com/)\n[](https://github.com/AtomFlow-AI/MoleCode)\n<br>[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n<br>[](.claude/skills/molecode/)\n[](AGENTS.md)\n[](.claude/skills/molecode/SKILL.md)\n\n**English** | [中文](README.zh-CN.md)\n\n<br>\n<br>\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## Try our latest products on the official website!\nPlease visit the [AtomFlow website](https://atomflow-ai.com/).\n\n<p align=\"center\">\n <img src=\"docs/assets/demo_atomchat.png\" width=\"33%\" />\n <img src=\"docs/assets/demo_retro.png\" width=\"33%\" />\n <img src=\"docs/assets/demo_paper_read.png\" width=\"33%\" />\n</p>\n\n<br>\n \n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Works with your coding agent (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **[Agent Skill](https://docs.claude.com/en/docs/claude-code/skills)**,\nso coding agents can clone this repo and immediately reason over and edit\nmolecules at the explicit-graph level — no extra setup, no MCP server required.\n\n| Agent | How it picks MoleCode up |\n| --- | --- |\n| **Claude Code** | Auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/). Just ask it to understand or edit a molecule. |\n| **Codex** (and other agents) | Reads [`AGENTS.md`](AGENTS.md) at the repo root and uses the bundled CLI; interface metadata in [`agents/openai.yaml`](.claude/skills/molecode/agents/openai.yaml). |\n\nInstead of asking the model to hand-write SMILES — error-prone for anything\nnon-trivial — the skill has it **convert → inspect the named atoms/bonds → edit\nthe graph → validate**, all through one stable CLI:\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd # formula, counts, round-trip\npython .claude/skills/molecode/scripts/molecode_convert.py molecode-to-smiles --input edited.mmd\n```\n\nThe skill bundles the six conversion forms (SMILES / PSMILES / Markush ↔\nMoleCode) plus `validate`, `compare` (Markush-aware isomorphism) and `doctor`, a\nsyntax reference for hand-editing graphs, and a file-based edit workflow built\nfor large molecules. See [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\npython examples/08_image_to_molecode.py # OCSR: molecule image -> MoleCode (vision model)\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## About AtomFlow\n\nMoleCode is built and maintained by **[AtomFlow](https://atomflow-ai.com/)**.\n\nAtomFlow builds **LLM-native AI for chemistry** — letting language models operate\ndirectly on molecular structure rather than on opaque strings. Our work centers on\nmolecule-grounded applications, including:\n\n- **Molecular chat & interaction** — converse with a molecule; select atoms, bonds,\n or fragments and edit them in natural language.\n- **Structure-aware editing** — auditable, graph-level molecular edits.\n- **Retrosynthesis** — LLM-native synthesis planning over explicit structures.\n- **Literature reading & structure parsing** — extracting structures from papers\n and patents, including optical chemical structure recognition (OCSR).\n\nMoleCode is the open representation layer underneath these products — making\nmolecular structure explicit, editable, and auditable for LLMs.\n\n🌐 Learn more at **[atomflow-ai.com](https://atomflow-ai.com/)**.\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "9313c566162a2e8edff900ba37e8a6150f09cfc9": {"t": 1785771611.7731187, "n": 13640, "h": "08ace5e4848a8c47", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\nOfficial repository for [**MoleCode unlocks structural intelligence in large language models**](https://arxiv.org/pdf/2605.16480).\n\n*Molecode presents molecules as code and enables LLMs to operate and reason on chemistry directly.*\n<br>*Instead of making language models reconstruct molecular structure from cryptic strings,*\n<br>*MoleCode lets them read, write, and edit directly on the structures.*\n\n[](https://arxiv.org/abs/2605.16480)\n[](https://arxiv.org/pdf/2605.16480)\n[](https://atomflow-ai.com/)\n[](https://github.com/AtomFlow-AI/MoleCode)\n<br>[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n<br>[](.claude/skills/molecode/)\n[](AGENTS.md)\n[](.claude/skills/molecode/SKILL.md)\n\n**English** | [中文](README.zh-CN.md)\n\n<br>\n<br>\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Works with your coding agent (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **[Agent Skill](https://docs.claude.com/en/docs/claude-code/skills)**,\nso coding agents can clone this repo and immediately reason over and edit\nmolecules at the explicit-graph level — no extra setup, no MCP server required.\n\n| Agent | How it picks MoleCode up |\n| --- | --- |\n| **Claude Code** | Auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/). Just ask it to understand or edit a molecule. |\n| **Codex** (and other agents) | Reads [`AGENTS.md`](AGENTS.md) at the repo root and uses the bundled CLI; interface metadata in [`agents/openai.yaml`](.claude/skills/molecode/agents/openai.yaml). |\n\nInstead of asking the model to hand-write SMILES — error-prone for anything\nnon-trivial — the skill has it **convert → inspect the named atoms/bonds → edit\nthe graph → validate**, all through one stable CLI:\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd # formula, counts, round-trip\npython .claude/skills/molecode/scripts/molecode_convert.py molecode-to-smiles --input edited.mmd\n```\n\nThe skill bundles the six conversion forms (SMILES / PSMILES / Markush ↔\nMoleCode) plus `validate`, `compare` (Markush-aware isomorphism) and `doctor`, a\nsyntax reference for hand-editing graphs, and a file-based edit workflow built\nfor large molecules. See [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\npython examples/08_image_to_molecode.py # OCSR: molecule image -> MoleCode (vision model)\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## About AtomFlow\n\nMoleCode is built and maintained by **[AtomFlow](https://atomflow-ai.com/)**.\n\nAtomFlow builds **LLM-native AI for chemistry** — letting language models operate\ndirectly on molecular structure rather than on opaque strings. Our work centers on\nmolecule-grounded applications, including:\n\n- **Molecular chat & interaction** — converse with a molecule; select atoms, bonds,\n or fragments and edit them in natural language.\n- **Structure-aware editing** — auditable, graph-level molecular edits.\n- **Retrosynthesis** — LLM-native synthesis planning over explicit structures.\n- **Literature reading & structure parsing** — extracting structures from papers\n and patents, including optical chemical structure recognition (OCSR).\n\nMoleCode is the open representation layer underneath these products — making\nmolecular structure explicit, editable, and auditable for LLMs.\n\n🌐 Learn more at **[atomflow-ai.com](https://atomflow-ai.com/)**.\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "e7859d2be8956a06a5394e0e76c4f05dd772bd38": {"t": 1785771613.7314856, "n": 13640, "h": "9a02af3bb63eca60", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\nOfficial repository for [**MoleCode unlocks structural intelligence in large language models**](https://arxiv.org/pdf/2605.16480).\n\n*Molecode presents molecules as code and enables LLMs to operate and reason on chemistry directly.*\n<br>*Instead of making language models reconstruct molecular structure from cryptic strings,*\n<br>*MoleCode lets them read, write, and edit on the structures directly.*\n\n[](https://arxiv.org/abs/2605.16480)\n[](https://arxiv.org/pdf/2605.16480)\n[](https://atomflow-ai.com/)\n[](https://github.com/AtomFlow-AI/MoleCode)\n<br>[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n<br>[](.claude/skills/molecode/)\n[](AGENTS.md)\n[](.claude/skills/molecode/SKILL.md)\n\n**English** | [中文](README.zh-CN.md)\n\n<br>\n<br>\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Works with your coding agent (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **[Agent Skill](https://docs.claude.com/en/docs/claude-code/skills)**,\nso coding agents can clone this repo and immediately reason over and edit\nmolecules at the explicit-graph level — no extra setup, no MCP server required.\n\n| Agent | How it picks MoleCode up |\n| --- | --- |\n| **Claude Code** | Auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/). Just ask it to understand or edit a molecule. |\n| **Codex** (and other agents) | Reads [`AGENTS.md`](AGENTS.md) at the repo root and uses the bundled CLI; interface metadata in [`agents/openai.yaml`](.claude/skills/molecode/agents/openai.yaml). |\n\nInstead of asking the model to hand-write SMILES — error-prone for anything\nnon-trivial — the skill has it **convert → inspect the named atoms/bonds → edit\nthe graph → validate**, all through one stable CLI:\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd # formula, counts, round-trip\npython .claude/skills/molecode/scripts/molecode_convert.py molecode-to-smiles --input edited.mmd\n```\n\nThe skill bundles the six conversion forms (SMILES / PSMILES / Markush ↔\nMoleCode) plus `validate`, `compare` (Markush-aware isomorphism) and `doctor`, a\nsyntax reference for hand-editing graphs, and a file-based edit workflow built\nfor large molecules. See [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\npython examples/08_image_to_molecode.py # OCSR: molecule image -> MoleCode (vision model)\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## About AtomFlow\n\nMoleCode is built and maintained by **[AtomFlow](https://atomflow-ai.com/)**.\n\nAtomFlow builds **LLM-native AI for chemistry** — letting language models operate\ndirectly on molecular structure rather than on opaque strings. Our work centers on\nmolecule-grounded applications, including:\n\n- **Molecular chat & interaction** — converse with a molecule; select atoms, bonds,\n or fragments and edit them in natural language.\n- **Structure-aware editing** — auditable, graph-level molecular edits.\n- **Retrosynthesis** — LLM-native synthesis planning over explicit structures.\n- **Literature reading & structure parsing** — extracting structures from papers\n and patents, including optical chemical structure recognition (OCSR).\n\nMoleCode is the open representation layer underneath these products — making\nmolecular structure explicit, editable, and auditable for LLMs.\n\n🌐 Learn more at **[atomflow-ai.com](https://atomflow-ai.com/)**.\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "977b14bdcabbeeaf9dcd85c92c6c21de8487ffef": {"t": 1785771614.9508228, "n": 13122, "h": "454ca2c193bde659", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\n**From molecular strings to structural code: enabling LLMs to operate on chemistry directly.**\n\n*Stop making language models reconstruct molecular structure from cryptic strings — let them read, write, and edit structure directly.*\n\n[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n[](https://atomflow-ai.com/)\n\n[](.claude/skills/molecode/)\n[](AGENTS.md)\n[](.claude/skills/molecode/SKILL.md)\n\n**English** | [中文](README.zh-CN.md)\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Works with your coding agent (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **[Agent Skill](https://docs.claude.com/en/docs/claude-code/skills)**,\nso coding agents can clone this repo and immediately reason over and edit\nmolecules at the explicit-graph level — no extra setup, no MCP server required.\n\n| Agent | How it picks MoleCode up |\n| --- | --- |\n| **Claude Code** | Auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/). Just ask it to understand or edit a molecule. |\n| **Codex** (and other agents) | Reads [`AGENTS.md`](AGENTS.md) at the repo root and uses the bundled CLI; interface metadata in [`agents/openai.yaml`](.claude/skills/molecode/agents/openai.yaml). |\n\nInstead of asking the model to hand-write SMILES — error-prone for anything\nnon-trivial — the skill has it **convert → inspect the named atoms/bonds → edit\nthe graph → validate**, all through one stable CLI:\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd # formula, counts, round-trip\npython .claude/skills/molecode/scripts/molecode_convert.py molecode-to-smiles --input edited.mmd\n```\n\nThe skill bundles the six conversion forms (SMILES / PSMILES / Markush ↔\nMoleCode) plus `validate`, `compare` (Markush-aware isomorphism) and `doctor`, a\nsyntax reference for hand-editing graphs, and a file-based edit workflow built\nfor large molecules. See [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\npython examples/08_image_to_molecode.py # OCSR: molecule image -> MoleCode (vision model)\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## About AtomFlow\n\nMoleCode is built and maintained by **[AtomFlow](https://atomflow-ai.com/)**.\n\nAtomFlow builds **LLM-native AI for chemistry** — letting language models operate\ndirectly on molecular structure rather than on opaque strings. Our work centers on\nmolecule-grounded applications, including:\n\n- **Molecular chat & interaction** — converse with a molecule; select atoms, bonds,\n or fragments and edit them in natural language.\n- **Structure-aware editing** — auditable, graph-level molecular edits.\n- **Retrosynthesis** — LLM-native synthesis planning over explicit structures.\n- **Literature reading & structure parsing** — extracting structures from papers\n and patents, including optical chemical structure recognition (OCSR).\n\nMoleCode is the open representation layer underneath these products — making\nmolecular structure explicit, editable, and auditable for LLMs.\n\n🌐 Learn more at **[atomflow-ai.com](https://atomflow-ai.com/)**.\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "ec4f25b1dfc2fc29e19e1026dd66315ee1166ac6": {"t": 1785771616.7349007, "n": 13033, "h": "07fb601c49f85a4e", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\n**From molecular strings to structural code: enabling LLMs to operate on chemistry directly.**\n\n*Stop making language models reconstruct molecular structure from cryptic strings — let them read, write, and edit structure directly.*\n\n[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n[](https://atomflow-ai.com/)\n\n[](.claude/skills/molecode/)\n[](AGENTS.md)\n[](.claude/skills/molecode/SKILL.md)\n\n**English** | [中文](README.zh-CN.md)\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Works with your coding agent (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **[Agent Skill](https://docs.claude.com/en/docs/claude-code/skills)**,\nso coding agents can clone this repo and immediately reason over and edit\nmolecules at the explicit-graph level — no extra setup, no MCP server required.\n\n| Agent | How it picks MoleCode up |\n| --- | --- |\n| **Claude Code** | Auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/). Just ask it to understand or edit a molecule. |\n| **Codex** (and other agents) | Reads [`AGENTS.md`](AGENTS.md) at the repo root and uses the bundled CLI; interface metadata in [`agents/openai.yaml`](.claude/skills/molecode/agents/openai.yaml). |\n\nInstead of asking the model to hand-write SMILES — error-prone for anything\nnon-trivial — the skill has it **convert → inspect the named atoms/bonds → edit\nthe graph → validate**, all through one stable CLI:\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd # formula, counts, round-trip\npython .claude/skills/molecode/scripts/molecode_convert.py molecode-to-smiles --input edited.mmd\n```\n\nThe skill bundles the six conversion forms (SMILES / PSMILES / Markush ↔\nMoleCode) plus `validate`, `compare` (Markush-aware isomorphism) and `doctor`, a\nsyntax reference for hand-editing graphs, and a file-based edit workflow built\nfor large molecules. See [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + egl_graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## About AtomFlow\n\nMoleCode is built and maintained by **[AtomFlow](https://atomflow-ai.com/)**.\n\nAtomFlow builds **LLM-native AI for chemistry** — letting language models operate\ndirectly on molecular structure rather than on opaque strings. Our work centers on\nmolecule-grounded applications, including:\n\n- **Molecular chat & interaction** — converse with a molecule; select atoms, bonds,\n or fragments and edit them in natural language.\n- **Structure-aware editing** — auditable, graph-level molecular edits.\n- **Retrosynthesis** — LLM-native synthesis planning over explicit structures.\n- **Literature reading & structure parsing** — extracting structures from papers\n and patents, including optical chemical structure recognition (OCSR).\n\nMoleCode is the open representation layer underneath these products — making\nmolecular structure explicit, editable, and auditable for LLMs.\n\n🌐 Learn more at **[atomflow-ai.com](https://atomflow-ai.com/)**.\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "2ff74351d23eb4d5596afb8279d2e7d40c43e746": {"t": 1785771618.179827, "n": 11973, "h": "019c7f61d2e1f579", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\n**From molecular strings to structural code: enabling LLMs to operate on chemistry directly.**\n\n*Stop making language models reconstruct molecular structure from cryptic strings — let them read, write, and edit structure directly.*\n\n[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n\n[](.claude/skills/molecode/)\n[](AGENTS.md)\n[](.claude/skills/molecode/SKILL.md)\n\n**English** | [中文](README.zh-CN.md)\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Works with your coding agent (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **[Agent Skill](https://docs.claude.com/en/docs/claude-code/skills)**,\nso coding agents can clone this repo and immediately reason over and edit\nmolecules at the explicit-graph level — no extra setup, no MCP server required.\n\n| Agent | How it picks MoleCode up |\n| --- | --- |\n| **Claude Code** | Auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/). Just ask it to understand or edit a molecule. |\n| **Codex** (and other agents) | Reads [`AGENTS.md`](AGENTS.md) at the repo root and uses the bundled CLI; interface metadata in [`agents/openai.yaml`](.claude/skills/molecode/agents/openai.yaml). |\n\nInstead of asking the model to hand-write SMILES — error-prone for anything\nnon-trivial — the skill has it **convert → inspect the named atoms/bonds → edit\nthe graph → validate**, all through one stable CLI:\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd # formula, counts, round-trip\npython .claude/skills/molecode/scripts/molecode_convert.py molecode-to-smiles --input edited.mmd\n```\n\nThe skill bundles the six conversion forms (SMILES / PSMILES / Markush ↔\nMoleCode) plus `validate`, `compare` (Markush-aware isomorphism) and `doctor`, a\nsyntax reference for hand-editing graphs, and a file-based edit workflow built\nfor large molecules. See [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + egl_graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "527b9167e82e8e5b42d50bc114ed2065a68eddce": {"t": 1785771622.7588048, "n": 11984, "h": "5a8c3822dac17f7c", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\n**From molecular strings to structural code: enabling LLMs to operate on chemistry directly.**\n\n*Stop making language models reconstruct molecular structure from cryptic strings — let them read, write, and edit structure directly.*\n\n[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n\n[](.claude/skills/molecode/)\n[](AGENTS.md)\n[](.claude/skills/molecode/SKILL.md)\n\n**English** | [中文](README.zh-CN.md)\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Works with your coding agent (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **[Agent Skill](https://docs.claude.com/en/docs/claude-code/skills)**,\nso coding agents can clone this repo and immediately reason over and edit\nmolecules at the explicit-graph level — no extra setup, no MCP server required.\n\n| Agent | How it picks MoleCode up |\n| --- | --- |\n| **Claude Code** | Auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/). Just ask it to understand or edit a molecule. |\n| **Codex** (and other agents) | Reads [`AGENTS.md`](AGENTS.md) at the repo root and uses the bundled CLI; interface metadata in [`agents/openai.yaml`](.claude/skills/molecode/agents/openai.yaml). |\n\nInstead of asking the model to hand-write SMILES — error-prone for anything\nnon-trivial — the skill has it **convert → inspect the named atoms/bonds → edit\nthe graph → validate**, all through one stable CLI:\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd # formula, counts, round-trip\npython .claude/skills/molecode/scripts/molecode_convert.py molecode-to-smiles --input edited.mmd\n```\n\nThe skill bundles the six conversion forms (SMILES / PSMILES / Markush ↔\nMoleCode) plus `validate`, `compare` (Markush-aware isomorphism) and `doctor`, a\nsyntax reference for hand-editing graphs, and a file-based edit workflow built\nfor large molecules. See [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"gpt-4o-mini\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + egl_graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "8bfcd3bfc497869abf39be41ee7df3a0487274f1": {"t": 1785771624.6772091, "n": 11947, "h": "3cb8eb9ad8e69030", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\n**From molecular strings to structural code: enabling LLMs to operate on chemistry directly.**\n\n*Stop making language models reconstruct molecular structure from cryptic strings — let them read, write, and edit structure directly.*\n\n[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n\n[](.claude/skills/molecode/)\n[](AGENTS.md)\n[](.claude/skills/molecode/SKILL.md)\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Works with your coding agent (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **[Agent Skill](https://docs.claude.com/en/docs/claude-code/skills)**,\nso coding agents can clone this repo and immediately reason over and edit\nmolecules at the explicit-graph level — no extra setup, no MCP server required.\n\n| Agent | How it picks MoleCode up |\n| --- | --- |\n| **Claude Code** | Auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/). Just ask it to understand or edit a molecule. |\n| **Codex** (and other agents) | Reads [`AGENTS.md`](AGENTS.md) at the repo root and uses the bundled CLI; interface metadata in [`agents/openai.yaml`](.claude/skills/molecode/agents/openai.yaml). |\n\nInstead of asking the model to hand-write SMILES — error-prone for anything\nnon-trivial — the skill has it **convert → inspect the named atoms/bonds → edit\nthe graph → validate**, all through one stable CLI:\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd # formula, counts, round-trip\npython .claude/skills/molecode/scripts/molecode_convert.py molecode-to-smiles --input edited.mmd\n```\n\nThe skill bundles the six conversion forms (SMILES / PSMILES / Markush ↔\nMoleCode) plus `validate`, `compare` (Markush-aware isomorphism) and `doctor`, a\nsyntax reference for hand-editing graphs, and a file-based edit workflow built\nfor large molecules. See [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"gpt-4o-mini\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + egl_graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "5e1bf177d3357caa715466d12a00463fe27b7189": {"t": 1785771627.3306477, "n": 10923, "h": "ebc360fab66c70c1", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\n**From molecular strings to structural code: enabling LLMs to operate on chemistry directly.**\n\n*Stop making language models reconstruct molecular structure from cryptic strings — let them read, write, and edit structure directly.*\n\n[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"gpt-4o-mini\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Use with coding agents (Claude Code · Codex)\n\nMoleCode ships as a ready-to-use **Agent Skill** so a coding agent can grab this\nrepo and immediately understand and edit molecules at the graph level:\n\n- **Claude Code** auto-discovers the skill at [`.claude/skills/molecode/`](.claude/skills/molecode/) —\n just ask it to understand or edit a molecule.\n- **Codex / other agents** read [`AGENTS.md`](AGENTS.md) and use the bundled CLI.\n\n```bash\npython .claude/skills/molecode/scripts/molecode_convert.py doctor\npython .claude/skills/molecode/scripts/molecode_convert.py smiles-to-molecode \"CCO\" --name Ethanol\npython .claude/skills/molecode/scripts/molecode_convert.py validate --input edited.mmd\n```\n\nThe skill bundles a stable CLI (the six conversion forms + `validate`/`compare`/\n`doctor`), a syntax reference for hand-editing graphs, and a file-based edit\nworkflow — see [`.claude/skills/molecode/SKILL.md`](.claude/skills/molecode/SKILL.md).\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + egl_graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\nAGENTS.md # entrypoint for coding agents\n.claude/skills/molecode/ # Agent Skill: SKILL.md + CLI + references (Claude Code / Codex)\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "970d5721ca9ed2f94624e139248bc1ae77f17f67": {"t": 1785771630.6211023, "n": 9830, "h": "fd2104f2fccc85a7", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\n**From molecular strings to structural code: enabling LLMs to operate on chemistry directly.**\n\n*Stop making language models reconstruct molecular structure from cryptic strings — let them read, write, and edit structure directly.*\n\n[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\n### Calling an LLM\n\nMoleCode is just a representation, so you can use **any** LLM SDK — the prompts\nare plain strings. For convenience the package also ships a tiny,\ndependency-free, **OpenAI-compatible** client (`molecode.llm.LLMClient`, built on\nstdlib `urllib`). You supply the API key and base URL — nothing is hard-coded, so\nit works with OpenAI, DeepSeek, Azure, Together, vLLM, Ollama, …\n\n```python\nfrom molecode import LLMClient\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT\nfrom molecode.molecule import mol_to_mermaid, mermaid_to_mol\nfrom rdkit import Chem\n\nclient = LLMClient(api_key=\"sk-...\", base_url=\"https://api.openai.com/v1\", model=\"gpt-4o-mini\")\n# (or set MOLECODE_API_KEY / MOLECODE_BASE_URL / MOLECODE_MODEL and call LLMClient())\n\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nreply = client.chat(f\"How many carbons are in this molecule?\\n```mermaid\\n{graph}\\n```\",\n system=MOLECULE_SYSTEM_PROMPT)\nprint(reply)\n```\n\nPrefer the official `openai` SDK? Pass the same prompt strings straight to\n`openai.OpenAI().chat.completions.create(...)` — you don't need `LLMClient` at all.\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + egl_graph isomorphism + abbreviation_map\n├── prompts/ # LLM system prompts (molecule + markush grammars)\n└── llm.py # optional OpenAI-compatible client (you supply key + base_url)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}, "2f04d49fed9ff7a32b0de59c372998295748fd63": {"t": 1785771632.867211, "n": 8486, "h": "9b1945a4806db16e", "c": "<div align=\"center\">\n\n# 🧬 MoleCode\n\n### An LLM-native, graph-explicit molecular language\n\n*Stop making language models reconstruct molecular structure from cryptic strings — let them read, write, and edit structure directly.*\n\n[](LICENSE)\n[](https://www.python.org/)\n[](https://www.rdkit.org/)\n\n<img src=\"docs/assets/overview.png\" alt=\"MoleCode overview\" width=\"100%\">\n\n</div>\n\n---\n\n## What is MoleCode?\n\nA molecule **is** a graph: atoms are nodes, bonds are edges, and chemistry emerges from the topology. Yet large language models are almost always fed molecules as *linear strings* like SMILES, where the graph is **implicit** — connectivity is positional, branches are syntactic, and rings hide inside index digits. Before an LLM can do any chemistry, it must first *reconstruct the graph from the syntax*, spending reasoning budget on structural bookkeeping.\n\n**MoleCode makes the structure the language.** Every atom and bond is written as a typed declaration with a persistent identifier, serialized as a [Mermaid](https://mermaid.js.org/) graph. Topology becomes directly readable, editable, and auditable inside the context window — and the format is **deterministically and losslessly inter-convertible with SMILES / MOL via RDKit** (no learned model, no information loss).\n\n```mermaid\ngraph TB\n subgraph chlorophenol[\"para-chlorophenol\"]\n chlorophenol_C_1[C]\n chlorophenol_O_1[OH]\n chlorophenol_C_2[CH]\n chlorophenol_C_3[CH]\n chlorophenol_C_4[C]\n chlorophenol_Cl_1[Cl]\n chlorophenol_C_5[CH]\n chlorophenol_C_6[CH]\n chlorophenol_C_1 === chlorophenol_C_2\n chlorophenol_C_2 --- chlorophenol_C_3\n chlorophenol_C_3 === chlorophenol_C_4\n chlorophenol_C_4 --- chlorophenol_C_5\n chlorophenol_C_5 === chlorophenol_C_6\n chlorophenol_C_6 --- chlorophenol_C_1\n chlorophenol_C_1 --- chlorophenol_O_1\n chlorophenol_C_4 --- chlorophenol_Cl_1\n end\n```\n\n> The same `Subgraph → Node → Edge` grammar covers **small molecules, polymers, and Markush structures** — and extends to reaction mechanisms and multimodal document parsing.\n\n---\n\n## Why it matters\n\n| | SMILES | **MoleCode** |\n| --- | --- | --- |\n| Topology | implicit, positional | **explicit, named nodes & edges** |\n| Atom identity | none | **persistent IDs** (stable across prompt → reasoning → output) |\n| Editing | whole-string rewrite | **local graph op** (add a methyl = 1 node + 1 edge) |\n| Validation | fragile string parsing | **deterministic RDKit round-trip** |\n| Reasoning behavior | memorizes syntax | **generalizes over structure** |\n\nEmpirically (see the [MoleCode paper](#-citation) and [docs/06-why-it-works.md](docs/06-why-it-works.md)):\n\n- **Generalization, not memorization.** SMILES accuracy collapses from ~42% on familiar molecules to ~20% on novel ones; MoleCode holds **~76–80%** across all familiarity tiers.\n- **Cheaper reasoning.** MoleCode has longer *input* but its chain-of-thought grows **sub-linearly** with molecule size (~C^0.52) versus SMILES' super-linear ~C^1.65 — about a **5× lower total token cost** per query.\n- **Scales to big, repetitive objects.** Full-chain SMILES accuracy falls toward **0%** as polymer chains grow; MoleCode stays flat.\n- **Markush understanding** jumps from **38.1% → 84.0%**.\n\n---\n\n## Install\n\n```bash\ngit clone https://github.com/AtomFlow-AI/MoleCode.git\ncd MoleCode\npip install -e . # installs rdkit + networkx\n```\n\n## Quick start\n\n```python\nfrom rdkit import Chem\nfrom molecode import mol_to_mermaid, mermaid_to_mol, mol_to_smiles\n\n# SMILES -> MoleCode graph\ngraph = mol_to_mermaid(Chem.MolFromSmiles(\"CC(=O)Oc1ccccc1C(=O)O\"), name=\"Aspirin\")\nprint(graph)\n\n# MoleCode graph -> SMILES (lossless round-trip)\nassert mol_to_smiles(mermaid_to_mol(graph)) == Chem.CanonSmiles(\"CC(=O)Oc1ccccc1C(=O)O\")\n```\n\n---\n\n## Three domains, one grammar\n\n### 🧪 Small molecules — [`molecode.molecule`](molecode/molecule)\n\nAtoms are `prefix_Element_Number[Label]` nodes; bonds are `---` (single), `===` (double), `-.-` (triple), with `===|E|`/`===|Z|` and `_R`/`_S` for stereochemistry. → [syntax reference](docs/02-syntax.md)\n\n### 🔗 Polymers — [`molecode.polymer`](molecode/polymer)\n\nThe repeat unit stays **explicit** as a subgraph carrying a symbolic `×n` count, with `TL`/`TR` terminus markers — so the graph does not blow up with chain length. → [polymer docs](docs/03-polymers.md)\n\n```python\nfrom molecode.polymer import polymer_to_mermaid, mermaid_to_psmiles\n\ngraph = polymer_to_mermaid(\"*NCCCCCC(=O)*\", n=8, name=\"Nylon-6\") # PSMILES -> graph\nmermaid_to_psmiles(graph) # -> '*NCCCCCC(=O)*'\n```\n\n### 🧩 Markush structures — [`molecode.markush`](molecode/markush)\n\nVariable R-groups and named substituents become **abbreviation nodes** in curly braces — `{R1}`, `{Boc}`, `{Ar}` — something plain SMILES cannot express. A built-in graph-isomorphism comparator scores predictions up to abbreviation expansion. → [Markush docs](docs/04-markush.md)\n\n```mermaid\ngraph TB\n subgraph Mol[\"molecule name\"]\n Mol_C_1[C]\n Mol_O_1[OH]\n Mol_X_1{Boc}\n Mol_X_2{R1}\n Mol_C_1 --- Mol_O_1\n Mol_C_1 --- Mol_X_1\n end\n```\n\n---\n\n## Run the tasks: understand · generate · edit · reason\n\nMoleCode is a **drop-in representation for any LLM** — feed the grammar as a system prompt, hand the model a graph, and validate its output deterministically. The [`examples/`](examples) folder has runnable scripts for all four task families (they run **offline by default**, printing the exact prompt; set `MOLECODE_API_KEY` to call a model):\n\n```bash\npython examples/01_molecule_roundtrip.py # SMILES <-> graph (lossless)\npython examples/02_polymer_roundtrip.py # polymers with ×n\npython examples/03_markush_roundtrip.py # abbreviation nodes & isomorphism\npython examples/04_understanding.py # count atoms / formula / rings ...\npython examples/05_generation.py # de novo design under constraints\npython examples/06_editing.py # local graph edits (add/del/substitute)\npython examples/07_reasoning.py # reaction-product prediction\n```\n\nThe reusable ingredients:\n\n```python\nfrom molecode.prompts import MOLECULE_SYSTEM_PROMPT # give this to the LLM as the system prompt\nfrom molecode.molecule import mol_to_mermaid # your molecule -> what the model reads\nfrom molecode.molecule import mermaid_to_mol # model output -> validated RDKit Mol\n```\n\nSee [docs/05-tasks.md](docs/05-tasks.md) for the full task catalog.\n\n| Domain | Understanding | Generation | Editing | Reasoning |\n| --- | :---: | :---: | :---: | :---: |\n| Molecules | ✅ | ✅ | ✅ | ✅ |\n| Polymers | ✅ | ✅ | ✅ | — |\n| Markush | ✅ | — | — | — |\n\n---\n\n## Repository layout\n\n```\nmolecode/ # the library (pip-installable)\n├── molecule/ # small-molecule <-> Mermaid (rdkit_to_mermaid, mermaid_to_rdkit)\n├── polymer/ # polymer <-> Mermaid (polymer_to_mermaid, mermaid_to_psmiles)\n├── markush/ # Markush <-> Mermaid + egl_graph isomorphism + abbreviation_map\n└── prompts/ # LLM system prompts (molecule + markush grammars)\nexamples/ # 7 runnable demos (round-trips + 4 task families)\ndocs/ # overview, syntax, polymers, markush, tasks, why-it-works\n```\n\n---\n\n## Results at a glance\n\n| Generalization & reasoning | Goal-directed design | Scaling | Long molecules | General language |\n| :---: | :---: | :---: | :---: | :---: |\n|  |  |  |  |  |\n\n---\n\n## 📚 Citation\n\nIf you use MoleCode in your research, please cite the MoleCode technical report:\n\n```bibtex\n@article{yan2026molecode,\n title={MoleCode unlocks structural intelligence in large language models},\n author={Yan, Zhiyuan and Liu, Chen and Zhao, Boxuan and Lin, Kaiqing and Zhao, Jixiang and Wang, Yimi and Lv, Liuzhenghao and Li, Hao and Zhang, Shanzhuo and Yuan, Li and others},\n journal={arXiv preprint arXiv:2605.16480},\n year={2026}\n}\n```\n\n## License\n\n[MIT](LICENSE) © 2026 AtomFlow-AI\n"}}}} |