Reading the output¶
Every field, and the order to read them in.
Files¶
results/
├── comparison.json side-by-side across samples, after `openbiota run-all`
└── <sample>/
├── <sample>_report.pdf the Gut Health Test Metagenomic Report, ~330 pages
├── summary.txt the same content as text, one section per subject
├── results.json every number, machine-readable
├── run.log versions, flags, timings, reference fingerprints
├── depth_check.json rarefaction, after `openbiota depth-check`
├── taxonomy/ species profile and cached Bowtie2 alignment
├── alignments/ raw and per-panel DIAMOND hits
└── depth/ rarefaction scratch, regenerable
| File | Contents |
|---|---|
<sample>_report.pdf |
The report, in two parts (see below). Part A puts every reading in front of the reader as a graphic in fourteen short sections; Part B breaks each one down and, under each, shows what the human research says about changing it. Every percentile uses one seven-band scale (notably low → notably high). Two finished examples: sample-reports/ |
summary.txt |
Full technical summary, one section per subject |
results.json |
Everything in the text report, plus more, machine-readable |
run.log |
Versions, flags, timings, reference set sizes, stage progress |
depth_check.json |
Saturation analysis, if openbiota depth-check has been run |
comparison.json |
Cross-sample table, if openbiota run-all was used |
alignments/hits_all_<mate>.tsv |
Raw DIAMOND output |
alignments/hits_<panel>_<mate>.tsv |
Per-panel view, with role and organism appended |
taxonomy/metaphlan.*.tsv |
Species profile, plus the cached alignment so re-profiling is instant |
The directory name is the sample name, which comes from the FASTQ filename —
so SAMPLE2_A02_1.fastq.gz produces results/SAMPLE2_A02/SAMPLE2_A02_report.pdf.
Renaming the input renames the output; --sample overrides it.
alignments/ and depth/ together account for most of the disk a run uses and
are fully regenerable; openbiota prune --alignments --yes clears them.
Subsampled runs write to results/<sample>.subsampleN/ so smoke-test and
full-run caches do not invalidate each other.
Exit status is 1 if any [ERROR] diagnostic fired, so the tool composes into
a pipeline.
The report's two parts¶
Part A — at a glance (sections 1–14, about 55 pages). Every reading as a graphic, nothing deep; the full organism list sits here because "what else is in there" is the question that follows "what is flagged".
| § | What it shows |
|---|---|
| 1 | Summary: gut-health dial, what stood out (index, missing/depleted/expanded organisms, most notable functions, top pattern), every function as a bar, community donut |
| – | Table of contents |
| 2 | What stood out, in prose: the flagged organisms, the functions, the evidence-card tally, the age estimate |
| 3 | Your gut community: composition by class, diversity and evenness as neutral range strips (none has a favourable direction on its own) |
| 4 | Your microbial groups at a glance: the curated groups (butyrate producers, mucin degraders, oral-origin, opportunists …) on reference bars, each with its level against the typical carrier |
| 5 | Organisms that need attention — one rule, organisms.verdict, applied once to every organism on its one share and its rank among the reference adults who carry it: overgrown (an opportunist at or above the 90th percentile among carriers; any non-beneficial organism at or above the 97th; an opportunist most people do not carry that is several times above the people who do), worth watching (a conditional resident between the 90th and 97th; an opportunist fewer than one in ten adults carry), depleted (a beneficial organism at or below the 10th), missing (commonly carried, not detected where the detection model says it should have been), depleted, worth watching (expanded, or uncommon to carry). Each with its share, the typical carrier's level, its deviation and its rank among carriers |
| 6 | Your organisms, classified: every organism detected, one share of the whole each, largest first; the thirty most abundant described one by one; the organisms furthest above and below the reference; then the full table with class, share, level against the typical carrier, how many reference adults carry it, percentile, strain |
| 7 | Pathogens: every target searched, graded (see below), with each bacterial call reconciled against the organism inventory |
| 8 | Estimated biological age of biota: point estimate on the training-support histogram, conformal intervals, what moved it, the model card |
| 9 | Your microbial functions at a glance: every gene-capacity pathway on the seven-band bar |
| 10 | Resemblance to published disease patterns at a glance: shape verdict (diffuse vs specific), ranked table of every scored pattern |
| 11 | Biofilm-related potential |
| 12 | Your gut mycobiome |
| 13 | Gut-skin axis |
| 14 | What you can do about it: one line per evidence card — what fired, what was studied, evidence lane (A–E, X), for/against count, status |
Part B — in detail (sections 15–28). Each reading broken down; under each one an evidence card block.
| § | What it shows |
|---|---|
| 15 | Your microbial groups in detail: every group card with its members, each member's share, level and percentile, and its evidence |
| 16 | Organisms that need attention, one by one: detection power, reference carriage, level, curated interpretation with citations, disease signatures it appears in, evidence cards; then the cross-checks where two measurements disagree |
| 17 | Which strain, not just which species: the marker fingerprint of each organism's dominant population, and its comparative placement among the reference genomes of its species (nearest genome, distance, mixture evidence) |
| 18 | Pathogens in detail |
| 19 | Your microbial functions in detail: result, percentile, reference band, what it means, the research behind it, what the research says about changing it |
| 20 | Resemblance to published disease patterns, in detail: every scored pattern, most resemblant first, module scores, feature table, confounders, evidence cards; patterns not scored, and why |
| 21 | Biofilm findings in full |
| 22 | Your gut mycobiome, in detail |
| 23 | Gut-skin axis, in detail |
| 24 | Your information and report context: the input register — what was supplied about the person and the sample, and what was missing |
| 25 | What this report cannot tell you |
| 26 | Sequencing quality and reference coverage: the reads, the QC gates, every detection method that ran and the reference release each used |
| 27 | How this test performs: measured accuracy of the engines on simulated communities with known composition |
| 28 | Technical data |
Organisms, on one scale. Section 6 gives every organism one share of the whole, on the scale of the marker catalogue that measures the composition. A † marks a share divided among populations the whole-genome mapping tells apart within one marker species; a ° marks an organism the marker catalogue has no entry for, whose share is estimated from the whole-genome search and drawn from the unclassified band; within marks a population counted inside its relatives' shares above it; a § marks a share that includes what the marker catalogue had read under a relative the whole-genome competition rejected — the reads belong to the marked organism, so its share came with them, and the rejected name is printed beneath. Level is the deviation from the typical carrier — the median level among reference adults who carry the organism at all, printed in brackets — with the percentile among those carriers; the two are taken on the same distribution, so above the 50th percentile is always a positive deviation. Where fewer than ten reference adults carry an organism no rank is stated. Where the reference catalogue reads a species fivefold differently from the composition, the organism is ranked instead in the population of a lane whose reading agrees with the share (marked ‡, the population named); where none does, the row says not comparable.
One judge of levels. Whether an organism's level needs attention is
decided in exactly one place, openbiota.organisms.verdict, from its one
share and its rank among the reference adults who carry it; the attention
page is the set of organisms that rule flags, plus the organisms no method
found that the reference adults commonly carry. No other section judges a
level — the reference catalogue's own census ranks nothing on this page any
more, because a second judge with its own estimator put the same organism on
the page twice and moved the page whenever either judge changed. A population
counted within a relative's share is judged as that relative when it is the
same population under another catalogue's name (its reading within a factor
of two of the relative's share), and on its own lane rank when it is a
distinct population or the relative has no rank. A beneficial organism that
is high is not a finding: a supplement being taken is not an overgrowth. The
rule is tested branch by branch on synthetic organisms
(tests/test_organisms.py), and on any run present the page is checked to be
exactly the image of the rule (tests/test_attention.py).
One account of what is present. The pathogen screen aligns reads to its
own 485 reference genomes, so sequence an organism shares with a relative the
bundle carries no reference for lands on the nearest target and reads as a
signal. Every named bacterial call is therefore checked against the organism
inventory, which mapped the same reads competitively against every relative
it found. A call the inventory found keeps its status and quotes the
community share; one the inventory did not find, whose coverage is piled into
conserved regions rather than spread across the genome (or whose call the
competitive confirmation rejected), is reported under Sequence that belongs
to relatives, not to these organisms, names the relatives that carry the
reads, and stops counting as a finding. A call with genuine coverage that the
inventory's catalogues cannot see — they have a detection floor this screen
does not — is kept, and says so. pathogens.inventory_reconciliation records
the outcome, and each record carries inventory_agreement,
inventory_species, inventory_evenness and, where it applies,
inventory_share_percent or inventory_relatives. Identity is deliberately
not a gate: a genuine strain 1–2% divergent from its reference maps no better
than a cross-mapped relative.
Sections ranked against a single reference catalogue — the biofilm cards and the disease-pattern tables — keep that catalogue's own readings, because that is what makes a percentile against its cohort mean anything, and say so where the pooled methods disagree with them.
Evidence cards. Each card names the exact intervention (strain and dose as
studied, diet protocol, drug, or clinical route), who it was studied in, the evidence for and against side by side with PMIDs/DOIs, the evidence lane (A guideline/label · B replicated RCT · C single or conflicting RCT · D non-randomised human · E animal/in vitro · X against), the applicability of the studied population to this sample, the safety rules that fired and which context fields would be needed to say more, and the phrases the report will not use. Where no human study shows that changing a reading changes an outcome, the card says no supported targeted intervention — that is a result, not a gap. Where FMT is the only route with evidence, the card says so and gives its regulatory status. Nothing on a card is a recommendation; the disclaimer is on every card.
Read it in this order¶
1. Diagnostics. An [ERROR] means the run is invalid. Zero rpoB makes
every figure indeterminate; a dead butyrate positive control means something
is broken upstream. Stop there.
2. The rpoB denominator. Everything is divided by it. The summary reports
its yield per million read pairs and flags implausible values. An
under-detected denominator inflates every pathway at once.
3. Stability flags. UNSTABLE means the fragment count is low enough that
counting noise dominates, however precise the number looks.
4. The numbers. Per-gene values are more interpretable than the panel aggregate. Where a residue-consistent subset is reported, the headline is the upper bound and the subset is the tighter estimate.
5. The cross-pathway pattern. Everything elevated at once points at the denominator, not at biology.
Key fields¶
Copies per 100 bacterial genomes¶
The primary measurement. For a single-copy gene: 100 means essentially every bacterium carries it, 10 means roughly one in ten, 1 means roughly one in a hundred.
Percentile¶
Position within the reference cohort. The 60th percentile means 60% of cohort
samples had a lower value. Requires refs/reference_ranges.json from
openbiota cohort.
Bands¶
trace / low / moderate / high / very high are scan aids computed from
the absolute value. The percentile is the meaningful comparison; the band is
just a label.
Flags¶
| Flag | Meaning |
|---|---|
ok |
Nothing to note |
UNSTABLE |
Below the panel's minimum fragment count; counting noise dominates |
LOW-ID |
Fragments average under 75% translated identity — matching distant relatives rather than the gene itself. Upper bound only. |
few-refs |
Fewer than 25 reference sequences; a low value is weak evidence of absence |
refs-capped |
Reference set hit its size cap; sensitivity is bounded by it |
upper-bound |
Panel has an active-site filter that reads are mostly too short to apply |
INDETERMINATE |
No rpoB denominator |
extension |
Pathway beyond the original scope |
none |
Nothing detected |
Diagnostic codes¶
| Code | Level | Meaning |
|---|---|---|
rpob-zero |
error | No denominator; every figure indeterminate |
positive-control-zero |
error | butyrate returned nothing; the run is invalid |
rpob-low-yield / rpob-high-yield |
warn | Denominator outside the plausible band |
all-panels-elevated |
warn | Everything high at once — a normalisation artefact |
low-identity-<gene> |
warn | Distant-homolog matching; see LOW-ID |
implausible-<panel> |
warn | More gene copies than there are genomes to carry them |
residue-concordant-<gene> |
info | The two independent residue checks agree |
residue-discordant-<gene> |
warn | They disagree; trust neither over the headline |
unstable-<panel> |
info | Below the stability threshold |
refs-small-<gene> / refs-truncated-<gene> |
info | Reference set size notes |
unresolved-subjects |
warn | Cached hits came from a different database; re-run with --force |
Residue check¶
Reported in two halves for urdA.
Reference side — how many accepted fragments matched a reference that itself carries an acceptable active-site residue. Applies to every fragment.
Read side — of the fragments whose alignment reached the site, how many carried an acceptable residue. This is the published filter, applied where available. Typically a small percentage of fragments at 151 bp.
When both are available the report cross-checks them against each other, since they share no evidence.
Closest reference organisms¶
The reference sequences the reads matched best. This is not taxonomic identification — a read matching a Clostridium reference means the nearest sequence in the reference set came from one, nothing more.
Confidence tier¶
confirmed means the reading meets the criteria at which validation produced
no false positives: at least 2 matching fragments and at least 75% mean
translated identity. provisional means detected but below that bar — a
possible signal rather than a reliable one. See
VALIDATION.md.
What it means¶
Each pathway carries an explanation matching where the reading fell — above the
75th percentile, below the 25th, or in between. The text is specific to that
metabolite and comes from interpretation.implications in its panel file, so
the report and the panel definition cannot drift apart.
Community composition¶
Derived from the rpoB fragments, which are already computed as the
denominator. Phylum-level proportions are reliable. Genus labels are
nearest-reference matches. Proportions approximate cell fractions, not the
DNA-mass fractions a read-count profiler like Kraken reports.
Profile similarity fields¶
| Field | Meaning |
|---|---|
modules.<name>.score |
Weighted mean of feature values, −1 to +1 |
modules.<name>.percentile |
Rank of that score against the reference null |
modules.<name>.weight_coverage |
Fraction of planned feature weight actually measured |
combined.percentile |
The headline figure. Fraction of the matched reference less concordant with the pattern |
confidence.grade |
HIGH / MODERATE / LOW / INSUFFICIENT |
confidence.reasons_for_downgrade |
Why it is not higher, in plain language |
abstention.abstained |
Whether the engine refused to score |
abstention.what_would_change_this |
What to fix, if it did |
cross_engine_checks[].verdict |
CONCORDANT / DISCORDANT / UNAVAILABLE |
dysbiosis_anchor.score |
GMWI2. Positive leans healthy, negative leans disturbed |
features[].v |
That feature's signed contribution, −1 to +1 |
features[].w/q/s/c |
Evidence weight, cohort independence, specificity, direction agreement |
features[].reference_percentile |
Where the sample sits for that feature |
A combined.percentile of 63 means the sample is more concordant with the
profile's prespecified pattern than 63% of the matched reference set. It is
not a 63% chance of having the condition.
Added by the v3 contract, on each profile result:
| Field | Meaning |
|---|---|
status |
scored, low_coverage, not_computable or abstained |
confidence_vector.* |
The dimensions behind the grade, kept separate rather than multiplied: technical_reliability, independent_feature_coverage, evidence_maturity, assay_transportability, population_transportability, empirical_specificity, literature_uniqueness_prior, out_of_distribution, direction_conflict, interval_width |
confidence_vector.uncertainty_interval |
Bootstrap interval on the percentile |
competing_profiles |
Other profile families that score within reach of this one |
top_two_margin |
Percentile points between this profile and the next-highest family |
modules.<name>.module_status / independent_cluster_coverage |
Whether a study module could be scored, and what fraction of its independent feature clusters were measured |
modules.<name>.bound / would_bind_if |
Whether the module's evidence type has a measurement in this pipeline, and what would bind it if not |
features[].evidence_type / claim_level |
What kind of measurement the feature is and what the source study could legitimately claim |
features[].scoring_weight / audit_factor_wqsc |
Only w enters the score; w·q·s·c is recorded for audit |
And alongside the profiles, under profile_similarity:
| Field | Meaning |
|---|---|
ranked[] |
Every profile with status, percentile, concordance and maturity, highest first |
shape_analysis.verdict |
specific, diffuse, quiet, mixed or unscored — the library-wide reading |
shape_analysis.n_above_typical_band / n_notably_high |
How many profiles sit above the 75th / 95th percentile |
shape_analysis.mean_specificity_of_high_scorers |
Whether the high scorers discriminate their own condition or track general disturbance |
confounder_ledger.recorded / missing / profiles_abstained |
Which subject facts were supplied, which were not, and which profiles refused to score for want of them |
withheld_opt_in_profiles |
Profiles skipped without --include-opt-in |
community.groups[] |
Ten curated microbial groups: summed abundance, cohort percentile, prevalence, each member's own placement |
community.species[] |
Every species named by the scoring lane: abundance, cohort percentile, prevalence, and which groups it belongs to |
Full detail on the scoring: PROFILES.md.
Sequencing quality fields¶
sequencing_quality.gates is the spec 4.2 gate table.
| Field | Meaning |
|---|---|
overall |
pass, warn, fail or unknown — the worst individual gate |
usable_nonhost_pairs / depth_adequate / minimum_usable_pairs |
The prespecified depth floor (500,000 pairs) and whether it was met |
gates[] |
One row per gate: gate, label, value, display, status, note. A gate that could not be measured is unknown, never pass |
provenance |
Instrument, run, flowcell, lane and index read from the FASTQ headers, and the batch key they form |
sequencing_quality.fastp is the parsed fastp report: pairs and bases in and
out, Q20/Q30, GC, duplication rate, read-length profile, adapter-trimmed reads,
insert-size peak, and whether the reads arrived pre-trimmed.
Extended catalogue fields¶
extended_catalogue is the MetaPhlAn 4 SGB inventory. It is reported, never
scored — what_this_is says so in the file.
| Field | Meaning |
|---|---|
n_sgbs_detected / n_species_detected / n_genera_detected |
Catalogue breadth in this sample |
n_unnamed_sgbs / unnamed_sgb_percent |
Genome bins with no cultured representative, and their share of the sample |
unclassified_percent |
What even this catalogue could not name |
sgbs[] |
Every bin: sgb, species, genus, kingdom, percent, unnamed |
bridge_to_scoring_lane |
Species named by both profilers, by MetaPhlAn 4 alone, and by MetaPhlAn 3 alone, with examples |
Version identifiers¶
Two profile results are comparable only when all five of these match. They are
all in results.json and on the technical page of the PDF.
| Identifier | Where |
|---|---|
| Pipeline version | version |
| DIAMOND reference fingerprint | run["reference fingerprint"] |
| MetaPhlAn database | profile_similarity.taxonomic_engine.database |
| Reference cohort manifest | profile_similarity.reference.taxonomic.manifest.manifest_id |
| Profile version | profile_similarity.profiles.<name>.profile.version |
results.json structure¶
tool, version, sample
measures, does_not_measure
run flags, timings, versions, fingerprints
input read counts, lengths, GC, quality, mate structure
normalisation rpoB counts, the formula, indeterminate flag
search hit lines, mate collapse accounting
panels[] per pathway:
accepted_fragments, decoy_fragments, copies_per_100_genomes
copies_per_100_genomes_residue_consistent
aggregate_method, aggregate_from, stable, caveats
genes[] per gene: fragments, identity, references, residue_check
decoys[]
reference_comparison percentile, cohort quartiles, status per pathway
community_profile phyla, genera, diversity indices
diagnostics[] level, code, message
reference_entries provenance for every reference set
profile_similarity disease-pattern engine (see below)
microbiome_age status, estimate, 80%/95% intervals, OOD detail,
contributions, model bundle id
findings_and_evidence
findings reference context, detection model, every species with
detection status/power, reference prevalence class,
percentile among carriers with 90% bootstrap interval,
BH q, bucket 1-7, curated interpretation; contradictions
triggers[] what fired (panel/group/profile/species, direction)
evidence_summaries[] per card: intervention identity, studied protocol,
supporting/against assertions with sources, lane,
applicability, safety verdict, display policy,
never_say, follow-up route, FMT status
registry digests of the intervention/safety/interpretation registries
Comparing over time¶
The same sample analysed twice gives the same answer; two samples from the same person weeks apart give a trend. That trend is more informative than any single value, because the method's systematic biases — reference set composition, identity floors, read length — are held constant across runs and largely cancel in a difference.
Keep results directories per timepoint and compare
reference_comparison.panels.<name>.value across them.
Strain resolution (section 17)¶
Species profiling says an organism is present. Strain resolution says which one — and for much of gut biology that is the question that matters: whether an E. coli is a harmless resident or carries an intact Shiga-toxin operon is a strain-level question, not a species-level one.
The report resolves, for every organism with enough coverage, the dominant population's consensus across marker genes, at single-base resolution. In the supplied samples that is 49–78 organisms each, over 5.5–7.5 million callable bases.
What a fingerprint is, and is not¶
| It is | It is not |
|---|---|
| This sample's own population of that organism | A match to a named laboratory strain |
| The dominant population | Proof of a single strain — a minority population can be concealed |
| Comparable between specimens at base level | A whole-genome identity claim from conserved markers |
| Evidence of an organism's identity | Attribution of a separately detected toxin or resistance gene |
An organism detected but not resolved is reported as exactly that. Absence of resolution is a limit of sequencing depth, not a finding about the organism.
How it is produced¶
The marker lane is a second pass over the reads, pinned to MetaPhlAn 4.1.1
and the mpa_vJun23_CHOCOPhlAnSGB_202403 database — the same pair that
produced the sample's abundance profile. Mixing the 4.1 and 4.2 workflows is
not supported and is actively prevented: a 4.2 strainphlan on PATH will not
be used against 4.1 alignments.
# emit SAM alongside the usual outputs, in a fresh directory so an existing
# bowtie2 summary cannot cause the alignment to be skipped
metaphlan reads_1.fastq.gz,reads_2.fastq.gz --input_type fastq \
--bowtie2db refs/metaphlan4_db --index mpa_vJun23_CHOCOPhlAnSGB_202403 \
--nproc 32 -s sample.markers.sam.bz2 \
--bowtie2out sample.markers.bowtie2.bz2 -o sample.markers.species.tsv
sample2markers.py -i sample.markers.sam.bz2 -o consensus_markers \
-d refs/metaphlan4_db/mpa_vJun23_CHOCOPhlAnSGB_202403.pkl -n 32
samtools is a hard dependency of sample2markers.py.
What was asked for, and what came back¶
Every report now carries a completeness census: each registered resolution target with the state it actually reached. The distinction it preserves is the one that matters most in a screening report:
An unrun, failed or unavailable assay is never reported as a negative result.
States include completed, reference_unavailable (the tool or reference is
not installed), incompatible_input (an RNA virus cannot be assayed from DNA
sequencing, and adding reference sequences cannot change that) and scheduled
(registered, with reference curation outstanding). The full per-target detail,
with a reason for every non-terminal target, is in results.json under
resolution_census.