# Driving JBrowse with an AI agent (two Drosophila genomes)

:::caution JBrowse v5 beta

The tutorials target the JBrowse v5 beta, and the v4.3.0 release
on the [download page](https://jbrowse.org/jb2/download/) lacks some of what they show. To install the
beta of JBrowse Web, run `npm install -g @jbrowse/cli@next`, then
`jbrowse create jbrowse2 --branch v5.0.0-beta.17`. Desktop beta builds are coming soon.

:::

An AI agent, given four requests in plain words, aligns two fruit fly species
that have no published alignment and inspects the result in JBrowse Desktop.
Typed one at a time, the requests ask the agent to:

- align the two genomes with minimap2 and open them side by side, genes and all
- add a dotplot of the pair, restricted to the chromosome arms
- count alignment blocks by strand, to find where the two genomes run in
  opposite directions
- navigate the view to what it found

## Prerequisites

- JBrowse Desktop, installed and running (see the
  [desktop quickstart](https://jbrowse.org/jb2/docs/quickstart_desktop))
- an MCP client with a shell of its own, for the alignment step: Claude Code, or
  Claude Desktop, set up as in [Using JBrowse with AI agents](https://jbrowse.org/jb2/docs/agents)
- [minimap2](https://github.com/lh3/minimap2)
- `node`, for the [JBrowse CLI](https://jbrowse.org/jb2/docs/cli)

<!-- TUTORIAL_INSTALL minimap2,node,jbrowse-cli START -->

```bash
# Debian/Ubuntu
sudo apt install minimap2 nodejs
# or conda, which has every tool above
conda install -c bioconda -c conda-forge minimap2 nodejs
# any platform
npm install -g @jbrowse/cli
```

<!-- TUTORIAL_INSTALL minimap2,node,jbrowse-cli END -->

## The data

The assemblies are two GenArk genomes
([_D. simulans_](https://genomes.jbrowse.org/accession/GCF_016746395.2/),
[_D. mauritiana_](https://genomes.jbrowse.org/accession/GCF_004382145.1/)); each
hub config holds the 2bit sequence, a chromAlias file, an NCBI RefSeq gene track
and a Trix text index.

No download is needed, since the agent fetches both sequences itself and aligns
them, a step that takes minutes and gigabytes of memory. For a pair of your own,
swap in your `.pif.gz` and assemblies, as _Ask the agent to align and open the
two genomes_ shows.

<details>
<summary>The files</summary>

| What it is                                                   | File                                                                                                                |
| ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------- |
| _D. simulans_ sequence, which the agent downloads to align   | [GCF_016746395.2.fa.gz](https://hgdownload.soe.ucsc.edu/hubs/GCF/016/746/395/GCF_016746395.2/GCF_016746395.2.fa.gz) |
| _D. mauritiana_ sequence, which the agent downloads to align | [GCF_004382145.1.fa.gz](https://hgdownload.soe.ucsc.edu/hubs/GCF/004/382/145/GCF_004382145.1/GCF_004382145.1.fa.gz) |

</details>

## Ask the agent to align and open the two genomes

The first request, in one sentence:

```text
Align D. simulans GCF_016746395.2 against D. mauritiana GCF_004382145.1 with
minimap2. Run it in the background and poll it, and when it is done index it
and open both genomes side by side, with their gene tracks and the alignment
between them.
```

The agent runs this aligner command:

<!-- from: scripts/build_fly_agent_synteny.sh -->

```bash
# asm20: the two species diverge past the 1% asm10 allows
# --cs: writes the difference string the index below carries
minimap2 -t 8 -cx asm20 --cs mau.fa.gz sim.fa.gz > sim_vs_mau.paf
```

The alignment takes several minutes, so the agent runs it in the background. The
agent then indexes the PAF, so the browser can read one region without parsing
the whole file:

<!-- from: scripts/build_fly_agent_synteny.sh -->

```bash
jbrowse make-pif sim_vs_mau.paf
```

The agent's config merges the two genomes.jbrowse.org hub configs, keeping each
gene track, and adds this alignment as a synteny track. For your own pair, swap
`uri` for your `.pif.gz` (its `.tbi` beside it), load both assemblies, and check
the order of `assemblyNames` on the track:

```json addtrack
{
  "type": "SyntenyTrack",
  "trackId": "sim_vs_mau",
  "name": "D. simulans vs D. mauritiana",
  "assemblyNames": ["GCF_016746395.2", "GCF_004382145.1"],
  "adapter": {
    "type": "PairwiseIndexedPAFAdapter",
    "uri": "sim_vs_mau.pif.gz",
    "assemblyNames": ["GCF_016746395.2", "GCF_004382145.1"]
  }
}
```

In `assemblyNames`, the query (`sim.fa.gz`, the second `minimap2` argument)
comes first and the target second, the order of the PAF columns. In the other
order no chromosome name resolves and the synteny band draws empty.

<Figure caption="chr3R on both genomes with RefSeq genes on each row and the minimap2 alignment between them, colored by strand." src="/img/agent_synteny/comparison_built.png" />

## Ask for a dotplot restricted to the chromosome arms

```text
Add a dotplot of the same two assemblies underneath.
```

With the axes restricted to the chromosome arms, the plot shows one diagonal:

```text
Restrict both dotplot axes to chr2L, chr2R, chr3L, chr3R, chr4 and chrX.
```

Ask the agent to quantify what restricting the axes drops. Add one more request,
to color the dotplot by strand, so a reversed block draws in blue and a forward
one in red.

<Figure caption="The alignment as a dotplot cut to the chromosome arms, colored by strand." src="/img/agent_synteny/dotplot_arms.png" />

## Ask where the two genomes run in opposite directions

```text
Where do the two genomes run in opposite directions? Answer from the
alignment file, not from the dotplot, and show me the numbers.
```

At whole-genome zoom a reverse-strand block a few hundred kilobases wide is a
few pixels, so the request asks for numbers from the PAF: aligned bases per arm,
split by strand, at mapping quality (MAPQ) 30 or better:

```bash
awk -F'\t' '
BEGIN {
  # the arm each RefSeq accession is, from the chromAlias files
  split("NC_052520.2 2L NC_052521.2 2R NC_052522.2 3L NC_052523.2 3R NC_052524.2 4 NC_052525.2 X", a, " ")
  split("NC_046667.1 2L NC_046668.1 2R NC_046669.1 3L NC_046670.1 3R NC_046671.1 4 NC_046672.1 X", b, " ")
  for (i = 1; i in a; i += 2) q[a[i]] = a[i+1]
  for (i = 1; i in b; i += 2) t[b[i]] = b[i+1]
}
# $12 is MAPQ, $5 the strand, $4-$3 the aligned length on the query
$12 >= 30 && ($1 in q) && ($6 in t) && q[$1] == t[$6] {
  aligned[q[$1]] += $4 - $3
  if ($5 == "-") reverse[q[$1]] += $4 - $3
}
END {
  for (k in aligned)
    printf "%-3s %6.2f Mb aligned, %5.2f%% reverse\n", k, aligned[k]/1e6, 100*reverse[k]/aligned[k]
}' sim_vs_mau.paf | sort
```

```text
2L   22.15 Mb aligned,  0.28% reverse
2R   20.56 Mb aligned,  5.02% reverse
3L   22.56 Mb aligned,  0.03% reverse
3R   27.03 Mb aligned,  0.01% reverse
4     1.10 Mb aligned,  0.00% reverse
X    21.04 Mb aligned,  4.44% reverse
```

Four arms have essentially no reverse-strand alignment and are the control: 2R
and X sit an order of magnitude above them.

Grouping the reverse-strand blocks of 5 kb or more, and cutting a group wherever
half a megabase passes with none, gives three regions:

```text
2R  sim    59,995 - 2,256,808  <->  mau   628,956 - 3,646,198   (2.20 Mb, 75 blocks)
X   sim 8,303,553 - 8,752,357  <->  mau 8,530,265 - 8,980,862   (0.45 Mb,  2 blocks)
X   sim 21,441,285 - 22,026,996 <->  mau 21,459,277 - 22,872,816 (0.59 Mb, 12 blocks)
```

## Ask the agent to open the 2R and X regions

```text
Close the gene tracks and take the synteny view to the 2R region.
```

The agent opens the simulans row at `chr2R:1-2,400,000` and the mauritiana row
at `chr2R:500,000-3,800,000`.

<Figure caption="The 2R region, the alignment alone. Reverse-strand blocks draw blue and cross the band." src="/img/agent_synteny/inversion_2r.png" />

Then ask for the first of the two X regions, `chrX:8,100,000-8,950,000` over
`chrX:8,330,000-9,180,000`, where the reverse blocks are fewer and longer:

<Figure caption="The X region, the alignment alone. Two reverse blocks cross in the middle." src="/img/agent_synteny/inversion_x.png" />

## Three instructions to include when prompting the agent

Three instructions each prevent a failure that raises no error:

- **Start long work in the background, and let it finish before opening
  anything.** Otherwise a tool call times out, after two minutes for
  `run_javascript`, and the agent reports a failure that did not happen.
- **Restrict the dotplot axes to the arms.** Otherwise a few hundred unplaced
  scaffolds (not assigned to a chromosome) interleave both axes.
- **Ask for answers counted from the alignment file.** Otherwise the agent
  describes the dotplot.

Two more are worth asking for:

- **Screenshot what you build and read the image back.** A wrong track id or an
  empty region still renders as a plausible browser.
- **Ask for the numbers before navigating.** The view you then see is a claim
  you can check.

## Running the whole pipeline as a script

[`build_fly_agent_synteny.sh`](https://github.com/GMOD/jbrowse-components/blob/main/scripts/build_fly_agent_synteny.sh)
runs the pipeline without the agent. It needs the tools in
[Prerequisites](#prerequisites), plus `jq` and `curl`. The script:

1. Downloads both genomes from their hosted GenArk configs.
2. Aligns simulans against mauritiana with minimap2.
3. Indexes the PAF as PIF.
4. Merges the two hosted configs and the synteny track into one `config.json` to
   open in Desktop.

```bash
curl -O https://raw.githubusercontent.com/GMOD/jbrowse-components/main/scripts/build_fly_agent_synteny.sh
bash build_fly_agent_synteny.sh fly_agent_synteny_build
```

## See also

- **Tutorial:** [Synteny visualization (pairwise minimap2)](https://jbrowse.org/jb2/docs/tutorials/synteny_visualization)
- **Docs:** [Using JBrowse with AI agents](https://jbrowse.org/jb2/docs/agents)
- **Docs:** [Recipes for driving JBrowse from an agent](https://jbrowse.org/jb2/docs/agents_recipes)
- **Docs:** [Driving the live JBrowse session](https://jbrowse.org/jb2/docs/agents_live_model)

## Citations

- Chakraborty et al. (2021).
  [Evolution of genome structure in the _Drosophila simulans_ species complex](https://doi.org/10.1101/gr.263442.120)
- Li (2018).
  [Minimap2: pairwise alignment for nucleotide sequences](https://doi.org/10.1093/bioinformatics/bty191)

