Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions src/content/docs/authoring/execution.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ A requirement check (see [Requirements](/authoring/manifest-reference/#requireme

Every job gets a private **work directory** (`$FG_WORK_DIR`), and a checkout of the project at the app's **pinned commit** is symlinked into it as `repo`. The `working_dir` runnable field controls which of these the command runs from:

- **`repo`** (default for most runnables) — the script `cd`s into `$FG_WORK_DIR/repo` (or the manifest's subdirectory within it). Use this when the command relies on the project being the current directory — for example Pixi tasks, or scripts that reference sibling files with relative paths.
- **`manifest`** (default for most runnables) — the script `cd`s into the manifest's directory within the checkout: `$FG_WORK_DIR/repo` when the manifest is at the repo root, or its subdirectory when the manifest lives deeper (e.g. a monorepo). Use this when the command relies on being run from beside the manifest — for example Pixi tasks, or scripts that reference sibling files with relative paths.
- **`repo`** — the script `cd`s into the checkout root (`$FG_WORK_DIR/repo`) regardless of where the manifest lives. Use this for a manifest in a subdirectory whose command still needs to run from the top of the project.
- **`work`** (default for **container** runnables) — the script `cd`s into `$FG_WORK_DIR`. The project is still reachable via the `repo` symlink (e.g. `nextflow run repo`). Use this for tools that should write their outputs into a clean per-job directory rather than the project checkout (which is shared by every job running the same version of the app).

The checkout is per-version: jobs of an app that hasn't been updated share one checkout (so e.g. a Pixi environment builds once and is reused), and updating the app gives subsequent jobs a fresh checkout of the new commit while running jobs keep the one they started with.
Expand All @@ -61,7 +62,7 @@ runnables:
working_dir: work
```

Containers default to `work` because the project checkout is **not** bind-mounted into the container (only the work directory and your file/directory parameters are), so a container's current directory should be the work dir. A container runnable that genuinely needs the project can set `working_dir: repo` — Fileglancer then bind-mounts the checkout into the container automatically so the command can run from it and read the project's files.
Containers default to `work` because the project checkout is **not** bind-mounted into the container (only the work directory and your file/directory parameters are), so a container's current directory should be the work dir. A container runnable that genuinely needs the project can set `working_dir: manifest` or `working_dir: repo` — Fileglancer then bind-mounts the checkout into the container automatically so the command can run from it and read the project's files.

## Environment Variables

Expand Down Expand Up @@ -202,7 +203,7 @@ apptainer exec --bind /home/user/.fileglancer/jobs/1-lolcow-say "$SIF_PATH" \
'Hello from Fileglancer!'
```

**Bind mounts** are auto-detected from `file` and `directory` parameters — the effective values the command is built from, so manifest defaults and parameters declared in `env_parameters` are bound too, not just values the user typed. The job's working directory is always bound, and when `working_dir: repo` is set, the cached repo clone is bound as well. Use `bind_paths` to add extra paths:
**Bind mounts** are auto-detected from `file` and `directory` parameters — the effective values the command is built from, so manifest defaults and parameters declared in `env_parameters` are bound too, not just values the user typed. The job's working directory is always bound, and when `working_dir` is `manifest` or `repo`, the cached repo clone is bound as well. Use `bind_paths` to add extra paths:

```yaml
container: ghcr.io/org/image:tag
Expand Down
4 changes: 2 additions & 2 deletions src/content/docs/authoring/manifest-reference.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ The `runnables.yaml` manifest describes your app. This page documents its struct
|-------|------|----------|-------------|
| `name` | string | yes | Display name shown in the Fileglancer UI |
| `description` | string | no | Short description of the app |
| `repo_url` | string | no | GitHub URL of a separate repository containing the tool code (see [Separate Tool Repo](/authoring/overview/#separate-tool-repo)). Must be a valid GitHub repository URL — the manifest is rejected at load time otherwise |
| `repo_url` | string | no | GitHub URL of a separate repository containing the tool code (see [Separate Tool Repo](/authoring/overview/#separate-tool-repo)). Only takes effect when it names a *different* repository (`owner/repo`); pointing it at the manifest's own repo is ignored, and the job runs from the manifest's branch and pinned commit. Must be a valid GitHub repository URL — the manifest is rejected at load time otherwise |
| `requirements` | list of strings | no | Tools that must be available in the job environment (see [Requirements](#requirements)) |
| `runnables` | list of objects | yes | One or more runnable definitions (see [Runnables](#runnables)). A manifest with an empty `runnables` list is rejected |

Expand All @@ -38,7 +38,7 @@ Each runnable defines a single command that users can launch. If a manifest has
| `container` | string | no | Container image URL for Apptainer (see [Containers](/authoring/execution/#containers-apptainer)) |
| `bind_paths` | list of strings | no | Additional paths to bind-mount into the container (requires `container`) |
| `container_args` | string | no | Default extra arguments for container exec (e.g. `--nv`), overridable at launch time |
| `working_dir` | string | no | Where the command runs: `repo` (the cloned project, optionally the manifest's subdirectory) or `work` (the job's work directory). Defaults to `work` for container runnables and `repo` otherwise (see [Execution Environment](/authoring/execution/#working-directory)) |
| `working_dir` | string | no | Where the command runs: `manifest` (the manifest's directory inside the cloned project), `repo` (the cloned project's root), or `work` (the job's work directory). Defaults to `work` for container runnables and `manifest` otherwise (see [Execution Environment](/authoring/execution/#working-directory)) |
| `auto_url` | boolean | no | Service runnables only. When `true`, Fileglancer publishes the service URL for you once `$FG_SERVICE_PORT` is accepting connections — bind your service to `$FG_SERVICE_PORT` and you need no URL-writing code (see [Services](/authoring/services/)) |
| `service_url_suffix` | string | no | Service runnables with `auto_url`. Text appended to `http://$FG_HOSTNAME:$FG_SERVICE_PORT` when publishing — a path and/or query, e.g. `/?access_token=${FG_SERVICE_TOKEN}` for one-click auth. May contain literal URL text and the placeholders `${FG_SERVICE_TOKEN}`, `${FG_SERVICE_PORT}`, `${FG_HOSTNAME}` (braces required); nothing else (see [Services](/authoring/services/)) |
| `requirements` | list of strings | no | Additional tool requirements specific to this runnable, merged with manifest-level requirements |
Expand Down
2 changes: 2 additions & 0 deletions src/content/docs/authoring/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ When `repo_url` is set:
- The discovery repo (containing `runnables.yaml`) is used only for manifest metadata.
- The tool repo (`repo_url`) is cloned separately and used as the working directory for the job.

`repo_url` only triggers this separate-repo behavior when it points to a *different* repository (a different `owner/repo`); the branch is ignored in that comparison. If `repo_url` names the **same** repository the manifest lives in, it is not treated as separate — the job runs from the manifest's own branch and pinned commit. So a manifest on a non-default branch does not need `repo_url` pointing back at itself; doing so with a bare URL (no `/tree/<branch>`) would otherwise imply the repo's default branch. Omit `repo_url` unless the code genuinely lives in another repository.

Repos are cloned into a per-user cache, and every app is **pinned to an exact commit** when it is added. Jobs run from an immutable per-commit checkout of the pinned code — they never pull automatically, and nothing can change a job's code while it runs. To get the newest code, use the **Update** action for the app in the UI, which pulls the latest commits on the app's revision, re-reads the manifest, and re-pins the app (both the manifest repo and the `repo_url` tool repo, when one is declared). Updates are per-app: other apps sharing the same repository keep their own pinned commits.

## Where to Go Next
Expand Down
56 changes: 52 additions & 4 deletions src/content/docs/authoring/parameters.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ Each parameter with a `flag` field becomes a CLI flag appended to the base comma
| `raw` | boolean | no | If `true`, the value is appended to the command without shell quoting. Validated against shell metacharacters for safety. Default: `false` |
| `value_separator` | string | no | How a flagged parameter is joined to its value: `"space"` emits `--flag 'value'`, `"equals"` emits `--flag='value'`. Use `equals` for tools (like Nextflow) that would otherwise misparse a value starting with `-` as another flag. Default: `"space"` |
| `boolean_style` | string | no | Only valid on `boolean` parameters. `"flag"` emits the bare flag when true and omits it when false; `"value"` emits an explicit `--flag true` / `--flag false` (or `--flag=true` / `--flag=false` with `value_separator: equals`). Use `value` for tools where omitting a false switch would leave a default of true in effect. Default: `"flag"` |
| `exists` | boolean | no | Only valid on `file` and `directory` parameters. When `true` (the default), the path must exist and be readable before launch. Set `false` for outputs the job creates: the existence check is skipped, and `directory` parameters are created (as the user, within an allowed file share) before launch, so a home default like `~/.fileglancer/logs` works on first launch. Default: `true` |
| `exists` | boolean | no | Only valid on `file`, `directory`, and `path` parameters. When `true` (the default), the path must exist and be readable before launch. Set `false` for outputs the job creates: the existence check is skipped, and `directory` parameters are created (as the user, within an allowed file share) before launch, so a home default like `~/.fileglancer/logs` works on first launch. Default: `true` |
| `associations` | object | no | Only valid on `file`, `directory`, and `path` parameters. Declares which file types this parameter accepts, so the file browser can offer the app when the user navigates to a matching file or directory. See [File Associations](#file-associations) |

## Parameter Types

Expand All @@ -39,17 +40,64 @@ Each parameter with a `flag` field becomes a CLI flag appended to the base comma
| `boolean` | Checkbox | `--flag` (if true, omitted if false); `--flag true` / `--flag false` with `boolean_style: value` | N/A | Must be true/false |
| `file` | Text input + file browser | `--flag '/path/to/file'` | `'/path/to/file'` | Must be an absolute path that exists, is readable, and points to a file on the server (unless `exists: false`) |
| `directory` | Text input + directory browser | `--flag '/path/to/dir'` | `'/path/to/dir'` | Must be an absolute path that exists, is readable, and points to a directory on the server (unless `exists: false`) |
| `path` | Text input + file/directory browser | `--flag '/path/to/item'` | `'/path/to/item'` | Must be an absolute path that exists and is readable on the server (unless `exists: false`). Accepts either a file or a directory — no type check. Useful for inputs that take both, e.g. TIFF files and OME-Zarr directories |
| `enum` | Dropdown select | `--flag 'chosen_value'` | `'chosen_value'` | Value must be one of the `options` list |

**Notes on `file` and `directory` types:**
**Notes on `file`, `directory`, and `path` types:**

- The UI provides a browse button alongside the text input, so users can pick paths from the Fileglancer file browser instead of typing them.
- Paths are validated server-side before job submission (must exist, be accessible, and match the expected file/folder type, unless `exists: false`).
- Paths are validated server-side before job submission (must exist, be accessible, and match the expected file/folder type, unless `exists: false`; `path` parameters accept either kind).
- Both absolute paths (`/data/images`) and home-relative paths (`~/output`) are accepted.
- Shell metacharacters (`;`, `&`, `|`, `` ` ``, `$`, `(`, `)`, etc.) are rejected for safety.
- Set `exists: false` on paths the job creates, such as an output or logs directory. The path is still validated for file-share containment, but not for existence. If the path already exists, Fileglancer still checks that it matches the expected file/folder type. Fileglancer additionally creates `exists: false` directories (as the user, within an allowed file share) just before launch, so a default like `~/.fileglancer/logs` works out of the box and overrides that point at a new directory are created too. Overrides pointing at an existing directory are a no-op. This never creates anything outside a file share. `file` parameters with `exists: false` skip the existence check but nothing is created for them.
- Set `exists: false` on paths the job creates, such as an output or logs directory. The path is still validated for file-share containment, but not for existence. If the path already exists, Fileglancer still checks that it matches the expected file/folder type. Fileglancer additionally creates `exists: false` directories (as the user, within an allowed file share) just before launch, so a default like `~/.fileglancer/logs` works out of the box and overrides that point at a new directory are created too. Overrides pointing at an existing directory are a no-op. This never creates anything outside a file share. `file` and `path` parameters with `exists: false` skip the existence check but nothing is created for them (a `path` parameter's kind is ambiguous, so Fileglancer cannot know whether to create a directory).
- Apps auto-detected from a Nextflow pipeline's `nextflow_schema.json` follow the same convention as [nf-schema](https://nextflow-io.github.io/nf-schema/): a path parameter only requires existence when the schema property sets `"exists": true`.

## File Associations

`file`, `directory`, and `path` parameters can declare `associations`: the file types they accept. When a user navigates to a matching file or directory in the Fileglancer file browser, a **Compatible apps** panel appears above the listing. Clicking the app opens its launch form with the browsed path already filled into the associated parameter.

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `extensions` | list of strings | no | Name suffixes to match, e.g. `[.tif, .czi]`. Case-insensitive; a missing leading dot is added automatically. Multi-part suffixes match against the end of the name, so `.ome.zarr` works |
| `capabilities_manifest` | string | no | Repo-relative path to a [capability manifest](https://github.com/BioImageTools/capability-manifest) YAML file describing the OME-Zarr data the app supports — the same standard Fileglancer uses to pick compatible OME-Zarr web viewers. Accepts either a full manifest (`viewer:` + `capabilities:` sections) or a bare capabilities mapping. Resolved when the app manifest is loaded, so the pinned app snapshot carries its capabilities with it. Only valid on `directory` and `path` parameters |
| `label` | string | no | Display label shown in the file browser panel, e.g. `TIFF images`. Defaults to the parameter's `name` |

At least one of `extensions` or `capabilities_manifest` must be declared. Capability manifests are a separate standard and always live in their own file — they cannot be inlined in `runnables.yaml`.

### Matching Rules

- A `file` parameter only matches files, a `directory` parameter only matches directories, and a `path` parameter matches both.
- For a Zarr dataset (detected by content, not by name), declared capabilities are **authoritative**: the app is offered only when the compatibility check passes, even if `.zarr` is also listed in `extensions`. Plain (non-OME) Zarr never matches a capabilities rule, since compatibility cannot be verified.
- Everything else matches by case-insensitive name suffix.

This lets one input register many file types with different handling. For example, an image converter that accepts TIFF and CZI files by extension, plus the OME-Zarr datasets it can actually read:

```yaml
# runnables.yaml
parameters:
- flag: --input
name: Input image
type: path
required: true
associations:
extensions: [.tiff, .czi, .zarr]
capabilities_manifest: capabilities.yaml
label: Convertible images
```

```yaml
# capabilities.yaml (next to runnables.yaml)
capabilities:
ome_zarr_versions: [0.4, 0.5]
compression_codecs: [blosc, zstd, gzip]
```

This app appears for every `.tiff` and `.czi` file. For Zarr datasets, the capability manifest decides: an OME-Zarr 0.4 dataset compressed with blosc matches, while an unsupported version or codec hides the app — even though `.zarr` is in the extensions list.

<Aside type="note" title="Existing installs">
Installed apps cache their manifest, so associations added to an app after a user installed it take effect once the user clicks **Update** on the app.
</Aside>

## Flag Forms

Parameters support three flag styles:
Expand Down
Loading