Rowan
Automate repetitive workflows and reduce manual effort
Example: Generate reports, summarize documents, draft communications
Save 3-5 hours per week on routine tasks
Learn new skills, understand complex topics, get expert guidance
Example: Explain concepts, provide examples, suggest learning resources
Accelerate learning and skill development by 2x
Enhance output quality through reviews, suggestions, and refinements
Example: Review drafts, suggest improvements, catch errors
Improve work quality by 30-40% with less effort
Time estimate: 15-45 minutes depending on use case complexity
Prerequisites
Submit your Claude Code skill and start earning
epx add K-Dense-AI/scientific-agent-skills --skill rowanCompatible with
Supported agents
name: "rowan"
description: "Rowan is a cloud-native molecular modeling and medicinal-chemistry workflow platform with a Python API. Use for pKa and macropKa prediction, conformer and tautomer ensembles, docking and analogue dock..."
| name | rowan |
| description | Rowan is a cloud-native molecular modeling and medicinal-chemistry workflow platform with a Python API. Use for pKa and macropKa prediction, conformer and tautomer ensembles, docking and analogue docking, protein-ligand cofolding, MSA generation, molecular dynamics, permeability, descriptor workflows, and related small-molecule or protein modeling tasks. Ideal for programmatic batch screening, multi-step chemistry pipelines, and workflows that would otherwise require maintaining local HPC/GPU infrastructure. |
| license | Proprietary (API key required) |
| compatibility | Python 3.12+, API key required |
| metadata | version: "1.1" skill-author: Rowan Science trigger-keywords: "pKa prediction, molecular docking, conformer search, chemistry workflow, drug discovery, SMILES, protein structure, batch molecular modeling, cloud chemistry" |
Rowan is a cloud-native workflow platform for molecular simulation, medicinal chemistry, and structure-based design. Its Python API exposes a unified interface for small-molecule modeling, property prediction, docking, molecular dynamics, and AI structure workflows.
Use Rowan when you want to run medicinal-chemistry or molecular-design workflows programmatically without maintaining local HPC infrastructure, GPU provisioning, or a collection of separate modeling tools. Rowan handles all infrastructure, result management, and computation scaling.
Rowan is a good fit for:
Rowan is not the right fit for:
Rowan uses a credit-based usage model. All users, including free-tier users, can create API keys and use the Python API.
Credits are consumed according to compute type:
Purchased credits are priced per credit and remain valid for up to one year from purchase.
| Workflow | Typical Runtime | Estimated Credits | Notes |
|---|---|---|---|
| Descriptors | <1 min | 0.5–2 | Lightweight, good for triage |
| pKa (single transition) | 2–5 min | 2–5 | Depends on molecule size |
| MacropKa (pH 0–14) | 5–15 min | 5–15 | Broader sampling, higher cost |
| Conformer search | 3–10 min | 3–10 | Ensemble quality matters |
| Tautomer search | 2–5 min | 2–5 | Heterocyclic systems |
| Docking (single ligand) | 5–20 min | 5–20 | Depends on pocket size, refinement |
| Analogue docking series (10–50 ligands) | 30–120 min | 30–100+ | Shared reference frame |
| MSA generation | 5–30 min | 5–30 | Sequence length dependent |
| Protein-ligand cofolding | 15–60 min | 20–50+ | AI structure prediction, GPU-heavy |
uv pip install rowan-python
import rowan
rowan.api_key = "your_api_key_here" # or set ROWAN_API_KEY env var
# Submit a descriptors workflow — completes in under a minute
wf = rowan.submit_descriptors_workflow("CC(=O)Oc1ccccc1C(=O)O", name="aspirin")
result = wf.result()
print(result.descriptors['MW']) # 180.16
print(result.descriptors['SLogP']) # 1.19
print(result.descriptors['TPSA']) # 59.44
If that prints without error, you're set up correctly.
uv pip install rowan-python
# or: pip install rowan-python
Set an API key via environment variable (recommended):
export ROWAN_API_KEY="your_api_key_here"
Or set directly in Python:
import rowan
rowan.api_key = "your_api_key_here"
Verify authentication:
import rowan
user = rowan.whoami() # Returns user info if authenticated
print(f"User: {user.email}")
print(f"Credits available: {user.credits_available_string}")
For webhook signature verification, manage secrets through your user account:
import rowan
# Get your current webhook secret (returns None if none exists)
secret = rowan.get_webhook_secret()
if secret is None:
secret = rowan.create_webhook_secret()
print(f"Secret key: {secret.secret}")
# Rotate your secret (invalidates old, creates new)
# Use this periodically for security
new_secret = rowan.rotate_webhook_secret()
print(f"New secret created (old secret disabled): {new_secret.secret}")
# Verify incoming webhook signatures
is_valid = rowan.verify_webhook_secret(
request_body=b"...", # Raw request body (bytes)
signature="X-Rowan-Signature", # From request header
secret=secret.secret
)
Rowan accepts molecules in the following formats:
"CCO", "c1ccccc1O""InChI=1S/C2H6O/c1-2-3/h3H,2H2,1H3"The API will validate input and raise a rowan.ValidationError if a molecule cannot be parsed. Always use canonicalized SMILES for reproducibility.
Tip: Use RDKit to validate SMILES before submission:
from rdkit import Chem
smiles = "CCO"
mol = Chem.MolFromSmiles(smiles)
if mol is None:
raise ValueError(f"Invalid SMILES: {smiles}")
Most Rowan tasks follow the same three-step pattern:
import rowan
# 1. Submit — use the specific workflow function (not the generic submit_workflow)
workflow = rowan.submit_descriptors_workflow(
"CC(=O)Oc1ccccc1C(=O)O",
name="aspirin descriptors",
)
# 2. & 3. Wait and retrieve
result = workflow.result() # Blocks until done (default: wait=True, poll_interval=5)
print(result.data) # Raw dict
print(result.descriptors['MW']) # 180.16 — use result.descriptors dict, not result.molecular_weight
For long-running workflows, use streaming:
for partial in workflow.stream_result(poll_interval=5):
print(f"Progress: {partial.complete}%")
print(partial.data)
| Pattern | Use When | Duration |
|---|---|---|
result() | You can wait for the full result | <5 min typical |
stream_result() | You want progress feedback or need early partial results | >5 min, or interactive use |
Guideline: Use result() for descriptors, pKa. Use stream_result() for conformer search, docking, cofolding.
Rowan's API includes typed workflow result objects with convenience properties.
Results have two access patterns:
result.descriptors, result.best_pose, result.conformer_energiesresult.data — raw dictionary from the APIExample:
result = rowan.submit_descriptors_workflow(
"CCO",
name="ethanol",
).result()
# Convenience property (returns dict of all descriptors):
print(result.descriptors['MW']) # 46.042
print(result.descriptors['SLogP']) # -0.001
print(result.descriptors['TPSA']) # 57.96
# Raw data fallback (descriptors are nested under 'descriptors' key):
print(result.data['descriptors'])
# {'MW': 46.042, 'SLogP': -0.001, 'TPSA': 57.96, 'nHBDon': 1.0, 'nHBAcc': 1.0, ...}
Note: DescriptorsResult does not have a molecular_weight property. Descriptor keys use short names (MW, SLogP, nHBDon) not verbose names.
Some result properties are lazily loaded (e.g., conformer geometries, protein structures). To refresh:
result.clear_cache()
new_structures = result.conformer_molecules # Refetched
For nontrivial campaigns, use projects and folders to keep work organized.
import rowan
# Create a project
project = rowan.create_project(name="CDK2 lead optimization")
rowan.set_project("CDK2 lead optimization")
# All subsequent workflows go into this project
wf = rowan.submit_descriptors_workflow("CCO", name="test compound")
# Retrieve later
project = rowan.retrieve_project("CDK2 lead optimization")
workflows = rowan.list_workflows(project=project, size=50)
# Create a hierarchical folder structure
folder = rowan.create_folder(name="docking/batch_1/screening")
wf = rowan.submit_docking_workflow(
# ... docking params ...
folder=folder,
name="compound_001",
)
# List workflows in a folder
results = rowan.list_workflows(folder=folder)
Use microscopic pKa when:
Use macropKa when:
Example decision:
Phenol (pKa ~10): Use microscopic pKa
Amine (pKa ~9–10): Use microscopic pKa
Multi-ionizable drug (N, O, acidic group): Use macropKa
ADME assessment across GI pH: Use macropKa
Use conformer search when:
Use tautomer search when:
Combined workflow:
# Step 1: Find best tautomer
taut_wf = rowan.submit_tautomer_search_workflow(
initial_molecule="O=c1[nH]ccnc1",
name="imidazole tautomers",
)
best_taut = taut_wf.result().best_tautomer
# Step 2: Generate conformers from best tautomer
conf_wf = rowan.submit_conformer_search_workflow(
initial_molecule=best_taut,
name="imidazole conformers",
)
| Workflow | Use When | Input | Output |
|---|---|---|---|
| Docking | Single ligand, known pocket | Protein + SMILES + pocket coords | Pose, score, dG |
| Analogue docking | 5–100+ related compounds | Protein + SMILES list + reference ligand | All poses, reference-aligned |
| Protein-ligand cofolding | Sequence + ligand, no crystal structure | Protein sequence + SMILES | ML-predicted bound complex |
A lightweight entry point for batch triage, SAR, or exploratory scripts.
wf = rowan.submit_descriptors_workflow(
"CC(=O)Oc1ccccc1C(=O)O", # positional arg, accepts SMILES string
name="aspirin descriptors",
)
result = wf.result()
print(result.descriptors['MW']) # 180.16
print(result.descriptors['SLogP']) # 1.19
print(result.descriptors['TPSA']) # 59.44
print(result.data['descriptors'])
# {'MW': 180.16, 'SLogP': 1.19, 'TPSA': 59.44, 'nHBDon': 1.0, 'nHBAcc': 4.0, ...}
Common descriptor keys:
| Key | Description | Typical drug range |
|---|---|---|
MW | Molecular weight (Da) | <500 (Lipinski) |
SLogP | Calculated LogP (lipophilicity) | -2 to +5 |
TPSA | Topological polar surface area (Ų) | <140 for oral bioavailability |
nHBDon | H-bond donor count | ≤5 (Lipinski) |
nHBAcc | H-bond acceptor count | ≤10 (Lipinski) |
nRot | Rotatable bond count | <10 for oral drugs |
nRing | Ring count | — |
nHeavyAtom | Heavy atom count | — |
FilterItLogS | Estimated aqueous solubility (LogS) | >-4 preferred |
Lipinski | Lipinski Ro5 pass (1.0) or fail (0.0) | — |
The result contains hundreds of additional molecular descriptors (BCUT, GETAWAY, WHIM, etc.); access any via result.descriptors['key'].
For protonation-state energetics and acid/base behavior of a specific structure.
Two methods are available:
| Method | Input | Speed | Covers | Use when |
|---|---|---|---|---|
chemprop_nevolianis2025 | SMILES string | Fast | Deprotonation only (anionic conjugate bases) | Acidic groups only; quick screening |
starling | SMILES string | Fast | Acid + base (full protonation/deprotonation) | Most drug-like molecules; preferred SMILES method |
aimnet2_wagen2024 (default) | 3D molecule object | Slower, higher accuracy | Acid + base | You already have a 3D structure (e.g. from conformer search) |
# Fast path: SMILES input with full acid+base coverage (use starling method when available)
wf = rowan.submit_pka_workflow(
initial_molecule="c1ccccc1O", # phenol SMILES; param is initial_molecule, not initial_smiles
method="starling", # fast SMILES method, covers acid+base; chemprop_nevolianis2025 is deprotonation-only
name="phenol pKa",
)
result = wf.result()
print(result.strongest_acid) # 9.81 (pKa of the most acidic site)
print(result.conjugate_bases) # list of {pka, smiles, atom_index, ...} per deprotonatable site
For pH-dependent protonation behavior across a range.
wf = rowan.submit_macropka_workflow(
initial_smiles="CN1CCN(CC1)C2=NC=NC3=CC=CC=C32", # imidazole
min_pH=0,
max_pH=14,
min_charge=-2, # default
max_charge=2, # default
compute_aqueous_solubility=True, # default
name="imidazole macropKa",
)
result = wf.result()
print(result.pka_values) # list of pKa values
print(result.logd_by_ph) # dict of {pH: logD}
print(result.aqueous_solubility_by_ph) # dict of {pH: solubility}
print(result.isoelectric_point) # isoelectric point
print(result.data)
# {'pKa_values': [...], 'logD_by_pH': {...}, 'aqueous_solubility_by_pH': {...}, ...}
For 3D ensemble generation when ensemble quality matters.
wf = rowan.submit_conformer_search_workflow(
initial_molecule="CCOC(=O)N1CCC(CC1)Oc1ncnc2ccccc12",
num_conformers=50, # Optional: override default
name="conformer search",
)
result = wf.result()
print(result.conformer_energies) # [0.0, 1.2, 2.5, ...]
print(result.conformer_molecules) # List of 3D molecules
print(result.best_conformer) # Lowest-energy conformer
For heterocycles and systems where tautomer state affects downstream modeling.
wf = rowan.submit_tautomer_search_workflow(
initial_molecule="O=c1[nH]ccnc1", # or keto tautomer
name="imidazolone tautomers",
)
result = wf.result()
print(result.best_tautomer) # Most stable SMILES string
print(result.tautomers) # List of tautomeric SMILES
print(result.molecules) # List of molecule objects
For protein-ligand docking with optional pose refinement and conformer generation.
# Upload protein once, reuse in multiple workflows
protein = rowan.upload_protein(
name="CDK2",
file_path="cdk2.pdb",
)
# Define binding pocket
pocket = {
"center": [10.5, 24.2, 31.8],
"size": [18.0, 18.0, 18.0],
}
# Submit docking
wf = rowan.submit_docking_workflow(
protein=protein,
pocket=pocket,
initial_molecule="CCNc1ncc(c(Nc2ccc(F)cc2)n1)-c1cccnc1",
do_pose_refinement=True,
do_conformer_search=True,
name="lead docking",
)
result = wf.result()
print(result.scores) # Docking scores (kcal/mol)
print(result.best_pose) # Mol object with 3D coordinates
print(result.data) # Raw result dict
Protein preparation tips:
rowan.create_protein_from_pdb_id() insteadFor placing a compound series into a shared binding context.
# Analogue series (e.g., SAR campaign)
analogues = [
"CCNc1ncc(c(Nc2ccc(F)cc2)n1)-c1cccnc1", # reference
"CCNc1ncc(c(Nc2ccc(Cl)cc2)n1)-c1cccnc1", # chloro
"CCNc1ncc(c(Nc2ccc(OC)cc2)n1)-c1cccnc1", # methoxy
"CCNc1ncc(c(Nc2cc(C)c(F)cc2)n1)-c1cccnc1", # methyl, fluoro
]
wf = rowan.submit_analogue_docking_workflow(
analogues=analogues,
initial_molecule=analogues[0], # Reference ligand
protein=protein,
pocket=pocket,
name="SAR series docking",
)
result = wf.result()
print(result.analogue_scores) # List of scores for each analogue
print(result.best_poses) # List of poses
For multiple-sequence alignment (useful for downstream cofolding).
wf = rowan.submit_msa_workflow(
initial_protein_sequences=[
"MENFQKVEKIGEGTYGVVYKARNKLTGEVVALKKIRLDTETEGVP"
],
output_formats=["colabfold", "chai", "boltz"],
name="target MSA",
)
result = wf.result()
result.download_files() # Downloads alignments to disk
For AI-based bound-complex prediction when no crystal structure is available.
wf = rowan.submit_protein_cofolding_workflow(
initial_protein_sequences=[
"MENFQKVEKIGEGTYGVVYKARNKLTGEVVALKKIRLDTETEGVP"
],
initial_smiles_list=[
"CCNc1ncc(c(Nc2ccc(F)cc2)n1)-c1cccnc1"
],
name="protein-ligand cofolding",
)
result = wf.result()
print(result.predictions) # List of predicted structures
print(result.messages) # Model metadata/warnings
predicted_structure = result.get_predicted_structure()
predicted_structure.write("predicted_complex.pdb")
All workflows follow the same submit → wait → retrieve pattern and support webhooks and project/folder organization.
| Workflow | Function | When to use |
|---|---|---|
| Descriptors | submit_descriptors_workflow | First-pass triage: MW, LogP, TPSA, HBA/HBD, Lipinski filter |
| pKa | submit_pka_workflow | Single ionizable group; need protonation thermodynamics |
| MacropKa | submit_macropka_workflow | Multi-ionizable drugs; pH-dependent charge/LogD/solubility |
| Conformer Search | submit_conformer_search_workflow | 3D ensemble for docking, MD, or SAR; known tautomer |
| Tautomer Search | submit_tautomer_search_workflow | Heterocycles, keto–enol; uncertain tautomeric form |
| Solubility | submit_solubility_workflow | Aqueous or solvent-specific solubility prediction |
| Membrane Permeability | submit_membrane_permeability_workflow | Caco-2, PAMPA, BBB, plasma permeability |
| ADMET | submit_admet_workflow | Broad drug-likeness and ADMET property sweep |
| Workflow | Function | When to use |
|---|---|---|
| Docking | submit_docking_workflow | Single ligand, known binding pocket |
| Analogue Docking | submit_analogue_docking_workflow | SAR series (5–100+ compounds) in a shared pocket |
| Batch Docking | submit_batch_docking_workflow | Fast library screening; large compound sets |
| Protein MD | submit_protein_md_workflow | Long-timescale dynamics; conformational sampling |
| Pose Analysis MD | submit_pose_analysis_md_workflow | MD refinement of a docking pose |
| Protein Cofolding | submit_protein_cofolding_workflow | No crystal structure; AI-predicted bound complex |
| Protein Binder Design | submit_protein_binder_design_workflow | De novo binder generation against a protein target |
| Workflow | Function | When to use |
|---|---|---|
| Basic Calculation | submit_basic_calculation_workflow | QM/ML geometry optimization or single-point energy |
| Electronic Properties | submit_electronic_properties_workflow | Dipole, partial charges, HOMO-LUMO, ESP |
| BDE | submit_bde_workflow | Bond dissociation energies; metabolic soft-spot prediction |
| Redox Potential | submit_redox_potential_workflow | Oxidation/reduction potentials |
| Spin States | submit_spin_states_workflow | Spin-state energy ordering for organometallics/radicals |
| Strain | submit_strain_workflow | Conformational strain relative to global minimum |
| Scan | submit_scan_workflow | PES scans; torsion profiles |
| Multistage Optimization | submit_multistage_opt_workflow | Progressive optimization across levels of theory |
| Workflow | Function | When to use |
|---|---|---|
| Double-Ended TS Search | submit_double_ended_ts_search_workflow | Transition state between two known structures |
| IRC | submit_irc_workflow | Confirm TS connectivity; intrinsic reaction coordinate |
| Workflow | Function | When to use |
|---|---|---|
| NMR | submit_nmr_workflow | Predicted 1H/13C chemical shifts for structure verification |
| Ion Mobility | submit_ion_mobility_workflow | Collision cross-section (CCS) for MS method development |
| Hydrogen Bond Strength | submit_hydrogen_bond_basicity_workflow | H-bond donor/acceptor strength for formulation/solubility |
| Fukui | submit_fukui_workflow | Site reactivity indices for electrophilic/nucleophilic attack |
| Interaction Energy Decomposition | submit_interaction_energy_decomposition_workflow | Fragment-level interaction analysis |
| Workflow | Function | When to use |
|---|---|---|
| RBFE/FEP | submit_relative_binding_free_energy_perturbation_workflow | Relative ΔΔG for congeneric series |
| RBFE Graph | submit_rbfe_graph_workflow | Build and optimize an RBFE perturbation network |
| Workflow | Function | When to use |
|---|---|---|
| MSA | submit_msa_workflow | Multiple sequence alignment for cofolding (ColabFold, Chai, Boltz) |
| Solvent-Dependent Conformers | submit_solvent_dependent_conformers_workflow | Solvation-aware conformer ensembles |
For libraries or analogue series, submit in a loop using the specific workflow function. The generic rowan.batch_submit_workflow() and rowan.submit_workflow() functions currently return 422 errors from the API — use the named functions (submit_descriptors_workflow, submit_pka_workflow, etc.) instead.
smileses = ["CCO", "CC(=O)O", "c1ccccc1O"]
names = ["ethanol", "acetic acid", "phenol"]
workflows = [
rowan.submit_descriptors_workflow(smi, name=name)
for smi, name in zip(smileses, names)
]
print(f"Submitted {len(workflows)} workflows")
statuses = rowan.batch_poll_status([wf.uuid for wf in workflows])
# Returns aggregate counts — not per-UUID:
# {'queued': 0, 'running': 1, 'complete': 2, 'failed': 0, 'total': 3, ...}
if statuses["complete"] == statuses["total"]:
print("All workflows done")
elif statuses["failed"] > 0:
print(f"{statuses['failed']} workflows failed")
results
AI-first code editor with Composer
Before installing skills in Cursor, ensure your development environment meets these requirements:
node --versionrowanExecute the skills CLI command in your project's root directory to begin installation:
epx add K-Dense-AI/scientific-agent-skills --skill rowanFetches rowan from K-Dense-AI/scientific-agent-skills and configures it for Cursor.
The CLI shows a list of agents. Use arrow keys and space to select Cursor:
Confirm successful installation by checking the skill directory location:
.cursor/skills/rowan
Restart Cursor to activate rowan. Access via /rowanin your agent's command palette.
Learn more:View source on GitHubSkills CLI docsAbout CursorWhat are agent skills?
Steps
Common Pitfalls
✓ Do
✗ Don't
💡 Pro Tips
✓ Use when
Use when skill capabilities match your task, clear ROI on time saved, and you can validate outputs. Best for repetitive tasks, learning, and quality improvement.
✗ Avoid when
Avoid when task requires deep expertise you can't validate, involves sensitive decisions, or when learning process is more valuable than speed of completion.
scientific-brainstorming
K-Dense-AI/scientific-agent-skills · Science · same repo
paper-lookup
K-Dense-AI/scientific-agent-skills · Science · same repo
latex-posters
K-Dense-AI/scientific-agent-skills · Science · same repo
database-lookup
K-Dense-AI/scientific-agent-skills · Science · same repo
sympy
K-Dense-AI/scientific-agent-skills · Science · same repo
biopython
K-Dense-AI/scientific-agent-skills · Science · same repo
Useful defaults in rowan — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
Registry listing for rowan matched our evaluation — installs cleanly and behaves as described in the markdown.
rowan reduced setup friction for our internal harness; good balance of opinion and flexibility.
We added rowan from the explainx registry; install was straightforward and the SKILL.md answered most questions upfront.
rowan fits our agent workflows well — practical, well scoped, and easy to wire into existing repos.
Solid pick for teams standardizing on skills: rowan is focused, and the summary matches what you get after install.
Useful defaults in rowan — fewer surprises than typical one-off scripts, and it plays nicely with `npx skills` flows.
Registry listing for rowan matched our evaluation — installs cleanly and behaves as described in the markdown.
We added rowan from the explainx registry; install was straightforward and the SKILL.md answered most questions upfront.
rowan is among the better-maintained entries we tried; worth keeping pinned for repeat workflows.
showing 1-10 of 69