Skip to content

index

Agent-driven Domainator workflows

Copy-paste recipes for AI agents (or scripted pipelines) that need low-token, high-signal output from Domainator. For orientation and the CLI conventions, read AGENTS.md first.

The guiding idea: Domainator's HTML reports and binary artifacts (HDF5 matrices, XGMML, the .dvb viewer bundle) are meant for humans and browsers. For an agent, reach for the --json_out output modes and domainator ssn_navigator, which return compact, structured slices instead of whole-artifact dumps.

Machine-readable output cheat-sheet

Tool Flag Shape
domainator enum_report --json_out - NDJSON, one object per contig/CDS/domain
domainator hmmer_report --json_out - NDJSON, one object per HMM profile (add --columns alphabet for amino/DNA/RNA)
domainator summary_report --json_out - one JSON object (contig stats, domain frequency + co-occurrence, taxonomy)
domainator matrix_report --json_out - one JSON object (edge stats, connected components, split-event series)
domainator ssn_navigator (always JSON) targeted cluster / node / threshold queries

--json_out - writes to stdout; pass a path to write a file. These sit alongside the existing -o/--html_out outputs — nothing is removed.

Output shapes

The enum_report / hmmer_report NDJSON is dynamic: each object's keys are exactly the columns you requested via flags (e.g. --architecture --length), and values are strings, numbers, or null. There is no fixed key set — read the first line to see the shape. Example (enum_report --by contig --columns architecture length):

{"contig":"FeSOD_A0A1F4ZT98|unreviewed|Superoxide","architecture":"Sod_Fe_N; Sod_Fe_C","length":196}

The remaining outputs have stable shapes, shown below (pretty-printed here; the tools emit them compact). These are the contract — treat added keys as backward-compatible, removed/renamed keys as breaking.

summary_report --json_out

{
  "contig_stats": {
    "contigs": 20, "cdss": 0, "cds_per_10kb": 0.0,
    "length": {"min": 189, "max": 215, "mean": 200.15, "median": 201.0, "total": 4003}
  },
  "domain_frequency": [
    {"domain": "Sod_Fe_N", "database": "FeSOD_pfam", "count": 20,
     "description": "Iron/manganese superoxide dismutases, alpha-hairpin domain", "avg_score": 101.1}
  ],
  "domain_cooccurrence": null,
  "taxonomy": [{"taxid": 1234, "name": "Bacillus", "rank": "genus", "count": 5}]
}

length is null for empty input; domain_cooccurrence is null unless focus domains were given (then it is {row_domain: {col_domain: percent}}); taxonomy is present only with --taxonomy.

matrix_report --json_out

{
  "nodes": 20, "non_zero_edges": 52,
  "edge_scores": {"mean": 215.37, "median": 216.0, "min": 135.0, "max": 287.0},
  "connected_components": 2,
  "merge_impact_metric": "min_child",
  "split_events": [
    {"edge_index": 0, "threshold_from": "∞", "threshold_to": "287.00",
     "threshold_value": 287.0, "merge_impact": 1.0,
     "merge_size_counts": {"1": 1}, "largest_merge": 1.0, "merge_count": 1,
     "delta_largest": 1.0, "delta_avg_non_singleton": 2.0}
  ]
}

edge_scores is null for a matrix with no non-zero edges. split_events is bounded by domainator matrix_report --max_merge_events; a threshold_value of null denotes ∞.

merge_impact is the sum of every merge at that threshold, so it cannot by itself distinguish one large cluster splitting off from a swarm of small ones. The other three keys describe its terms: merge_size_counts maps each distinct merge size to how many merges of that size occurred, merge_count is their total, and largest_merge is the biggest single one. sum(size * count) == merge_impact holds exactly, and largest_merge == merge_impact only when merge_count is 1. A threshold reporting {"3": 1, "1": 33} is one 3-node cluster plus thirty-three single nodes falling off at once -- merge_impact 36, but no cluster larger than 3.

