How It Works

biocomposer decomposes the reasoning required to run a bioinformatics workflow into a stack of abstraction levels, so that at each level only one kind of decision has to be made. Composing tools normally forces the user to reason about everything at once: which tools to chain, how their formats and arguments line up, how to invoke each one, and how to provision its environment. biocomposer separates these concerns into layers, and each layer resolves its own class of decision before delegating the rest downward. The result is that the burden of reasoning about data flow moves smoothly from the user’s intent down to a concrete execution, with no single level holding all of the complexity.

Concretely, a pipeline is expressed against a small Python API; the API operates on a graph of typed nodes; and the nodes are backed by a layer of specializations (connector generation, per-item processing, feedback loops via decision nodes). Each level is a thin surface over the one beneath it, the user calls add_node(), which resolves a typed tool from the registry, which in turn pulls an image and triggers a container run.

Pipeline Dataflow

A pipeline is a directed acyclic graph (DAG): tools are nodes and data hand-offs are directed edges.

        flowchart LR
    A(["inputs"]) --> B["align"]
    B --> C["trim"]
    C --> D["fold"]
    D --> E(["result"])
    

The DAG representation gives the system three properties. Dependencies are explicit: an edge A → B declares that B consumes A’s output, and so run order never has to be specified by hand. The model generalises past linear chains: fan-out, fan-in, branching, and result sharing are all instances of the same node/edge structure. And it localises data conversion: mapping one tool’s output to another’s input is handled per edge, rather than as global script logic.

The API surface

The top layer is a small graph-construction API: add_input_node() for user-supplied values, add_node() for tools, add_edge() to wire them, set_output_node() to mark the result, and execute() to run. Construction is declarative: it records the graph, and no tool runs until execute() is called. These calls are deliberately thin. add_node triggers manifest resolution and image setup beneath it, and execute drives the evaluation described below, so the user never reasons about either.

The graph and node layer

Each node carries the typed input/output schema of its tool’s manifest. The following node types are specified:

  • Input nodes hold user files and parameters.

  • Tool nodes wrap a single registry tool and run once.

  • Gather nodes run a one-input tool once per item of an upstream collection, then gather the results.

  • Decision nodes re-run a node with adjusted inputs until a scored condition holds, a feedback loop contained within the node, so the graph as a whole stays acyclic. The score and modifier are each a Python function or a registry tool.

  • Subgraphs expose a one-in/one-out pipeline as a single node.

Edges are generated rather than written: each edge is realised as a connector that maps one tool’s output onto the next tool’s input, handling format conversion and item selection. When two edges supply the same input key, resolution is deterministic and governed by edge order (Input merging and key clashes).

The tool and container layer

At the base, each tool is a container image paired with a typed manifest. add_node("clustalo") resolves the manifest and pulls the image from DockerHub/Biocontainers/etc. Executing each tool in its own container pins its exact software and versions, making runs reproducible and letting tools with incompatible dependencies coexist in one graph. This layer is itself a wrapper: the tool library sits over external image sources, purpose-built images, BioContainers, or Docker Hub, so adding a tool means writing a manifest over an existing image rather than repackaging it (Tools and the registry, Adding your own tool).

How biocomposer runs tools

Constructing a graph defines a pipeline without executing it; computation begins only when execute() is called. At that point, biocomposer runs each tool in an isolated container, transfers data between consecutive steps, and returns the results. Tool installation and environment management are handled automatically, and the same pipeline runs on local or cloud hardware without modification.

Local vs. cloud

The same pipeline script runs in two places (see Installation):

  • Locally, using Docker on your machine, fine for lightweight tools.

  • On the cloud (Modal), which provides remote GPU machines for heavy tools like RFdiffusion or ColabFold. Results are stored on a persistent cloud volume you can download from.

Checkpoints

execute() returns the final step’s output as a dictionary of named results, typically paths to the files each tool produced. Every intermediate step’s output is also saved on disk under results/, so nothing is lost between steps.

Note

Tools are cited and used faithfully: each is run as its authors originally presented it, without modifying the original architecture or design choices.