Install any skill in seconds. Free to start, no credit card required.
Get Started Free →BRENDA Enzyme DB SOAP/REST queries: kinetic parameters (Km, Vmax, kcat, Ki), EC classes, substrate specificity, inhibitors, cofactors, organism data. 80K+ enzymes, 7M+ values. Free academic registration. For metabolic modeling use cobrapy-metabolic-modeling; metabolites use hmdb-database.
.claude/skills/jaechang-hits-brenda-database/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-01 | ✗→✓ | ▲ Improved | 166% | 0% |
| case-02 | ✗→✓ | ▲ Improved | 30% | 0% |
| case-03 | ✗→✓ | ▲ Improved | 30% | 0% |
| case-06 | ✗→✓ | ▲ Improved | 113% | 0% |
| case-15 | ✗→✓ | ▲ Improved | 182% | 0% |
BRENDA (BRaunschweig ENzyme DAtabase) is the world's most comprehensive enzyme information system, containing 80,000+ enzyme entries covering all classified enzymes (EC numbers). It holds 7M+ experimentally measured kinetic parameters (Km, Vmax, kcat, Ki, inhibition constants), substrate specificity data, cofactor requirements, tissue expression, and organism-specific enzyme variants from 200,000+ literature references. Programmatic access is via a SOAP-based web service (Python zeep library) with free academic registration.
cobrapy-metabolic-modeling; for metabolite structures use hmdb-databasezeep (SOAP client), pandas, requests1.1.1.1), enzyme names, or organism namesbashpip install zeep pandas requests # Register at https://www.brenda-enzymes.org/register.php to obtain API credentials
pythonfrom zeep import Client WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD_SHA256 = "your_sha256_hashed_password" # Use hashlib.sha256 # Get Km values for lactate dehydrogenase (EC 1.1.1.27) and pyruvate ec_number = "1.1.1.27" params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec_number}", "substrate*pyruvate", "", "", "", "", "") result = client.service.getKmValue(*params) print(f"Km values for LDH with pyruvate: {len(result)} records") for r in result[:3]: print(f" Km={r.kmValue} {r.kmValueMaximum or ''} mM | org: {r.organism} | PMID: {r.literature}")
Retrieve Michaelis constant (Km) values for a specific enzyme and substrate.
pythonfrom zeep import Client import hashlib, pandas as pd WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD = "your_password" PASSWORD_SHA256 = hashlib.sha256(PASSWORD.encode()).hexdigest() def get_km_values(ec_number, substrate=""): """Retrieve Km values for an EC number, optionally filtered by substrate.""" substrate_param = f"substrate*{substrate}" if substrate else "" params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec_number}", substrate_param, "", "", "", "", "") return client.service.getKmValue(*params) # Km for glucokinase (EC 2.7.1.2) with glucose results = get_km_values("2.7.1.2", substrate="glucose") print(f"Km (glucose, glucokinase): {len(results)} measurements") rows = [] for r in results[:10]: rows.append({ "km_value": r.kmValue, "km_max": r.kmValueMaximum, "unit": "mM", "organism": r.organism, "commentary": r.commentary[:80] if r.commentary else "", "pmid": r.literature, }) df = pd.DataFrame(rows) print(df.to_string(index=False))
python# Get ALL Km values (all substrates) for an EC number all_km = get_km_values("1.1.1.1") # Alcohol dehydrogenase print(f"\nAlcohol dehydrogenase - total Km records: {len(all_km)}") substrate_counts = {} for r in all_km: sub = r.substrate or "unknown" substrate_counts[sub] = substrate_counts.get(sub, 0) + 1 top_substrates = sorted(substrate_counts.items(), key=lambda x: -x[1])[:5] print("Top substrates by measurement count:") for sub, cnt in top_substrates: print(f" {sub}: {cnt} measurements")
Retrieve catalytic rate constants (kcat) for an enzyme.
pythonfrom zeep import Client import hashlib, pandas as pd WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD_SHA256 = hashlib.sha256("your_password".encode()).hexdigest() def get_kcat_values(ec_number, substrate=""): substrate_param = f"substrate*{substrate}" if substrate else "" params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec_number}", substrate_param, "", "", "", "", "") return client.service.getTurnoverNumber(*params) results = get_kcat_values("1.1.1.27") # Lactate dehydrogenase print(f"kcat records for LDH: {len(results)}") rows = [] for r in results[:10]: rows.append({ "kcat": r.turnoverNumber, "unit": "1/s", "substrate": r.substrate, "organism": r.organism, }) df = pd.DataFrame(rows) print(df.head())
Retrieve natural substrates and products for an enzyme.
pythonfrom zeep import Client import hashlib, pandas as pd WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD_SHA256 = hashlib.sha256("your_password".encode()).hexdigest() def get_substrates_products(ec_number): params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec_number}", "", "", "", "", "", "") return client.service.getSubstrates(*params) results = get_substrates_products("4.2.1.1") # Carbonic anhydrase print(f"Substrates for carbonic anhydrase (EC 4.2.1.1):") substrates_seen = set() for r in results[:10]: if r.substrate not in substrates_seen: print(f" {r.substrate} | organism: {r.organism}") substrates_seen.add(r.substrate)
python# Get inhibitors def get_inhibitors(ec_number): params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec_number}", "", "", "", "", "", "") return client.service.getInhibitors(*params) inhibitors = get_inhibitors("4.2.1.1") print(f"\nInhibitors of carbonic anhydrase: {len(inhibitors)} records") inhib_names = list(set(r.inhibitor for r in inhibitors if r.inhibitor)) print("Sample inhibitors:", inhib_names[:8])
Query kinetic parameters filtered by organism.
pythonfrom zeep import Client import hashlib WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD_SHA256 = hashlib.sha256("your_password".encode()).hexdigest() def get_km_by_organism(ec_number, organism): params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec_number}", "", f"organism*{organism}", "", "", "", "") return client.service.getKmValue(*params) # Human GAPDH Km values human_km = get_km_by_organism("1.2.1.12", "Homo sapiens") print(f"Human GAPDH (EC 1.2.1.12) Km values: {len(human_km)} records") for r in human_km[:5]: print(f" Substrate: {r.substrate:30s} Km={r.kmValue} mM")
Retrieve optimal pH and temperature data for an enzyme.
pythonfrom zeep import Client import hashlib WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD_SHA256 = hashlib.sha256("your_password".encode()).hexdigest() def get_ph_optimum(ec_number): params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec_number}", "", "", "", "", "", "") return client.service.getPhOptimum(*params) def get_temp_optimum(ec_number): params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec_number}", "", "", "", "", "", "") return client.service.getTemperatureOptimum(*params) ec = "3.4.21.4" # Trypsin ph_data = get_ph_optimum(ec) temp_data = get_temp_optimum(ec) print(f"Trypsin (EC {ec}):") ph_values = [r.phOptimum for r in ph_data[:10] if r.phOptimum] temp_values = [r.temperatureOptimum for r in temp_data[:10] if r.temperatureOptimum] if ph_values: print(f" pH optima: {sorted(ph_values)}") if temp_values: print(f" Temperature optima (°C): {sorted(temp_values)}")
Map EC numbers to UniProt accession numbers.
pythonfrom zeep import Client import hashlib WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD_SHA256 = hashlib.sha256("your_password".encode()).hexdigest() def get_uniprot_accessions(ec_number): params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec_number}", "", "", "", "", "", "") return client.service.getUniprotAccession(*params) results = get_uniprot_accessions("1.1.1.27") # LDH print(f"UniProt accessions for LDH (EC 1.1.1.27):") seen = set() for r in results[:10]: acc = r.uniprotAccessionNumber org = r.organism if acc and acc not in seen: print(f" {acc:12s} ({org})") seen.add(acc)
BRENDA uses SOAP (not REST) via a WSDL definition. The zeep Python library parses the WSDL and generates typed method calls. Authentication requires a SHA256-hashed password (not plain text). Each service method takes (email, password_sha256, param1, param2, ..., "") arguments with pipe-delimited field filters.
Enzyme Commission (EC) numbers follow the format X.X.X.X where each level specifies the reaction class (oxidoreductases=1, transferases=2, hydrolases=3, lyases=4, isomerases=5, ligases=6, translocases=7). BRENDA organizes all data by EC number.
Goal: For a set of enzymes in a metabolic pathway, extract Km and kcat values to parameterize a kinetic model.
pythonfrom zeep import Client import hashlib, pandas as pd, time WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD_SHA256 = hashlib.sha256("your_password".encode()).hexdigest() # Glycolysis enzymes enzymes = { "Hexokinase": "2.7.1.1", "Phosphoglucose isomerase": "5.3.1.9", "Phosphofructokinase": "2.7.1.11", "Aldolase": "4.1.2.13", } rows = [] for name, ec in enzymes.items(): params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec}", "", "organism*Homo sapiens", "", "", "", "") try: km_results = client.service.getKmValue(*params) kcat_results = client.service.getTurnoverNumber(*params) km_vals = [r.kmValue for r in km_results if r.kmValue] kcat_vals = [r.turnoverNumber for r in kcat_results if r.turnoverNumber] rows.append({ "enzyme": name, "ec": ec, "n_km_records": len(km_vals), "km_median_mM": pd.Series(km_vals).median() if km_vals else None, "n_kcat_records": len(kcat_vals), "kcat_median_1_s": pd.Series(kcat_vals).median() if kcat_vals else None, }) except Exception as e: rows.append({"enzyme": name, "ec": ec, "error": str(e)}) time.sleep(0.5) df = pd.DataFrame(rows) df.to_csv("glycolysis_kinetics.csv", index=False) print(df.to_string(index=False))
Goal: Compare inhibitor landscape across a set of related enzymes for drug discovery prioritization.
pythonfrom zeep import Client import hashlib, pandas as pd, time from collections import Counter WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD_SHA256 = hashlib.sha256("your_password".encode()).hexdigest() # Carbonic anhydrase isoforms ca_ecs = ["4.2.1.1"] # All carbonic anhydrases share this EC rows = [] for ec in ca_ecs: params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec}", "", "", "", "", "", "") try: inhib_results = client.service.getInhibitors(*params) for r in inhib_results[:30]: rows.append({ "ec": ec, "inhibitor": r.inhibitor, "organism": r.organism, "ic50": r.ic50Value if hasattr(r, "ic50Value") else None, }) except Exception as e: print(f"Error for {ec}: {e}") time.sleep(0.5) df = pd.DataFrame(rows) print(f"Total inhibitor records: {len(df)}") top_inhib = Counter(df["inhibitor"]).most_common(10) print("\nMost reported inhibitors:") for inhib, count in top_inhib: print(f" {inhib}: {count} records")
| Parameter | Module | Default | Range / Options | Effect | |-----------|--------|---------|-----------------|--------| | ecNumber* | All queries | required | EC number string | Filter by enzyme class | | substrate* | Km, kcat | — | substrate name | Filter by substrate | | organism* | All queries | — | species name | Filter by organism (e.g., "Homo sapiens") | | commentary* | All queries | — | text substring | Filter by comment text | | ligandStructureId* | Compound-based | — | BRENDA structure ID | Filter by ligand ID | | Password | Auth | required | SHA256 hash | Authentication (hashlib.sha256) |
hashlib.sha256("your_password".encode()).hexdigest().os.environ["BRENDA_EMAIL"] and os.environ["BRENDA_PASSWORD"] patterns.time.sleep() between queries: BRENDA's SOAP service may be slow; space large batch queries with 0.5–1 second sleeps to avoid timeouts.organism*Homo sapiens).When to use: Understand the substrate scope of an enzyme for pathway analysis.
pythonfrom zeep import Client import hashlib WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD_SHA256 = hashlib.sha256("your_password".encode()).hexdigest() ec = "1.1.1.1" # Alcohol dehydrogenase params = (EMAIL, PASSWORD_SHA256, f"ecNumber*{ec}", "", "", "", "", "", "") results = client.service.getSubstrates(*params) substrates = list(set(r.substrate for r in results if r.substrate)) print(f"Substrates of EC {ec} ({len(substrates)} unique): {substrates[:10]}")
When to use: Compute catalytic efficiency (kcat/Km) from BRENDA data.
pythonimport pandas as pd # After fetching km_results and kcat_results for same ec + substrate # km_values = [r.kmValue for r in km_results if r.kmValue] # mM # kcat_values = [r.turnoverNumber for r in kcat_results if r.turnoverNumber] # 1/s km_median = 0.1 # mM (example) kcat_median = 500 # s^-1 (example) efficiency = kcat_median / (km_median * 1e-3) # Convert Km to M print(f"Catalytic efficiency (kcat/Km): {efficiency:.2e} M^-1 s^-1") # Diffusion limit ≈ 10^8-10^9 M^-1 s^-1
When to use: Resolve enzyme common name to EC number for BRENDA queries.
pythonfrom zeep import Client import hashlib WSDL = "https://www.brenda-enzymes.org/soap/brenda_zeep.wsdl" client = Client(WSDL) EMAIL = "your@email.com" PASSWORD_SHA256 = hashlib.sha256("your_password".encode()).hexdigest() # Search enzymes by name params = (EMAIL, PASSWORD_SHA256, "recommendedName*lactate dehydrogenase", "", "", "", "", "", "") results = client.service.getEcNumber(*params) print(f"EC numbers for 'lactate dehydrogenase':") for r in results[:5]: print(f" EC {r.ecNumber}: {r.recommendedName}")
| Problem | Cause | Solution | |---------|-------|----------| | zeep.exceptions.Fault: Authentication failed | Wrong password or SHA256 format | Ensure hashlib.sha256(password.encode()).hexdigest() — hexdigest not digest | | Empty result list | EC number or substrate not found | Verify EC format (X.X.X.X with dots); try without substrate filter first | | SOAP timeout | Large query or slow connection | Use organism filter to reduce result set; set zeep transport timeout | | AttributeError on result field | Field not available for this query | Use getattr(r, "field", None) to safely access optional fields | | Slow response for popular enzymes | Large datasets (TP53 = 10K+ records) | Filter by organism and substrate to reduce data transfer | | zeep.exceptions.TransportError | Network connectivity issue | Check VPN, retry after 30 seconds |
cobrapy-metabolic-modeling — Constraint-based metabolic modeling using Km/Vmax from BRENDA as kinetic constraintshmdb-database — Metabolite structure and biological context for BRENDA substrateskegg-database — Pathway context for BRENDA enzymes via EC number cross-referencesuniprot-protein-database — Protein sequence and structure data for enzymes found in BRENDA| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-07 | fail→fail | 16,432 | 21,267 | +29% | 1 | 1 | 0% | 2,814 | 9,218 | +228% | 0 | 0 | — |
case-01 | fail→pass | 15,793 | 33,481 | +112% | 1 | 1 | 0% | 3,275 | 8,726 | +166% | 0 | 0 | — |
case-02 | fail→pass | 31,336 | 13,633 | -56% | 1 | 1 | 0% | 6,046 | 7,847 | +30% | 0 | 0 | — |
case-03 | fail→pass | 35,946 | 19,124 | -47% | 1 | 1 | 0% | 7,534 | 9,784 | +30% | 0 | 0 | — |
case-04 | pass→pass | 10,332 | 7,185 | -30% | 1 | 1 | 0% | 1,602 | 6,462 | +303% | 0 | 0 | — |
case-05 | pass→pass | 19,787 | 9,207 | -53% | 1 | 1 | 0% | 3,052 | 7,106 | +133% | 0 | 0 | — |
case-06 | fail→pass | 16,727 | 7,164 | -57% | 1 | 1 | 0% | 3,122 | 6,647 | +113% | 0 | 0 | — |
case-08 | pass→pass | 10,572 | 11,578 | +10% | 1 | 1 | 0% | 2,012 | 7,188 | +257% | 0 | 0 | — |
case-09 | pass→pass | 14,175 | 4,329 | -69% | 1 | 1 | 0% | 2,065 | 6,111 | +196% | 0 | 0 | — |
case-10 | pass→pass | 11,637 | 8,498 | -27% | 1 | 1 | 0% | 2,272 | 7,163 | +215% | 0 | 0 | — |
case-11 | pass→pass | 5,678 | 3,935 | -31% | 1 | 1 | 0% | 1,199 | 6,267 | +423% | 0 | 0 | — |
case-12 | fail→fail | 30,846 | 19,958 | -35% | 1 | 1 | 0% | 1,607 | 8,524 | +430% | 0 | 0 | — |
case-13 | fail→fail | 15,438 | 10,498 | -32% | 1 | 1 | 0% | 3,125 | 7,611 | +144% | 0 | 0 | — |
case-14 | pass→pass | 24,031 | 25,451 | +6% | 1 | 1 | 0% | 4,449 | 10,623 | +139% | 0 | 0 | — |
case-15 | fail→pass | 12,863 | 7,171 | -44% | 1 | 1 | 0% | 2,484 | 7,017 | +182% | 0 | 0 | — |
case-16 | fail→pass | 8,224 | 3,136 | -62% | 1 | 1 | 0% | 1,477 | 6,101 | +313% | 0 | 0 | — |
case-17 | fail→fail | 15,371 | 14,567 | -5% | 1 | 1 | 0% | 2,899 | 8,306 | +187% | 0 | 0 | — |
case-18 | fail→pass | 12,620 | 6,591 | -48% | 1 | 1 | 0% | 2,317 | 6,717 | +190% | 0 | 0 | — |
case-19 | pass→pass | 6,732 | 4,454 | -34% | 1 | 1 | 0% | 1,145 | 6,291 | +449% | 0 | 0 | — |
case-20 | fail→pass | 10,538 | 7,010 | -33% | 1 | 1 | 0% | 1,688 | 6,819 | +304% | 0 | 0 | — |
case-21 | pass→pass | 8,124 | 5,235 | -36% | 1 | 1 | 0% | 1,415 | 6,202 | +338% | 0 | 0 | — |
case-22 | pass→pass | 6,723 | 4,483 | -33% | 1 | 1 | 0% | 1,218 | 6,284 | +416% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted, and 21 counted toward the lift figure. The other 1 produced results that are not comparable between the two arms, so they are excluded from the headline rather than averaged into it. The headline lift of +36 percentage points is the difference between those two pass rates over the 21 comparable cases. 1 case got worse with the skill loaded, and it is included in that figure.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.