Every threshold matrix_report reports means the same thing as build_ssn --threshold: the graph of edges scoring strictly above the threshold. So a reported threshold T and its edge/cluster counts are exactly what domainator build_ssn -i <matrix> --threshold T emits, and split_events[i].edge_index is the last MST edge scoring above that threshold. Thresholds equal to a score are therefore exclusive of that score's own ties -- the merge listed at threshold T becomes visible at the next lower threshold.

ssn_navigator (one shape per --mode)

// --mode overview
{"name": "net", "domainator_version": "0.10.0", "nodes": 4, "mst_edges": 3,
 "connected_components": 1,
 "metadata_columns": [{"name": "category", "type": "str"}, {"name": "count", "type": "int"}],
 "defaults": {"color_by": null, "label_by": null}, "merge_impact_metric": "min_child"}

// --mode thresholds  -> suggested cut-points, finest first (threshold_value null == ∞)
{"thresholds": [{"threshold_value": 7.0, "threshold_label": "7.00",
                 "clusters": 2, "non_singleton_clusters": 1, "largest_cluster": 3}]}

// --mode clusters --threshold X
{"threshold": 5.0, "clusters": 2, "singletons": 1, "shown": 2,
 "cluster_list": [{"id": 5, "size": 3}, {"id": 3, "size": 1}]}
// "truncated": <n> is added when more than --top_n clusters exist.

// --mode cluster --threshold X (--id N | --node NAME) [--members]
{"threshold": 5.0, "cluster_id": 5, "size": 3,
 "metadata_summary": [
   {"name": "category", "type": "str", "count": 3, "missing": 0, "unique": 2,
    "top": [{"value": "alpha", "count": 2}, {"value": "beta", "count": 1}]},
   {"name": "count", "type": "int", "count": 3, "missing": 0,
    "min": 1.0, "max": 3.0, "mean": 2.0, "p25": 1.5, "median": 2.0, "p75": 2.5}
 ]}
// "members": ["A","B","C"] is present only with --members.
// str columns carry top/unique (+ "truncated" past --top_n); numeric columns carry the quartile stats.

// --mode node --node NAME
{"node": "A", "node_index": 0, "metadata": {"category": "alpha", "count": 1},
 "memberships": [{"threshold_value": 7.0, "threshold_label": "7.00",
                  "cluster_id": 5, "cluster_size": 3}]}

Recipe 1 — annotate, then get a structured summary

Annotation tools (domainate, structure_domainate) retain every input record, including records without hits, and add domain annotations for retained hits. Use domain_search / structure_search to select matching records or regions instead. Sequence search can emit neighborhoods or translated CDSs; structure search emits matching targets' full observed protein sequences and marks their best-hit regions. --add_annotations adds domain annotations (Domainator features) alongside the search best-hit annotations (Domain_Search features) already present. The annotation tools do not accept --hits_only or --no_annotations. The input being annotated/searched is -i; references being searched for are -r. See command roles and output shapes.

domainator domainate -i genomes.gb -r pfam.hmm -o annotated.gb --max_overlap 0.6
domainator summary_report -i annotated.gb --json_out summary.json
domainator enum_report -i annotated.gb --by contig --columns architecture length --json_out contigs.ndjson

summary.json gives dataset-level domain frequencies and (with --taxonomy) taxonomic breakdown; contigs.ndjson gives one line per contig with its domain architecture — filter/aggregate it with any JSON tooling.

Taxonomy-restricted extraction

All three extract_* tools, select_by_cds, select_by_contig, and domain_search accept the same taxonomy criteria. The input is still the file being edited:

# Extract peptides whose original CDS belongs to Bacteria but not clade 1224.
domainator extract_peptides -i annotated.gb --taxonomy_expr "2 & ~1224" -o peptides.gb
# Do not admit unlabeled proteins just because the expression is negated.
domainator extract_domains -i annotated_proteins.gb --taxonomy_expr "~2" -o nonbacterial.gb
# For annotation workflows, select whole records before domainate.
domainator select_by_contig -i genomes.gb --include_taxids 2 -o bacteria.gb
domainator domainate -i bacteria.gb -r pfam.hmm -o annotated_bacteria.gb

