# First app run **You will learn:** how to discover PlayMolecule apps, set up a job for one, run it locally, and find its outputs. **Prerequisites:** - [`playmolecule` installed](../installation.md) with a working registry (default GCloud Docker registry, or your own `PM_REGISTRIES`). - Docker (or Apptainer) available on your machine. We'll use `proteinprepare`, the app that protonates a protein at a chosen pH, as the running example. The recipe is the same for every app — they're all just Python functions. ## Setup ```python from playmolecule import describe_apps from playmolecule.apps import proteinprepare ``` {py:func}`~playmolecule.describe_apps` is the entry point for discovery. `playmolecule.apps` is the namespace where every installed app appears as an importable submodule. ## Step 1 — See what's installed ```python describe_apps() ``` You'll see lines like: ```text ProteinPrepare playmolecule.apps.proteinprepare.v1.proteinprepare ProteinPrepare despite it's name prepares proteins but also other systems including nucleic acids DeepSite playmolecule.apps.deepsite.v1.deepsite Predict ligand binding pockets in your protein of interest using a neural network-based predictor. ... ``` The first line has the human-readable name followed by the **fully qualified import path**; the indented second line is the one-sentence description from the app's manifest. The qualified path looks like `playmolecule.apps...` — but you don't need to type the version; the latest one is aliased at `playmolecule.apps.` (see [Select an app version](../howto/select-an-app-version.md)). If you want the data as a dict instead of printed output: ```python apps = describe_apps(as_dict=True) apps["playmolecule.apps.proteinprepare.v1.proteinprepare"]["description"] ``` ## Step 2 — Inspect a single app Every app is a normal Python function with a generated signature and docstring: ```python help(proteinprepare) ``` `help` shows the parameter list pulled from the app manifest — names, types, defaults, descriptions, expected outputs, and any built-in examples. In IPython, `proteinprepare?` is equivalent. ## Step 3 — Set up the job Calling the app function **does not run anything**; it sets up an {py:class}`~playmolecule.ExecutableDirectory`: ```python ed = proteinprepare(outdir="out", pdbid="3ptb") ``` After this call, `./out/` exists on disk with everything the container needs to execute: a `run__/` inputs directory, the rendered run script, and the manifest's input JSON. `ed` is just a handle on that directory. Nothing has executed yet — you can still tweak files in `./out/` if you want to. ## Step 4 — Run the job ```python ed.run() ``` This pulls the app's container image if it isn't cached, runs it against the inputs directory, and streams logs to stdout. When `run()` returns, the job is done. (Caveat: against an HTTP backend, `run()` submits asynchronously and returns immediately — see [Log in to the HTTP backend](../howto/log-in-to-the-http-backend.md) and set `PM_BLOCKING=1` if you want the call to wait.) ## Step 5 — Check status and outputs ```python print(ed.status) ``` You'll see `JobStatus.COMPLETED` (or `JobStatus.ERROR` if something failed). The full list of states is in {py:class}`~playmolecule.JobStatus`. The outputs are sitting in `./out/`. For `proteinprepare`: ```text out/ ├── output.pdb # the protonated structure ├── details.csv # residue-by-residue protonation report ├── pka_plot.png # pKa plot └── run_/ # input manifest + logs + run script ``` What lands in `outdir` is defined by the app's manifest — `help(proteinprepare)` lists the `Outputs` section. ## Step 6 — Shorter syntax You can chain the call and the run in one line: ```python proteinprepare(outdir="out", pdbid="3ptb").run() ``` This is fine for ad-hoc work. Keep the `ed` binding when you want to query status later, submit to SLURM, or batch several jobs together. ## Recap - {py:func}`~playmolecule.describe_apps` lists everything available. - Every app is a Python function that accepts manifest-defined parameters and returns an {py:class}`~playmolecule.ExecutableDirectory`. - Calling the app **sets up** a job; calling {py:meth}`~playmolecule.ExecutableDirectory.run` **executes** it. - {py:attr}`ed.status ` tells you whether the run succeeded. ## Next - [Using app versions and tests](02-using-app-versions-and-tests.md) - [Pass input files to an app](../howto/pass-input-files-to-an-app.md) - [What an {py:class}`~playmolecule.ExecutableDirectory` is](../explanation/executable-directory.md)