This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
FLASHApp is a Streamlit web application for visualizing top-down proteomics results from the OpenMS FLASH* tool family. It is built on the OpenMS streamlit-template and bundles three independent sub-applications, each registered as a section in app.py:
- FLASHDeconv (⚡️) — spectral deconvolution: raw MS ion peaks → neutral monoisotopic masses (proteoforms), with isotope/charge resolution and FDR scoring.
- FLASHTnT (🧨) — tag-and-track top-down identification: runs FLASHDeconv, then matches short sequence "tags" against a protein FASTA database to identify proteins (PrSMs), with target/decoy FDR.
- FLASHQuant (📊) — proteoform quantification from FLASHDeconv mass traces (view-only; no run step).
The heavy lifting is done by TOPP command-line tools (FLASHDeconv, FLASHTnT, DecoyDatabase) shipped in the Docker image; the app drives them, parses their output into pandas DataFrames, caches them per workspace, and renders them through a custom Vue.js Streamlit component (flash_viewer_grid).
# Run locally (online_deployment=false in settings.json → always "local" mode)
streamlit run app.py local
# Unit tests (pytest; uses fakeredis, needs pyopenms importable)
pytest tests/ -v
pytest tests/test_selection_clear.py -v # single file
pytest tests/test_selection_clear.py::test_name -v # single test
# Lint (errors-only; mirrors .github/workflows/pylint.yml, which runs on `main`)
pylint $(git ls-files '*.py') --errors-only --disable=C0103,C0114,C0301,C0411,W0212,W0631,W0602,W1514,W2402,E0401,E1101,F0001,R1732
# Docker (full image with OpenMS + TOPP tools + Vue build)
docker build -f Dockerfile --no-cache -t flashapp:latest --build-arg GITHUB_TOKEN=<gh-token> .
docker run -p 8501:8501 flashapp:latest # → http://localhost:8501
# Dockerfile.arm is the linux/arm64 variant (swaps miniforge installer to aarch64).Python is pinned to 3.11 (matches the Docker runtime). GITHUB_TOKEN is required at build time to fetch the private openms-streamlit-vue-component submodule and OpenMS resources.
These are already the defaults on the main/release branches; verify them when building or debugging a blank viewer:
- Submodule present:
git submodule init && git submodule update(update to latest:git submodule update --remote). - Vue component built & copied: the bundle in
js-component/dist/is produced from theopenms-streamlit-vue-component/submodule (a Vite/Vue project). Always prefer building the bundle via Docker, never a local Node toolchain — the repoDockerfilejs-buildstage (node:21→npm install && npm run build) is the canonical, reproducible build. To rebuild the committed bundle from local submodule source (e.g. after editing a.vuefile), use a small Docker stage thatCOPYs the local submodule and runsnpm run build, then export and copydist/overjs-component/dist/:FROM node:21 AS build WORKDIR /openms-streamlit-vue-component COPY . . RUN npm install && npm run build FROM scratch AS export COPY --from=build /openms-streamlit-vue-component/dist /
Only the prebuiltdocker build -f vue-build.Dockerfile --target export \ --output type=local,dest=./vue-dist openms-streamlit-vue-component # then replace js-component/dist/ with ./vue-dist/
js-component/dist/is committed; the submodule source is fetched separately. (A bare localnpm install && npm run buildalso works but is not preferred — Docker guarantees the toolchain.) src/render/components.py→_RELEASE = True(loads the bundle fromjs-component/dist/). WhenFalse, the component is loaded from the Vite dev server athttp://localhost:5173for live Vue development..streamlit/config.toml→developmentMode = false.
Build order matters: the OpenMS/TOPP build must precede the Vue build in the Dockerfiles (see recent commits reordering this).
--no-cacheis recommended for the full image.
Every sub-app follows the same path; understanding it requires reading src/Workflow.py, src/parse/, src/workflow/FileManager.py, and src/render/:
mzML upload ──► WorkflowManager.execution()
└─ executor.run_topp('FLASHDeconv' / 'FLASHTnT' / 'DecoyDatabase')
└─ writes out_deconv.mzML, annotated.mzML, *.tsv, *.feature, *.msalign
└─ src/parse/* turns those into pandas DataFrames
└─ FileManager.store_data(dataset_id, key, df) ──► workspace cache
│
Viewer page ◄── render_grid() (src/render/render.py) ◄── reads cached dfs + layout ◄──┘
└─ get_component_function() ──► Vue `flash_viewer_grid` component
- Workflows:
src/Workflow.pydefinesDeconvWorkflow,TagWorkflow(FLASHTnT), andQuantWorkflow, all subclasses ofWorkflowManager(src/workflow/WorkflowManager.py). Each implementsupload(),configure(),execution(),results().execution()runs TOPP tools, stores every output file viaFileManager.store_file(), then calls the parsers.TagWorkflowchainsDecoyDatabase→FLASHDeconv→FLASHTnT. - Parsers (
src/parse/):deconv.py::parseDeconv,tnt.py::parseTnT,quant.py::parseQuant/flashquant.py::parseFLASHQuantOutputare the entry points. The mzML→DataFrame heavy lifting lives inmasstable.py(parseFLASHDeconvOutput,parseFLASHTaggerOutput) using a multiprocessing pool;tag_resolution.pymaps tags ↔ proteoforms. - Renderers (
src/render/):render.py(render_grid,render_component) pushes state into the Vue component and reads user selections back out.components.pydeclares the component and defines the per-cell component classes:PlotlyHeatmap,Tabulator(Scan/Mass/Protein/Tag tables),PlotlyLineplot,Plotly3Dplot,FDRPlotly,SequenceView,InternalFragmentMap,FLASHQuant.compression.pycompresses payloads sent to the browser;StateTracker.pytracks selection state across cells (cross-component linking via shared scan/mass identifiers).
Each sub-app's pages (in content/<SubApp>/) are registered in app.py. The distinctive FLASHApp concept is the Layout Manager (FLASHDeconvLayoutManager.py, FLASHTnTLayoutManager.py): a grid editor where the user composes which visualization components appear in which cells (≤5 experiments, ≤3 columns/row). The chosen layout is persisted to the workspace cache and the Viewer page renders it (falling back to a built-in default if none is saved).
- Layout is stored via
FileManager.store_dataunder dataset key'layout'for FLASHDeconv and'flashtnt_layout'for FLASHTnT (separate namespaces — they share the underlyingdeconv_dfs/anno_dfsdata but keep independent layouts). It is JSON-importable/exportable. - Sequence Input (
FLASHDeconvSequenceInput.py) saves a proteoform sequence + fixed modifications to the'sequence'dataset; doing so unlocks theSequence viewandInternal fragment mapcomponents in the Layout Manager. - FLASHQuant is simpler: File Upload + a single fixed-layout Viewer, no Layout Manager, and uses a separate cache subdirectory.
State lives in per-session workspaces (enable_workspaces: true, workspaces_dir: ".." → ../workspaces-FLASHApp/). FileManager (src/workflow/FileManager.py) is the single gateway to the workspace's cache/: store_file, store_data, get_results, result_exists, get_results_list, get_files, keyed by a dataset_id (typically <filename>_<timestamp>). Demo workspaces are seeded from example-data/workspaces/ (demo_workspaces in settings.json).
ParameterManager (src/workflow/ParameterManager.py) persists widget state to JSON and generates TOPP .ini files. configure() exposes TOPP tool parameters via self.ui.input_TOPP('FLASHDeconv', exclude_parameters=[...], custom_defaults={...}). Widget keys must match keys in default-parameters.json. presets.json holds named parameter bundles (test_parameter_presets.py guards this).
The container entrypoint starts Redis + one or more RQ workers (queue openms-workflows) + Streamlit. When STREAMLIT_SERVER_COUNT > 1, it runs N Streamlit instances behind an nginx load balancer with sticky-cookie session routing. QueueManager (src/workflow/QueueManager.py) offloads execution() to RQ when online_deployment is set. The entrypoint is written to tolerate Apptainer/Singularity read-only rootfs (all runtime state goes under $RUNTIME_DIR, default /tmp/opendiakiosk). k8s/ is a kustomize base + overlays/prod deploying to namespace openms as ghcr.io/openms/flashapp:latest behind nginx/traefik ingress; clean-up-workspaces.py runs via cron for periodic GC.
build-and-test.yml— multi-arch (amd64 + arm64) Docker build → merged manifest, kustomize/kubeconform lint, and container smoke tests under apptainer / nginx-on-kind / traefik-on-kind, then publishes images + an ORAS SIF to GHCR. (Its "test" jobs are deployment smoke tests, not pytest.)unit-tests.yml— the pytest suite.pylint.yml— lint.build-windows-executable-app.yaml+test-win-exe-w-embed-py.yaml— the PyInstaller desktop build.ghcr-cleanup.yml— registry GC.
app.pysets multiprocessing start method tospawn(polars + Unix fork are incompatible) and importspyopenmsearly (required for the Windows build). Don't remove these.- Running workflows locally needs the TOPP binaries (
FLASHDeconv,FLASHTnT) onPATH— they ship only in the full Docker image. The upload/viewer/download paths work on pre-computed result files without them. - Windows packaged build:
run_app.py+run_app_temp.spec(PyInstaller). Awindowsarg insys.argvtriggers a working-directorychdirinpage_setup(). - Pages start with
page_setup()fromsrc/common/common.py, which initializes the workspace, sidebar, and params; callsave_params(params)at the end. Useshow_fig()/show_table()for consistent display. - Decorate
configure()/ page sections with@st.fragmentfor partial reruns. - Workflow display names map to lowercase-hyphenated keys ("FLASHTnT" → workflow dir / preset keys); TOPP params use colon paths (
tag:min_length).