Guide through creating a new Isabl bioinformatics application. Use when building pipelines that integrate with the Isabl platform.
Installation
Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
Define application_settings for configurable paths/parameters
Implement validate_experiments() to check input validity
Implement get_dependencies() if app depends on other app results
Implement get_command() to generate the shell command
Implement get_analysis_results() to extract outputs
Register in INSTALLED_APPLICATIONS
Write tests using pytest fixtures
Step 1: Define Application Metadata
Create the application class with required metadata:
from isabl_cli import AbstractApplication, options
classMyApplication(AbstractApplication):
"""
Brief description of what this application does.
"""# Required metadata
NAME = "my_application"
VERSION = "1.0.0"# Optional: restrict to specific assembly/species
ASSEMBLY = "GRCh37"# or "GRCh38", None for any
SPECIES = "HUMAN"# or None for any
Step 2: Choose CLI Options
Configure how the application receives input experiments:
from isabl_cli import AbstractApplication, options
classMyApplication(AbstractApplication):
NAME = "my_application"
VERSION = "1.0.0"# CLI configuration
cli_help = "Run my application on experiments"
cli_options = [options.TARGETS] # or REFERENCES, PAIRS
CLI Option Types
options.TARGETS - Single or multiple target experiments
Validate input experiments before creating analyses:
from isabl_cli import AbstractApplication, options
classMyApplication(AbstractApplication):
NAME = "my_application"
VERSION = "1.0.0"
cli_options = [options.TARGETS]
defvalidate_experiments(self, targets, references):
"""
Raise AssertionError if experiments are invalid for this app.
Called before creating analyses.
"""assertlen(targets) == 1, "Requires exactly one target experiment"assert targets[0].technique.method == "WGS", "Only WGS supported"
Tumor-Normal Pair Validation
from isabl_cli import AbstractApplication, options
classMyPairApplication(AbstractApplication):
NAME = "my_pair_application"
VERSION = "1.0.0"
cli_options = [options.PAIRS]
defvalidate_experiments(self, targets, references):
assertlen(targets) == 1, "One tumor per analysis"assertlen(references) == 1, "One normal per analysis"assert targets[0].sample.category == "TUMOR"assert references[0].sample.category == "NORMAL"
Step 5: Implement get_dependencies()
Define dependencies on other application results:
from isabl_cli import AbstractApplication, options, utils
classMyApplication(AbstractApplication):
NAME = "my_application"
VERSION = "1.0.0"
cli_options = [options.TARGETS]
application_settings = {
"alignment_app_pk": 10, # PK of alignment application
}
defget_dependencies(self, targets, references, settings):
"""
Return (dependency_analyses, inputs_dict) if this app needs
results from other applications.
"""
bam, analysis_key = utils.get_result(
experiment=targets[0],
application_key=settings.alignment_app_pk,
result_key="bam"
)
return [analysis_key], {"input_bam": bam}
Step 6: Implement get_command()
Generate the shell command to execute:
from isabl_cli import AbstractApplication, options
classMyApplication(AbstractApplication):
NAME = "my_application"
VERSION = "1.0.0"
cli_options = [options.TARGETS]
application_settings = {
"tool_path": "/usr/bin/mytool",
"threads": 4,
}
defget_command(self, analysis, inputs, settings):
"""
Return the shell command to execute.
This is the core of the application.
"""
target = analysis.targets[0]
output_dir = analysis.storage_url
returnf"""
{settings.tool_path} \\
--input {target.bam_files["GRCh37"]["url"]} \\
--output {output_dir}/result.txt \\
--threads {settings.threads}
"""
Step 7: Implement get_analysis_results()
Extract output paths after successful completion:
from isabl_cli import AbstractApplication, options
classMyApplication(AbstractApplication):
NAME = "my_application"
VERSION = "1.0.0"
cli_options = [options.TARGETS]
application_results = {
"output_file": {
"frontend_type": "text-file",
"description": "Main output file",
"verbose_name": "Output",
}
}
defget_analysis_results(self, analysis):
"""
Return dict of result paths after successful completion.
Keys should match application_results.
"""return {
"output_file": f"{analysis.storage_url}/result.txt"
}
Step 8: Register in INSTALLED_APPLICATIONS
Add the application to the appropriate assembly apps module (e.g., apps_grch38):
deftest_my_application(tmpdir, commit):
import isabl_cli as ii
from isabl_cli import api, factories
from my_apps import MyApplication
# Create test experiment
experiment = api.create_instance(
"experiments",
**factories.ExperimentFactory()
)
# Run application
app = MyApplication()
app.run(
tuples=[([experiment], [])],
commit=commit
)
Complete Application Template
from isabl_cli import AbstractApplication, options
classMyApplication(AbstractApplication):
"""
Brief description of what this application does.
"""# Required metadata
NAME = "my_application"
VERSION = "1.0.0"# Optional: restrict to specific assembly/species
ASSEMBLY = "GRCh37"# or "GRCh38", None for any
SPECIES = "HUMAN"# or None for any# CLI configuration
cli_help = "Run my application on experiments"
cli_options = [options.TARGETS] # or REFERENCES, PAIRS# Configurable settings (can be overridden in database)
application_settings = {
"tool_path": "/usr/bin/mytool",
"threads": 4,
}
# Define expected results
application_results = {
"output_file": {
"frontend_type": "text-file",
"description": "Main output file",
"verbose_name": "Output",
}
}
defvalidate_experiments(self, targets, references):
"""
Raise AssertionError if experiments are invalid for this app.
Called before creating analyses.
"""assertlen(targets) == 1, "Requires exactly one target experiment"assert targets[0].technique.method == "WGS", "Only WGS supported"defget_dependencies(self, targets, references, settings):
"""
Return (dependency_analyses, inputs_dict) if this app needs
results from other applications.
"""return [], {}
defget_command(self, analysis, inputs, settings):
"""
Return the shell command to execute.
This is the core of the application.
"""
target = analysis.targets[0]
output_dir = analysis.storage_url
returnf"""
{settings.tool_path} \\
--input {target.bam_files["GRCh37"]["url"]} \\
--output {output_dir}/result.txt \\
--threads {settings.threads}
"""defget_analysis_results(self, analysis):
"""
Return dict of result paths after successful completion.
Keys should match application_results.
"""return {
"output_file": f"{analysis.storage_url}/result.txt"
}
Advanced Patterns
Multiple Targets (Cohort Analysis)
from isabl_cli import AbstractApplication, options, api
classCohortApplication(AbstractApplication):
NAME = "cohort_analysis"
VERSION = "1.0.0"
cli_options = [options.TARGETS]
unique_analysis_per_individual = False# Allow multiple targetsdefget_experiments_from_cli_options(self, **cli_options):
# Custom logic to group experiments
targets = api.get_instances("experiments", **filters)
return [(targets, [])] # Single analysis for all targets
Project-Level Merge
from isabl_cli import AbstractApplication, options
classMergeApplication(AbstractApplication):
NAME = "merge_results"
VERSION = "1.0.0"
cli_options = [options.TARGETS]
application_project_level_results = {
"merged_output": {
"frontend_type": "text-file",
"description": "Merged output across project",
}
}
defmerge_project_analyses(self, analysis, analyses):
# Combine results from all analyses in projectpassdefget_project_analysis_results(self, analysis):
return {"merged_output": f"{analysis.storage_url}/merged.txt"}
Common Issues
AssertionError in validate_experiments: Check your validation logic matches actual data
Command fails silently: Check head_job.log and head_job.err in storage_url
Dependencies not found: Ensure dependency app has SUCCEEDED status
Results not extracted: Verify paths in get_analysis_results() exist