In-process Nextflow Tower API shim — accumulate -with-tower trace events without a Seqera Platform subscription
Project description
Nextflow Turret
A self-hosted replacement for Seqera Platform (formerly Nextflow Tower).
Run any Nextflow pipeline with -with-tower, track progress in real time, launch new runs from
a web UI, and inspect logs — all without a cloud subscription.
Features
| Feature | Details |
|---|---|
| Tower trace receiver | Accepts the full Nextflow -with-tower HTTP protocol |
| SQLite persistence | Every run is immediately written to disk; survives restarts |
| Pipeline launcher | Submit pipelines via web form or REST API; cancel running jobs |
| Web dashboard | Live run list, per-run progress detail, failed-task drill-down |
| REST API | JSON API for runs and launches (OpenAPI docs at /docs) |
| Embeddable library | Use WorkflowRegistry + TowerRouter inside your own Python app |
Installation
# Into an existing project
uv add "nextflow-turret @ git+https://github.com/msk-mind/nextflow-turret.git"
# Or with pip
pip install "nextflow-turret @ git+https://github.com/msk-mind/nextflow-turret.git"
Quick start — standalone server
# Start the server (default: http://0.0.0.0:8000, DB: turret.db)
turret
# Or with explicit options (always override config file)
turret --host 127.0.0.1 --port 9000 --db /data/turret.db --log-dir /data/logs
# Or via Python
python -m nextflow_turret.server --port 9000
Config file
Create a turret.toml in the working directory (or ~/.config/turret/config.toml for user-level defaults). CLI flags always win over config values.
[server]
host = "0.0.0.0"
port = 8000
db = "/data/turret.db"
log_dir = "/data/turret-logs"
[launcher]
nextflow = "/opt/nextflow/nextflow"
work_dir = "/scratch/nf-work"
default_profile = "slurm"
A fully-commented template is at turret.toml.example.
Then point Nextflow at it:
nextflow run nf-core/rnaseq -with-tower http://localhost:8000 -name dispatcher_mybatch \
-profile docker -r 3.14.0
Open http://localhost:8000 to see the live dashboard.
REST API
Interactive docs are available at /docs when the server is running.
Tower trace endpoints (called by Nextflow)
| Method | Path | Purpose |
|---|---|---|
GET |
/user-info |
Auth check on Nextflow startup |
POST |
/trace/create |
Workflow registered → returns {workflowId} |
PUT |
/trace/{id}/begin |
Workflow running |
PUT |
/trace/{id}/progress |
Periodic task counts + per-task list |
PUT |
/trace/{id}/heartbeat |
Keepalive (same payload as progress) |
PUT |
/trace/{id}/complete |
Workflow finished |
Runs API
| Method | Path | Description |
|---|---|---|
GET |
/api/runs |
List all runs (newest first) |
GET |
/api/runs/{workflow_id} |
Single run detail with task counts, failures, resources |
Launches API
| Method | Path | Description |
|---|---|---|
GET |
/api/launches |
List all launches (newest first) |
POST |
/api/launches |
Submit a new pipeline launch |
GET |
/api/launches/{id} |
Launch status and metadata |
GET |
/api/launches/{id}/log?tail=N |
stdout/stderr log (optionally tailed) |
DELETE |
/api/launches/{id} |
Cancel a running launch (SIGTERM) |
Submit a launch via REST
curl -X POST http://localhost:8000/api/launches \
-H "Content-Type: application/json" \
-d '{
"pipeline": "nf-core/rnaseq",
"revision": "3.14.0",
"profile": "docker",
"params": {"input": "samplesheet.csv", "genome": "GRCh38"},
"work_dir": "/scratch/work"
}'
run_name → batch_id mapping
Nextflow is launched with -name dispatcher_{batch_id}. The dispatcher_ prefix
is stripped automatically to produce the batch_id that identifies the run.
To use a different prefix, create your own TowerRouter:
from nextflow_turret import TowerRouter, WorkflowRegistry
registry = WorkflowRegistry()
router = TowerRouter(
registry=registry,
run_name_to_batch_id=lambda name: name.removeprefix("mypipeline_"),
)
Embedding in your own Python app
If you prefer to host the Tower receiver inside an existing service rather than running the standalone server, use the core library directly:
from nextflow_turret import TowerRouter, WorkflowRegistry
registry = WorkflowRegistry()
router = TowerRouter(registry=registry)
# In your HTTP handler:
result = router.handle_get(path) # GET /user-info
result = router.handle_post(path, body) # POST /trace/create
result = router.handle_put(path, body) # PUT /trace/{id}/progress
# Read progress at any time:
state = registry.get_by_batch("mybatch")
print(state["pct"], "% complete")
print(state["task_counts"]) # {"succeeded": 42, "running": 3, ...}
print(state["failures"]) # [{"taskId": 7, "process": "ALIGN", "exit": 1}, ...]
Module-level singleton
For quick scripts, a global registry is available:
import nextflow_turret as turret
turret.register_workflow(workflow_id, batch_id, run_name)
turret.update_progress(workflow_id, progress_dict, tasks_list)
turret.mark_complete(workflow_id)
state = turret.get_progress(batch_id) # → dict or None
Utilities
from nextflow_turret import tower_process_to_slurm_name
# Convert a Tower process name to a SLURM job name prefix
tower_process_to_slurm_name("MUSSEL:EXTRACT_FEATURES:TESSELLATE_FEATURIZE_BATCH")
# → "MUSSEL_EXTRACT_FEATURES_TESSELLATE_FEATURIZE_BATCH"
Architecture
nextflow_turret/
├── state.py # WorkflowRegistry, WorkflowState — core in-memory model
├── handlers.py # TowerRouter — parses Tower HTTP payloads
├── db/
│ └── store.py # RunStore — SQLite persistence (runs + launches)
├── launcher/
│ └── launcher.py # Launcher — subprocess management for pipeline runs
└── server/
├── app.py # FastAPI application factory (create_app)
├── registry.py # PersistentWorkflowRegistry — DB-backed registry
├── __main__.py # CLI entry point (turret / python -m nextflow_turret.server)
└── templates/ # Jinja2 HTML templates (dashboard, detail, launch form)
Key design decisions:
- Write-through persistence — every Tower trace event is committed to SQLite before the HTTP response is sent.
- Restart recovery — on startup,
PersistentWorkflowRegistryre-hydrates all rows from the DB so in-progress runs can continue receiving trace events. - No external dependencies for the core library — only
fastapi,uvicorn, andjinja2are needed for the server extras.
Development
git clone https://github.com/msk-mind/nextflow-turret.git
cd nextflow-turret
# Run tests (uv installs deps automatically)
uv run pytest
# Or sync into a venv and work interactively
uv sync --extra server
source .venv/bin/activate
pytest --tb=short -q
Test layout
| File | Tests | Coverage |
|---|---|---|
tests/test_turret.py |
39 | Core library (WorkflowRegistry, WorkflowState, TowerRouter) |
tests/test_server.py |
44 | Server layer (RunStore, PersistentWorkflowRegistry, all endpoints) |
tests/test_integration.py |
32 | Cross-layer: Tower→SQLite, restart recovery, concurrency, API/DB/UI consistency |
tests/test_e2e.py |
34 | Full scenarios: NF trace lifecycle, failed tasks, multi-run dashboard, launch UI journey, error paths |
License
Nextflow Turret is released under the GNU Affero General Public License v3.0 (AGPL-3.0-or-later).
This means:
- Free to use, modify, and self-host for any purpose.
- If you modify Nextflow Turret and run it as a network service, you must make your modified source code available to users of that service.
See LICENSE for the full terms.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file nextflow_turret-0.1.0.tar.gz.
File metadata
- Download URL: nextflow_turret-0.1.0.tar.gz
- Upload date:
- Size: 74.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
bdfbe11619210a4a23b9651ef0b9728dd2f6a94c3d59bc4d4c0fd7a1bc593858
|
|
| MD5 |
57886f071214f1083b4de291f560a8eb
|
|
| BLAKE2b-256 |
a4810df4c8fda5a2a65d7985d5bb5d73188998e00721daa66adc8e718cbf27cf
|
Provenance
The following attestation bundles were made for nextflow_turret-0.1.0.tar.gz:
Publisher:
publish.yml on msk-mind/nextflow-turret
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nextflow_turret-0.1.0.tar.gz -
Subject digest:
bdfbe11619210a4a23b9651ef0b9728dd2f6a94c3d59bc4d4c0fd7a1bc593858 - Sigstore transparency entry: 1705218918
- Sigstore integration time:
-
Permalink:
msk-mind/nextflow-turret@3503aa86d7c51ebfd66f07cb234a2c00453454d8 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/msk-mind
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@3503aa86d7c51ebfd66f07cb234a2c00453454d8 -
Trigger Event:
release
-
Statement type:
File details
Details for the file nextflow_turret-0.1.0-py3-none-any.whl.
File metadata
- Download URL: nextflow_turret-0.1.0-py3-none-any.whl
- Upload date:
- Size: 59.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d5a166d370c1b174afe466a5125f91e967cef3aae9782357ec57a532bbdee8d3
|
|
| MD5 |
ece1e988bd662e7fa41798294814a27f
|
|
| BLAKE2b-256 |
85e2cdd4f136cd00990046ce1f945f646cab43f92aea239a3b83ca9cc77109ec
|
Provenance
The following attestation bundles were made for nextflow_turret-0.1.0-py3-none-any.whl:
Publisher:
publish.yml on msk-mind/nextflow-turret
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
nextflow_turret-0.1.0-py3-none-any.whl -
Subject digest:
d5a166d370c1b174afe466a5125f91e967cef3aae9782357ec57a532bbdee8d3 - Sigstore transparency entry: 1705218946
- Sigstore integration time:
-
Permalink:
msk-mind/nextflow-turret@3503aa86d7c51ebfd66f07cb234a2c00453454d8 -
Branch / Tag:
refs/tags/v0.1.0 - Owner: https://github.com/msk-mind
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@3503aa86d7c51ebfd66f07cb234a2c00453454d8 -
Trigger Event:
release
-
Statement type: