Building chemscii: Enabling Text-Based Chemical Structure Rendering With Claude
Published:
Introduction
Will this be useful? Maybe? Was it a fun exercise? Absolutely!
In this post we explore (a) adding text-based chemical structure rendering to Claude and (b) using Claude Code as a development tool for a simple cheminformatics project. The result is chemscii, a Python package that renders molecular structures as ASCII art.
The goal was to build something fun and see how Claude Code handled a cheminformatics workflow: parsing chemical inputs, generating 2D coordinates, and producing clean visual output.
The chemscii Project Idea
The concept is simple: take a chemical identifier (SMILES string, compound name, or ChEMBL ID) and render it as text in your terminal. No GUI applications, no image files, just pure ASCII art chemistry.
Core requirements:
- Multiple input formats: SMILES strings, IUPAC names, ChEMBL IDs
- 2D coordinate generation: Use RDKit to compute molecular layouts
- Text-based rendering: Map bonds and atoms to terminal characters
- CLI interface: Make it easy to use from the command line
- Claude Code integration: Enable use as a custom tool within Claude
The technical challenge? Molecular structures exist in continuous 2D space, but terminals are discrete grids. You need to map floating-point coordinates to character positions while preserving chemical topology. Plus, you want it to look decent.
Development: Micromanaging Claude
Rather than giving Claude free reign, I took a structured, iterative approach. First, I wrote a CLAUDE.md file to give persistent, project-specific context and instructions.
# chemscii development
## general guidelines
YOU MUST follow Python best practices and modern development standards. It is IMPORTANT to NOT DEVIATE from these principles:
1. YOU MUST use conda for virtual environment management
2. YOU MUST use poetry for python dependency management
3. YOU MUST write unit tests for all modules
4. YOU MUST use CI/CD (GitHub Actions) with pytest (unit testing), black (formatting), ruff (linting), and optionally mypy (type checking)
5. YOU MUST use type hints for all code
6. YOU MUST otherwise follow google code and docstring conventions
7. YOU MUST write code that is minimal, simple, reusable, and easy to understand
## project scope
YOU MUST focus entirely on building a python package for rendering chemical structures as ASCII/Unicode art, optimized for text-based environments.
With the project context in place, I asked Claude to geneate a preliminary project tree structure, which I edited. Then I asked Claude to generate initial python module stubs (methods, inputs, and descriptions but no implementation). Again, I edited the stubs to match my desired schema. The tree structure was something like the following:
chemscii/
├── src/
│ └── chemscii/
│ ├── __init__.py
│ ├── parsers/ # Input format parsers
│ │ ├── __init__.py
│ │ ├── molecule.py # SMILES and SDF formats
│ │ ├── name.py # Molecule name to SMILES
│ │ └── chembl.py # ChEMBL ID to SMILES
│ ├── layout/ # 2D coordinate generation
│ │ ├── __init__.py
│ │ ├── atoms.py # Atoms
│ │ └── bonds.py # Bonds
│ ├── renderers/ # Text rendering engines
│ │ ├── __init__.py
│ │ ├── base.py # Base renderer
│ │ ├── ascii.py # Basic ASCII renderer
│ │ └── unicode.py # Basic Unicode renderer
│ └── cli.py # Command-line interface built with rich
├── tests/
│ ├── __init__.py
│ ├── test_parsers.py
│ ├── test_layout.py
│ ├── test_renderers.py
│ └── fixtures/ # Test molecule SMILES and SDF
└── examples/
└── basic_usage.ipynb
Next, I asked Claude to generate the package conda environment.yml, poetry pyproject.toml, installation instructions, initial test fixtures, precommit hooks, and CI/CD (GitHub Actions). I was specific about the desired dependencies and workflow, so the resulting infrastructure only needed minor modifications. With the foundation in place, I proceeded to ask claude to generate each module and inspected / edited the generated output. Following this approach the initial chemscii command line tool was quickly developed.
CLI Example:
chemscii colchicine
O
C-- ==
-C
|
|
|
N
/C /
/ \\ /
C/ C
| |
| |
| |
C===C C===C
C | \ / \
\ | \ / \ ==O
\ | C---C C=
O---C = = |
= = = |
= --C C =C
C- \ \\ = \ C
| \ C= \ //
| O O
| /
C---O /
/
Wow! The development was smooth and with a little debugging the initial prototype worked! But to be honest, when I first saw this rendering, I laughed out loud both because I was excited by how quickly I had a prototype and because it looked so comically bad.
One surprise: Claude Code handled RDKit reasonably well. It knew to use AllChem.Compute2DCoords() for layout and understood molecular graph traversal. However, the initial result needed some polishing. So I added options to make sure structures were Kekulized, set preferred coordinates, and use ring templates to improve the chemical structure rendering. In addition, to improve the general aesthetics I manually added an image to ASCII rendering approach using ascii-magic.
CLI Example:
chemscii colchicine

Claude Code Integration
After building the CLI the next step was to explore Claude Code integrations. I started with the simple CLAUDE.md approach. Claude Code automatically reads CLAUDE.md files in your project directory. These files provide context and instructions that guide Claude’s behavior when working in that directory. The example file and more detailed instructions can be found in the chemscii repository.

This approach is the simplest: anyone who installs chemscii and copies CLAUDE.md can immediately use the integration with zero configuration. However, this approach is limited because it is directory scoped and Claude does not have direct access the CLI parameters. In addition, if we wanted to configure multiple tools it may become cumbersome to specify and manage them in a single markdown file.
Claude also supports model context protocol (MCP) servers. To build a chemscii MCP server the mcp package was used to configure a FastMCP server that exposes a render_molecule tool that Claude can call to render chemical structures without needing CLI instructions. Unlike the CLAUDE.md approach, MCP integration work globally (not directory-scoped), provides a structured tool interface (e.g., allows us to manage tools via the claude CLI or by editing ~/.claude.json), and gives Claude direct access to rendering parameters. To streamline integration, I added a --mcp argument to the chemscii CLI. Now by installing chemscii and including the below lines in your ~/.claude.json you can have text-based chemical strucutre rendering in Claude Code.
"mcpServers": {
"chemscii": {
"command": "chemscii",
"type": "stdio",
"args": [
"--mcp"
]
}
}
For detailed installation and usage instructions see the example.
Conclustion
Key learnings from this project:
- For a weekend project, Claude Code accelerated development significantly. I spent more time designing and less time typing.
- Having unit tests, pre-commit hooks, and CI/CD configured first allowed pretty clean development. The initial protype didn’t work but could be quickly debugged and improved.
- The current stdio-based MCP integration in Claude provides limited support for rendering ANSI color codes. Unfortunately at the moment this means the
chemsciiMCP server does not provide the same color rendering as the CLI. - Having ASCII chemistry in my terminal is unexpectedly entertaining.
Check out chemscii on GitHub or install with pip install chemscii.
