Literate Notebooks

BioLang notebooks (.bln files) interleave Markdown prose with executable BioLang code. They're perfect for documenting analyses, creating reproducible reports, and sharing results with collaborators.

Quick Start

# Run a notebook in the terminal
bl notebook analysis.bln

# Export to standalone HTML
bl notebook analysis.bln --export html

# Convert from Jupyter
bl notebook experiment.ipynb --from-ipynb > experiment.bln

# Convert to Jupyter
bl notebook experiment.bln --to-ipynb > experiment.ipynb

The .bln Format

A .bln file is plain text. Markdown prose is rendered, and code blocks are evaluated. Interpreter state carries over between blocks — variables defined in one block are available in all later blocks.

Fenced Code Blocks

Use standard Markdown fenced code blocks with biolang, bl, or no language tag:

## Sample Quality Control

Load the FASTQ file and check basic statistics.

```biolang
let reads = read_fastq("sample_R1.fastq.gz")
let stats = read_stats(reads)
print(stats)
```

## Filter Low-Quality Reads

Keep only reads with mean Phred score above 25.

```bl
let filtered = reads |> filter(|r| mean_phred(r.quality) > 25)
print(f"Kept {len(filtered)} of {len(reads)} reads")
```

Dash-Delimited Code Blocks

Alternatively, use --- on its own line to delimit code blocks. This is the original BioLang notebook format:

## Load Data
Read the FASTA file and compute per-sequence GC content.
---
let seqs = read_fasta("contigs.fa")
let gc_table = seqs |> map(|s| {id: s.id, gc: gc_content(s.seq)}) |> table()
print(gc_table)
---
## Results
The table above shows GC content per contig.

You can mix both styles in the same notebook. Code blocks with other language tags (e.g. ```python) are treated as prose and displayed but not executed.

Cell Directives

Add special comment annotations at the top of a code block to control how it behaves:

Directive Effect
# @hide Execute the code but don't display it in output. Useful for setup code.
# @skip Don't execute this block. Useful for draft or commented-out cells.
# @echo Print the code before executing it. Shows both code and output.
# @hide-output Execute the code (and show it) but suppress any printed output.

Directives are stripped from the code before execution. You can combine them:

```biolang
# @echo
# @hide-output
let config = {min_quality: 30, threads: 8}
let reference = "GRCh38"
```

HTML Export

Export a notebook to a self-contained HTML file with syntax highlighting and a dark-themed design:

bl notebook analysis.bln --export html > report.html

The HTML output includes inline CSS styling, BioLang syntax highlighting with color-coded keywords, strings, comments, and pipe operators. It's a single file with no external dependencies — perfect for sharing via email or publishing.

Jupyter Interop

Convert between BioLang's .bln format and Jupyter's .ipynb format for compatibility with the Jupyter ecosystem.

Import from Jupyter

# Convert .ipynb to .bln (prints to stdout)
bl notebook experiment.ipynb --from-ipynb > experiment.bln

Markdown cells become prose sections. Code cells are wrapped in fenced ```biolang blocks. Outputs are discarded (they'll be regenerated when you run the notebook).

Export to Jupyter

# Convert .bln to .ipynb (prints to stdout)
bl notebook analysis.bln --to-ipynb > analysis.ipynb

Prose sections become Markdown cells. Code blocks become code cells with "language": "biolang" metadata. The resulting notebook uses nbformat v4 and can be opened in JupyterLab, VS Code, or any notebook viewer.

Terminal Rendering

When you run bl notebook file.bln in a terminal, prose sections are rendered with ANSI styling:

  • Headings — bold, underlined, with level indicators
  • Inline code — cyan highlight
  • Bold and italic — ANSI bold/italic
  • Blockquotes — indented with | prefix in dim text
  • Lists — bullet points with indentation

Code blocks are executed in order. Output is interleaved between prose sections, making it easy to follow an analysis step by step.

Example Notebook

Here's a complete .bln notebook demonstrating the key features:

# GC Content Analysis

This notebook analyzes GC content across a set of contigs
and identifies potential outliers.

## Setup

```biolang
# @hide
let min_gc = 0.3
let max_gc = 0.7
```

## Load Data

Read the FASTA file and compute per-sequence statistics.

```biolang
let seqs = read_fasta("contigs.fa")
print(f"Loaded {len(seqs)} sequences")
```

## Compute GC Content

```biolang
# @echo
let gc_values = seqs |> map(|s| gc_content(s.seq))
let mean_gc = mean(gc_values)
let std_gc = stdev(gc_values)
print(f"Mean GC: {mean_gc:.3f} +/- {std_gc:.4f}")
```

## Identify Outliers

Flag contigs with GC content more than 2 standard deviations
from the mean — these may indicate contamination or
horizontal gene transfer.

```biolang
let outliers = seqs
  |> filter(|s| {
    let gc = gc_content(s.seq)
    abs(gc - mean_gc) > 2.0 * std_gc
  })
print(f"Found {len(outliers)} outlier contigs")
outliers |> each(|s| print(f"  {s.id}: GC={gc_content(s.seq):.3f}"))
```

## Summary

> The analysis identified potential contaminant contigs based
> on anomalous GC content. Review these sequences before
> downstream assembly or annotation.

Tips

  • Use # @hide for configuration and imports to keep the narrative clean
  • Use # @echo for key analysis steps so readers see both code and results
  • Use # @skip to temporarily disable expensive computation during development
  • Use # @hide-output when you want to show the code but not its (verbose) output
  • State carries across cells — define variables once and reuse them throughout
  • The HTML export is self-contained: share report.html directly
  • Use --from-ipynb to migrate existing Jupyter notebooks to BioLang