--taxonomy_unknown exclude is the default: missing, unidentified, deleted, unknown IDs, and uncovered regions are rejected with active criteria. evaluate explicitly uses an empty lineage (allowing unlabeled candidates for ~2); include bypasses the taxonomy gate for unresolved candidates, and error stops on them. None proves that a missing label is biologically outside an excluded clade.

Taxonomy is resolved on the original CDS/domain anchor before extension or translation. The longest source covering all anchor parts wins. Expanded neighborhoods can include other taxa. --invert does not invert taxonomy. Protein extract_unannotated and select_by_contig use whole-record taxonomy. No criteria means no taxonomy filtering or database loading; use --ncbi_taxonomy_path to select an existing offline database.

Recipe 2 — build a similarity network and navigate it

# 1. all-vs-all similarity -> dense matrix
domainator seq_dist -i proteins.gb -r proteins.gb --hdf_out dist.hdf5

# 2. (optional) per-node metadata to attach, e.g. domain architecture + taxonomy
domainator enum_report -i proteins.gb --by contig --columns architecture taxname:domain -o meta.tsv

# 3. compact SSN bundle
domainator build_ssn -i dist.hdf5 --dvb_out net.dvb --metadata meta.tsv

# 4. navigate without rendering
domainator ssn_navigator -i net.dvb -o - --query overview
domainator ssn_navigator -i net.dvb -o - --query thresholds                 # pick a cut-point
domainator ssn_navigator -i net.dvb -o - --query clusters --threshold 150   # clusters + sizes
domainator ssn_navigator -i net.dvb -o - --query cluster --threshold 150 --cluster 5   # members + metadata distribution

The metadata.tsv columns (from enum_report) become the per-cluster distributions in --mode cluster output: string columns yield the top values with counts; numeric columns yield min/max/mean/quartiles.

--mode thresholds derives the cuts from the bundle's merge order and reports merge_events / merge_event_total alongside them: those cuts are one per selected split event, which domainator ssn_navigator --max_merge_events caps (default 500, plus up to 20 more so no 5% band of the threshold range is left unrepresented). On a large network that is a small sample of the real event list, so treat the cuts as good candidate cut-points rather than as every threshold at which anything happens — and pass a higher cap, or 0, to see them all. The cap is yours, not the file's: it is applied when you ask, so any bundle answers at any cap without being rebuilt.

--threshold follows the viewer's slider: higher is finer. --threshold inf is the slider's ∞ end, where every node is its own cluster (reported as "threshold": null, the same spelling the bundle uses); omitting --threshold is the other end, one cluster per connected component.

Add --html_out net.html in step 3 for a self-contained browser viewer of the same network. Annotations made there (edited cells, new columns) are saved back into an ordinary .dvb by its "Save session…" button, so a session file feeds straight back into step 4 and the new columns show up in the per-cluster distributions. The chart glyph in each metadata column header is the interactive counterpart of those distributions -- a frequency table, bar or pie chart, histogram, box plot, cumulative distribution or summary statistics over the rows the table is currently showing, exportable as SVG, PNG or TSV. ssn_viewer.md is the guide to the viewer; the .dvb section of file_formats.md has the schema.

Recipe 3 — inspect a matrix's cluster structure

domainator seq_dist -i proteins.gb -r proteins.gb --hdf_out dist.hdf5
domainator matrix_report -i dist.hdf5 --json_out -

Returns edge-score stats, the number of connected components, and the strongest threshold split events — enough to decide where to cut the network before building an SSN.

Notes on token efficiency

  • domainator ssn_navigator and the report --json_out modes bound their lists with --top_n (default 50). Raise it deliberately when you need the long tail.
  • domainator ssn_navigator --query cluster omits the member id list unless you pass --members; the metadata distribution summary is usually what you want.
  • NDJSON (enum_report/hmmer_report) streams, so you can head/filter huge reports without materializing the whole thing.