# Evidence First Claims

> Record sources, evidence, hypotheses, results and claims in a ScientistOS research graph at the E0-E5 evidence level the lineage actually supports, and split work between the Scientist and Auditor roles. Use before asserting any scientific finding, citing a paper, or saying something "shows" or "causes" or "improves" something, and when promoting a claim, writing an abstract or results section, or auditing someone else's conclusion. Triggers include "record this finding", "add this evidence", "is this claim supported", "can we say X causes Y", "write up the results", "what level is this claim", "check for confounding or leakage". Do not use for non-scientific assertions or projects without a ScientistOS research graph.

- Skill: `ahmad-jaradat-space/evidence-first-claims` (Agent Skill)
- Install (CLI): `npx skillmds@latest add ahmad-jaradat-space/evidence-first-claims`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ahmad-jaradat-space/evidence-first-claims/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Research & Search
- Author: Ahmad-Jaradat-Space (https://skillmd.com/u/ahmad-jaradat-space)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ahmad-jaradat-space/evidence-first-claims

---


# Evidence-first claims

Say in one short line that you are using the `evidence-first-claims` skill before you act, so
the user can see which discipline you are working under.

A claim is only as strong as the lineage attached to it. The engine enforces this in code,
so an unsupported claim raises `ValueError` rather than quietly passing.

The CLI has no command for evidence or claims. Use the MCP tools `add_source`, `add_evidence`,
`register_hypothesis`, `add_assumption` and `register_claim`. They validate arguments and return
contract failures as readable errors. The Python API below is the fallback when the tools are
unavailable or you need something they do not expose.

Run the Python API with the interpreter that has `scientistos` installed, which is the project
venv (`.venv/bin/python`). A system `python3` will not have it importable.
`ResearchEngine(Path("research.db"))`
resolves relative to the current directory, so `cd` into the project that owns the graph, or
pass an absolute path. Do not create a new graph in whatever directory you happen to be in.

## The evidence ladder

Enforced in `ResearchEngine._validate_claim_evidence` (`src/scientistos/engine.py:191`):

| Level | What it requires |
|---|---|
| E0 | Nothing. Unsupported statement, speculation. |
| E1 | At least one evidence record or result, and every attached evidence must pass all four verification flags. |
| E2 | Everything above, plus at least one `result_id`. Empirical claims need empirical results. |
| E3 | Everything above, plus at least one supporting result carrying an explicit uncertainty record. |
| E4 | Everything above, plus every supporting result has a passing independent reproduction. |
| E5 | Everything above, plus corroboration from at least two distinct experiments. |

Two hard rules on top:

- A **causal** claim (`ClaimType.CAUSAL`) requires E4 or higher. You cannot say X causes Y off
  a literature reading and one run.
- E1 and above require the evidence's four verification flags to all be true:
  `existence`, `locator`, `entailment`, `scope_match`. Setting them is an assertion that you
  personally checked the passage. Do not set them to pass a gate.

Config defaults in `config/example.yaml`: abstract minimum E3, strong conclusion minimum E3,
causal minimum E4.

## Recording evidence and a claim

```python
from pathlib import Path
from scientistos.engine import ResearchEngine
from scientistos.models import EvidenceLevel, EvidenceVerification, SourceRecord, ClaimType

engine = ResearchEngine(Path("research.db"))

src = engine.add_source(SourceRecord(title="Smith 2024, tropospheric delay", doi="10.1234/x", year=2024))

ev = engine.add_evidence(
    src.id,
    locator="section 4.2, p. 11",        # must point at the exact place, not the whole paper
    excerpt="...verbatim text you actually read...",
    summary="Reports a 3 mm delay bias under high aerosol optical depth.",
    relevance=0.9,
    support=0.8,                          # negative value records contradicting evidence
    verification=EvidenceVerification(
        existence=True, locator=True, entailment=True, scope_match=True,
        checked_by="claude-code-read-passage",
    ),
)

claim = engine.register_claim(
    "High aerosol optical depth is associated with a positive VLBI group delay bias",
    level=EvidenceLevel.E1,
    confidence=0.7,
    claim_type=ClaimType.DESCRIPTIVE,
    evidence_ids=[ev.id],
    qualifiers=["single site", "one observing season"],
)
print(claim.id)
```

Other engine methods: `register_hypothesis`, `add_assumption`, `register_experiment`,
`approve`, `execute_experiment`, `record_result`, `record_reproduction`, `record_audit`,
`register_figure`, `impact`.

## Choosing the level

Pick the level the lineage supports, then stop. If `register_claim` raises, that is the
system working. The fix is to get the missing evidence, not to change the level you pass in
or weaken the verification flags.

Common honest outcomes:

- Read three papers, ran nothing: **E1**, descriptive, with qualifiers.
- Ran your own analysis once with a confidence interval: **E3** at best.
- Want to say "causes": you need **E4**, so you need an independent reproduction of every
  supporting result. Until then, say "is associated with".

## Counter-evidence

Record contradicting evidence with negative `support`. The engine wires it as an `opposes`
edge automatically. Never drop evidence that cuts against your hypothesis. A claim with
opposing evidence and no `qualifiers` raises a warning in the integrity audit, so state the
scope limit explicitly.

## The two roles

Work the two roles separately, and do not let one soften the other.

**As Scientist:** propose alternatives, predictions and discriminating experiments. Mark
assumptions explicitly with `add_assumption`. Prefer an executable test to an argument.

**As Auditor:** try to falsify, not to improve. Run `science falsification-plan` for the
standard attack list, and work through confounding, selection, leakage, measurement,
misspecification, multiplicity, coding defects, identifiability, and synthetic-null
behaviour. For an important computational result, demand an independent replay before
accepting it. Record what you find with `record_audit` rather than only saying it in chat.

The design assumes the Scientist and the Auditor are different model families
(`ModelRouter.independent_judges`, `src/scientistos/providers/router.py:38`). When you run
both roles yourself, that independence is weaker than the design intends. Say so when it
matters, and prefer an external reproduction for anything load-bearing.

## Before you write prose

Any sentence in an abstract, results section or summary should map to a claim in the graph
at the required level. If you are writing a conclusion that has no claim behind it, either
register the claim properly or mark the gap `[MISSING EVIDENCE]`. Do not strengthen causal
language during writing.

