BY Causal Reasoning Skill
Most "AI scientist" demos fake reasoning by chaining LLM calls and calling the chain a hypothesis. This skill does the opposite: it constrains the LLM with structured evidence retrieved from the BY knowledge graph and forces every claim to cite an existing entity with a defined evidence tier. The output is a short, ranked list of mechanistic hypotheses — each one falsifiable, each one traceable to a campaign, paper, or prior failure record.
It sits between statistical diagnosis (which says which features discriminate PASS from FAIL) and campaign optimization (which spends new compute). Without this step, the optimizer can only tweak thresholds; with it, the optimizer can target the underlying mechanism.
When to Use This Skill
Use this skill when:
- ✅
by-failure-diagnosishas produced a discriminating-features ranking and you need to translate statistical signals into mechanistic claims before the next round. - ✅
by-epitope-analysisis available so structural context (topology, hotspot residues, druggability) can be merged with statistical signals. - ✅ You are about to call
by-campaign-optimizerfor round N+1 — the optimizer's parameter changes should target a named mechanism, not a vibe. - ✅ A campaign shows an unexpected (non-trivial) pattern — e.g. high ipSAE designs are failing at the lab stage, or pass rate dropped vs the prior round with no parameter change.
- ✅ The user explicitly asks "why are my designs failing at this mechanism?", "what's the underlying cause?", or "rank possible explanations".
- ✅ You have access to
by-knowledgedata — querying without a populated graph yields hypotheses with no evidence, which violates the skill contract.
Do NOT use this skill when:
- ❌ As a substitute for actually running experiments. Hypotheses are pointers to experiments, not conclusions. If the user asks "is this the cause?", the answer is "the falsifiable prediction is X — run that assay to confirm", not "yes".
- ❌ Without evidence citations. Every claim must reference at least one knowledge-graph entity (
campaign_<id>orfailure_<id>). A "hypothesis" with no evidence is a guess — flag it as SPECULATIVE or refuse to emit it. - ❌ To generate more than 5 hypotheses. Parsimony is enforced: 3-5 is the cap. More than 5 means the agent is laundering uncertainty as breadth. If the diagnosis genuinely supports more candidates, that is a signal to call
by-hypothesis-debatefor adversarial pruning, not to inflate the list. - ❌ For per-residue redesign rationale. That is structural, not statistical — use
by-epitope-analysisinstead. - ❌ When the campaign has fewer than 30 scored designs. Statistical signals are too noisy; the hypotheses will not be reliably evidenced.
- ❌ For pre-campaign target selection. That is
by-researchterritory; this skill explains past failures, not future opportunities. - ❌ When the knowledge graph is empty (0 campaigns, 0 failures recorded). The skill cannot ground hypotheses in evidence — refuse to run, ask user to populate
by-knowledgefirst.
Quick Start
Typical invocation: feed the diagnosis + epitope outputs from a campaign,
let the skill query by-knowledge for evidence, and emit ranked hypotheses.
python3 scripts/generate_hypotheses.py \
--diagnosis campaigns/tnf/run01/diagnosis.json \
--epitope campaigns/tnf/run01/hotspots.json \
--target "TNF-alpha" \
--modality "VHH" \
--max-hypotheses 4 \
--out campaigns/tnf/run01/hypotheses.json \
--trail campaigns/tnf/run01/evidence_trail.md
Expected console output:
✓ Loaded diagnosis: 9 features tested, 3 significant
✓ Loaded epitope: 6 hotspots, topology=flat, druggability=moderate
✓ Queried knowledge graph: 12 similar campaigns, 4 matching failures
✓ Generated 4 hypotheses (1 HIGH, 2 MEDIUM, 1 SPECULATIVE)
✓ Wrote campaigns/tnf/run01/hypotheses.json
✓ Wrote campaigns/tnf/run01/evidence_trail.md
The resulting hypotheses.json is a JSON array of at most 5 ordered
hypotheses; each carries claim text, supporting + contradicting evidence with
entity IDs, a confidence label, and a falsifiable prediction.
To validate hypotheses after generation (verify every cited entity exists in the graph and the evidence tier was assigned correctly):
python3 scripts/score_hypothesis_evidence.py \
--hypotheses campaigns/tnf/run01/hypotheses.json \
--out campaigns/tnf/run01/hypotheses_scored.json
Installation
| Software | Version | License | Commercial Use | Installation Command |
|---|---|---|---|---|
| Python | ≥3.10 | PSF | ✅ Permitted | preinstalled |
mcp SDK |
≥1.0 | MIT | ✅ Permitted | pip install mcp |
pydantic (optional, schema validation) |
≥2.0 | MIT | ✅ Permitted | pip install pydantic |
jsonschema (optional, output validation) |
≥4.0 | MIT | ✅ Permitted | pip install jsonschema |
License Compliance: All packages permit commercial use in AI applications.
System requirements: No GPU, no internet. The skill is CPU-only and reads
from the locally persisted by-knowledge JSON store. Runtime is under a few
seconds for thousands of recorded campaigns.
Dependencies on other BY services: The by-knowledge MCP server must be
running for the generation script's evidence retrieval to work. If it is not,
generate_hypotheses.py falls back to a stub-data mode (clearly labeled in
the output) — but in stub mode the hypotheses are NOT evidence-grounded and
must be flagged SPECULATIVE before passing to any downstream skill.
Inputs
Required:
- Diagnosis output (
diagnosis.jsonfromby-failure-diagnosis):total_designs,passed,failed,pass_ratediscriminating_features[]— feature names sorted by adjusted p-value- Each feature must include
effect_size,passed_mean,failed_mean
- Target name (string) — used as the keyword anchor for
by-knowledgequeries - Modality — one of
antibody,nanobody,VHH,scFv,de_novo,binder - Access to
by-knowledge— the MCP server must be reachable, OR a local copy ofcampaigns.json+failures.jsonmust be passed via--knowledge-dir
Strongly recommended:
- Epitope output (
hotspots.jsonfromby-epitope-analysis):- Provides structural context:
topology,druggability, hotspot residue list - Without this, structural hypotheses (steric, electrostatic, aggregation) cannot be evidenced from the interface geometry
- Provides structural context:
Optional:
- Lab results (
experiment_results.jsonfromby-experiment-results, when available):- Real-world calibration: which designs that passed in-silico screening also passed (or failed) at the bench
- Lets the skill distinguish "the metric is wrong" from "the metric is right but the mechanism is missed"
- Prior hypothesis files — earlier rounds'
hypotheses.jsonto detect repeated mechanisms (the optimizer should already have addressed them) --max-hypotheses— hard cap, default 4, never above 5 (parsimony enforced)--include-speculative— include Tier 3 evidence claims (default off; require user opt-in)
See references/failure-mechanisms-catalog.md for the canonical mechanism set and which inputs each mechanism requires.
Outputs
All outputs are written to the campaign directory at
campaigns/<target>/<campaign_id>/:
| File | Format | Purpose |
|---|---|---|
hypotheses.json |
JSON array | Ranked hypotheses with evidence citations (downstream contract) |
evidence_trail.md |
Markdown | Human-readable narrative: queries run, evidence retrieved, contradictions flagged |
hypotheses_scored.json |
JSON array | Validation artifact from score_hypothesis_evidence.py (annotated evidence tiers) |
hypotheses.json schema (downstream-critical)
Each entry has exactly these fields:
| Field | Type | Description |
|---|---|---|
rank |
int | 1-indexed, sorted by confidence desc, then evidence count desc |
claim |
string | Single-sentence mechanistic statement (NOT a correlation) |
mechanism |
string | Canonical name from the catalog (e.g. hydrophobic_aggregation, steric_clash) |
confidence |
enum | HIGH / MEDIUM / SPECULATIVE (matches BY taxonomy) |
supporting_evidence |
array | One or more {entity_id, type, claim_relation, weight} records |
contradicting_evidence |
array | Same shape, may be empty; non-empty triggers confidence downgrade |
falsifiable_prediction |
string | The next experiment that would confirm or refute |
recommended_next_action |
string | Skill to call next (e.g. by-hypothesis-debate, by-campaign-optimizer) |
Full JSON Schema in references/hypothesis-output-schema.md.
Downstream consumers of hypotheses.json:
by-hypothesis-debate— adversarial ranking of the top candidatesby-campaign-optimizer— translates the top hypothesis into round-N+1 parameter changesby-knowledge—knowledge_store_failurerecords the confirmed root cause once a prediction is run
Clarification Questions
⚠️ CRITICAL: ASK THIS FIRST — without a concrete failure pattern to explain, the skill cannot ground its queries and will produce vacuous hypotheses.
- Which failure pattern are you trying to explain? Point me at the diagnosis output file. (ASK THIS FIRST)
- Expected: a path to a
diagnosis.jsonproduced byby-failure-diagnosis, OR a description of the discriminating features (e.g. "failed designs have lower pLDDT and higher hydrophobic_fraction"). - If no diagnosis exists yet → route to
by-failure-diagnosisfirst; this skill cannot reason from raw screening output.
- Expected: a path to a
- Do you have the matching epitope analysis output? (
hotspots.json)- Without structural context, structural hypotheses are downgraded to SPECULATIVE. Strongly preferred.
- Is the
by-knowledgegraph populated for this target class?- If <3 prior campaigns exist for the modality+target-class combination, hypotheses will rely on the catalog only; warn the user that evidence will be thin.
- Has a prior round of this campaign already produced hypotheses?
- If yes, point the script at the prior
hypotheses.jsonso repeated mechanisms can be flagged (the optimizer was supposed to address them).
- If yes, point the script at the prior
- Are lab results available? (
experiment_results.json)- Lab calibration upgrades hypothesis confidence by one tier when in-silico signal matches bench outcome.
- What is the hypothesis count limit?
- Default 4. Hard cap 5. Never override above 5 — that signals the skill should call
by-hypothesis-debatefor pruning.
- Default 4. Hard cap 5. Never override above 5 — that signals the skill should call
- What downstream action is planned?
- If next step is
by-campaign-optimizer, prioritize mechanisms with concrete parameter levers. If next step is lab submission, prioritize mechanisms with cheap falsification assays.
- If next step is
Standard Workflow
🚨 MANDATORY: USE THE SCRIPTS EXACTLY AS SHOWN — DO NOT WRITE INLINE HYPOTHESIS NARRATIVES 🚨
The skill is split deliberately: mechanical retrieval and scoring are handled by the scripts; only the per-hypothesis claim sentence and falsifiable prediction are generated by the LLM at runtime. That separation is what makes this skill different from a chain-of-LLM-calls demo.
Step 1: Verify inputs
Confirm the diagnosis file exists and has at least one significant discriminating feature (adjusted p < 0.05). If not, the skill exits early: without a statistical signal, mechanistic hypotheses are unfounded.
ls campaigns/<target>/<campaign_id>/diagnosis.json
jq '.discriminating_features | length' campaigns/<target>/<campaign_id>/diagnosis.json
✅ VERIFICATION: Expect ≥1 entries with adjusted_p_value < 0.05. If 0, route to by-failure-diagnosis for re-run with more designs.
Step 2: Generate candidate hypotheses
Run generate_hypotheses.py. It does the following deterministic work:
- Reads
diagnosis.jsonand matches discriminating features against the diagnostic-signature column in references/failure-mechanisms-catalog.md. - For each candidate mechanism, queries
by-knowledgeviamcp__by-knowledge__knowledge_query_similarand (when matching failures exist) by direct keyword scan offailures.json. - Scores each candidate via the precedence table in references/evidence-grading.md to assign a confidence tier.
- Ranks candidates by
(confidence_tier, supporting_evidence_count, contradicting_evidence_count_inverse). - Emits a JSON skeleton with all evidence citations populated and a Jinja-like
prompt template embedded for the agent to fill in the
claimandfalsifiable_predictionfields.
python3 scripts/generate_hypotheses.py \
--diagnosis campaigns/<target>/<campaign_id>/diagnosis.json \
--epitope campaigns/<target>/<campaign_id>/hotspots.json \
--target "<target>" \
--modality "<modality>" \
--max-hypotheses 4 \
--out campaigns/<target>/<campaign_id>/hypotheses.json \
--trail campaigns/<target>/<campaign_id>/evidence_trail.md
✅ VERIFICATION: Expect ✓ Generated N hypotheses where N ≤ 5. Each hypothesis must have ≥1 supporting evidence entry.
Step 3: Validate evidence citations
Before passing the file downstream, verify every cited entity exists in the knowledge graph and the relation type the claim asserts is actually present in that entity.
python3 scripts/score_hypothesis_evidence.py \
--hypotheses campaigns/<target>/<campaign_id>/hypotheses.json \
--out campaigns/<target>/<campaign_id>/hypotheses_scored.json
✅ VERIFICATION: Every hypothesis ends with evidence_check: OK. If evidence_check: ENTITY_NOT_FOUND appears, regenerate — a fabricated citation is worse than no citation.
Step 4: Hand off downstream
Pipe to one of:
by-hypothesis-debate— when ≥2 hypotheses tied at the top confidence tierby-campaign-optimizer— when one hypothesis dominates and has a concrete parameter leverby-knowledge(knowledge_store_failure) — after a falsifiable prediction has been run and confirmed
❌ DON'T:
- ❌ Write claim sentences inline without running
generate_hypotheses.py— that produces unevidenced hypotheses. - ❌ Increase
--max-hypothesesabove 5 — parsimony is the whole point. - ❌ Skip Step 3 — fabricated entity IDs are the most common silent failure mode.
- ❌ Use this skill's output as a confirmed root cause. Confirmed means a falsifiable prediction was run AND the result matched.
When Scripts Fail
Use the standard hierarchy. The most common modes for this skill:
- Fix and Retry (90%) —
by-knowledgeMCP server not running → start it (uv run mcp__by-knowledge) and re-run. Missingpydantic→pip install pydantic. - Modify Script (5%) — Add a new mechanism to the catalog → edit
references/failure-mechanisms-catalog.mdAND the catalog parsing ingenerate_hypotheses.py. Both must agree on mechanism keys. - Use as Reference (4%) — A custom mechanism not in the catalog → read the catalog and
evidence-grading.md, write one ad-hoc hypothesis by hand following the schema, then runscore_hypothesis_evidence.pyto validate. - Write from Scratch (1%) — Only if the entire
by-knowledgegraph is broken and cannot be repaired. In that case, output a single SPECULATIVE hypothesis and route toby-hypothesis-debatefor human-in-the-loop ranking.
Decision Points
Confidence tier assignment
| Supporting Tier | Contradicting Tier | Final Confidence | Notes |
|---|---|---|---|
| HIGH (≥3 campaigns OR peer-reviewed) | none | HIGH | Strong claim |
| HIGH | MEDIUM | MEDIUM | Downgrade one |
| HIGH | HIGH | SPECULATIVE | Real conflict, debate |
| MEDIUM | none | MEDIUM | Standard case |
| MEDIUM | MEDIUM | SPECULATIVE | Unclear |
| SPECULATIVE | any | SPECULATIVE | Cannot upgrade |
| none | any | refuse to emit | No evidence → no hypothesis |
Full precedence table at references/evidence-grading.md.
Mechanism prioritization
When multiple mechanisms have the same confidence tier, rank by:
- Falsifiability cost — cheaper experiments first (in-silico re-scoring < ELISA < SPR < cell assay)
- Parameter actionability — mechanisms the optimizer can directly address rank higher
- Evidence count — more independent supporting entities first
When to escalate to by-hypothesis-debate
- Top two hypotheses both HIGH confidence with overlapping mechanisms
- Top hypothesis SPECULATIVE because of HIGH-vs-HIGH conflict
- User asks for adversarial pressure on a single hypothesis
Common Issues
| Issue | Cause | Solution | Details |
|---|---|---|---|
| Empty knowledge graph (0 campaigns, 0 failures) | Skill called before any prior campaigns recorded | Refuse to emit hypotheses; ask user to populate via by-knowledge first |
references/evidence-grading.md |
| Single-source claim | Only one campaign in the graph matches the mechanism | Downgrade to SPECULATIVE; corroboration requires ≥2 independent entities (or 1 Tier-1 entity) | references/evidence-grading.md |
| Confirmation bias (LLM agrees with the diagnosis) | Claim sentence parrots the diagnosis input without independent evidence | Script forces evidence retrieval before claim generation; score_hypothesis_evidence.py flags claims without ≥1 supporting entity |
references/evidence-grading.md |
| Confidence inflation | Agent labels every hypothesis HIGH | The script assigns confidence mechanically from the precedence table — agent cannot override | references/evidence-grading.md |
| Hypothesis count creep | Output has 6+ hypotheses | Hard cap of 5 enforced by generate_hypotheses.py; emit ≥6 only with explicit --allow-overflow flag, which forces a by-hypothesis-debate handoff |
references/failure-mechanisms-catalog.md |
| Missing falsification clause | falsifiable_prediction field is empty or aspirational ("more research needed") |
Script validates the field is a runnable assay (regex match against assay-verb vocabulary); empty → fails Step 3 | references/hypothesis-output-schema.md |
| Claim/evidence mismatch | The claim cites entity X but X is about a different mechanism | score_hypothesis_evidence.py checks claim mechanism against entity mechanism field; mismatch flagged as RELATION_MISMATCH |
references/hypothesis-output-schema.md |
| Citing non-existent KG entity IDs | LLM invented a campaign_<random> ID that isn't in the graph |
score_hypothesis_evidence.py queries every cited ID via the knowledge MCP server; missing → ENTITY_NOT_FOUND. Hypothesis rejected outright |
references/hypothesis-output-schema.md |
| Non-mechanistic claims (correlations dressed as mechanisms) | Claim says "designs with feature X failed", but does not say WHY | Catalog uses canonical mechanism keys; claim sentence must reference one of them. The skill rejects claims that are pure restatements of statistics | references/failure-mechanisms-catalog.md |
| Missing assay context | falsifiable_prediction says "test it" with no assay named |
Predictions must name a specific assay (SPR, BLI, MST, DSF, HIC, AC-SINS, mass spec, ELISA, cell binding, etc.) | references/hypothesis-output-schema.md |
by-knowledge MCP server unreachable |
Server crashed or not started | Restart by-knowledge; the script's stub-data fallback labels everything SPECULATIVE and is for development only |
references/evidence-grading.md |
| Stale knowledge graph (old data dominates queries) | Campaigns from >12 months ago skew the keyword score | Run mcp__by-knowledge__knowledge_consolidate to prune stale low-access entries, then re-run hypothesis generation |
references/evidence-grading.md |
| Multiple campaigns under same target with different name spellings | Keyword match misses some (e.g. TNF-alpha vs TNFα vs TNF_alpha) |
Pass the canonical normalized form via --target; the script also tries common variants and warns on apparent splits |
references/failure-mechanisms-catalog.md |
| Diagnosis features not in the catalog | A custom feature like disulfide_count discriminates PASS/FAIL but no mechanism maps to it |
Add a row to the catalog (or use --catalog-overlay extra.yml) before regenerating; emitting a hypothesis from an unmapped feature would skip mechanism grounding |
references/failure-mechanisms-catalog.md |
Best Practices
- 🚨 CRITICAL: Never emit a hypothesis without ≥1 supporting evidence entity. This is the single rule that separates this skill from "AI scientist" hallucination demos.
- 🚨 CRITICAL: Cap hypotheses at 5. Parsimony is the contract. If 6+ mechanisms look plausible, that is a debate task, not a list task.
- ✅ REQUIRED: Run
score_hypothesis_evidence.pyafter every generation. Catches fabricated entity IDs and relation mismatches before downstream consumers see them. - ✅ REQUIRED: Match diagnosis features to canonical mechanism keys. Don't invent mechanisms — extend the catalog if needed.
- ✅ Prefer Tier-1 (peer-reviewed or multi-campaign) evidence; Tier-3 alone never reaches HIGH confidence.
- ✅ Write claim sentences in past or present indicative ("designs aggregate due to..."), never aspirational ("might possibly indicate...").
- ✅ Make every
falsifiable_predictionrunnable: name the assay, name the readout, name the threshold. - ✅ Cite contradicting evidence as well as supporting — the confidence tier reflects the conflict, not the supporting count alone.
- ✨ Optional: when lab data is available, upgrade matching hypotheses by one tier per the lab-calibration rule.
- ❌ DON'T write claims like "feature X discriminates PASS/FAIL". That is a correlation, not a mechanism.
- ❌ DON'T re-emit a hypothesis the optimizer already addressed in a prior round without flagging it as
REPEATED:in the claim.
Suggested Next Steps
Pick the downstream skill based on the shape of hypotheses.json:
by-hypothesis-debate— when ≥2 hypotheses share the top confidence tier OR when conflicting evidence drove a SPECULATIVE label. Debate spawns competing strategy agents and runs adversarial ranking before any GPU compute is committed.by-campaign-optimizer— when one hypothesis dominates AND has a clear parameter lever (e.g. lower temperature, swap scaffold, restrict CDR length). The optimizer readsrecommended_next_actionfrom the top hypothesis and translates it into a round-N+1 parameter delta.by-experiment-results— when the falsifiable prediction is cheap enough to run at the bench. Match the predicted assay to the lab queue; lab outcome closes the loop.by-knowledge(knowledge_store_failure) — once a prediction has been run and the mechanism confirmed, record it so future campaigns inherit the finding.by-research— only if hypothesis generation surfaced a target-biology gap (e.g. epitope conformational dynamics not characterized in literature). Re-research, then re-run this skill.
Each downstream skill expects hypotheses.json to validate against the schema
in references/hypothesis-output-schema.md;
that schema is the contract.
Related Skills
Upstream (run before this):
by-screening— produces PASS/FAIL labels and per-design featuresby-failure-diagnosis— producesdiagnosis.json(statistical signals)by-epitope-analysis— produceshotspots.json(structural context)by-experiment-results— optional, produces lab calibrationby-knowledge— must be populated with prior campaigns and failures
Downstream (run after this):
by-hypothesis-debate— adversarial ranking when multiple hypotheses tieby-campaign-optimizer— round-N+1 parameter changes targeting the top mechanismby-knowledge(knowledge_store_failure) — record confirmed mechanisms
Alternative / complementary:
by-research— for target uncertainty (literature gaps), not design uncertaintyby-failure-diagnosis— answers "which features matter"; this skill answers "what mechanism is behind those features"
References
Detailed documentation (in references/):
failure-mechanisms-catalog.md— Canonical list of biologic-design failure mechanisms with diagnostic signatures (steric clash, electrostatic mismatch, hydrophobic aggregation, cryptic epitope, polyspecificity, slow on-rate, allosteric perturbation, disulfide/PTM issues). For each: telltale in-silico features + recommended diagnostic assays.evidence-grading.md— Tier system (HIGH / MEDIUM / SPECULATIVE), how to combine supporting + contradicting evidence, precedence table, anti-confirmation rules.hypothesis-output-schema.md— Full JSON Schema forhypotheses.jsonincluding required fields, allowed confidence values, evidence-record shape, falsifiable-prediction rules. Two worked examples (HIGH-confidence and SPECULATIVE).
Scripts (in scripts/):
generate_hypotheses.py— Mechanical query → score → rank pipeline. Emits hypotheses with evidence pre-populated; the agent fills only the claim sentence and falsifiable prediction from the embedded prompt template.score_hypothesis_evidence.py— Post-generation validator. Verifies every cited entity exists, the claim's mechanism matches the entity's mechanism field, and assigns the evidence tier per the precedence table.
Related BY skills:
by-knowledgeSKILL.md — evidence sourceby-failure-diagnosisSKILL.md — statistical inputby-epitope-analysisSKILL.md — structural inputby-hypothesis-debateSKILL.md — adversarial downstreamby-campaign-optimizerSKILL.md — parameter-change downstreamby-researchSKILL.md — exemplar for confidence taxonomy
External references (for the catalog and grading rubrics):
- IEDB and AbDab antibody developability metadata
- Published guidance on antibody developability liabilities (e.g. hydrophobic patches, charge variants, PTM hotspots) — citations in references/failure-mechanisms-catalog.md
- Falsifiability framing follows the standard scientific method literature; the skill enforces it operationally rather than philosophically.
License: All third-party packages permit commercial use in AI applications. Skill content is internal to BY.