> ## Documentation Index
> Fetch the complete documentation index at: https://sitectl.libops.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Components

> How sitectl uses components to model optional stack capabilities and help operators turn features on and off safely.

export const Compose = () => <Tooltip headline="Compose" tip={<>
        Docker Compose is Docker's tool for defining and running multi-container applications.{" "}
        <a href="https://docs.docker.com/compose/">https://docs.docker.com/compose/</a>.
      </>}>
    <>
      <Icon icon="docker" />
      {" "}
      Compose
    </>
  </Tooltip>;

Components are how sitectl models optional capabilities within a stack. Instead of treating a <Compose /> project as one large, all-or-nothing setup, components let each optional feature carry its own defaults, configuration rules, and operator guidance.

## What a component does

When a plugin defines a component, sitectl can:

* **Ask about it during site creation**, prompting you to enable or disable it before the first launch.
* **Report its current state.** `sitectl component describe` lists all components registered by the active context's plugin and shows whether each one is on, off, or out of alignment with the project files.
* **Apply state changes safely.** `sitectl set <name> <disposition>` previews the transition, confirms destructive changes, and updates the component-owned files immediately. Simple components accept `on`/`off` aliases; topology components expose named dispositions such as `triplet` or `distributed`. `sitectl converge` is for later drift repair.

## Component states

A component can be in one of two states:

| State | Meaning                                                                                  |
| ----- | ---------------------------------------------------------------------------------------- |
| `on`  | The component is active and its services, configuration, and Drupal modules are in place |
| `off` | The component is inactive; its services and configuration are removed or suppressed      |

Within a state, a component also has a **disposition** that describes the selected implementation or topology. It is derived from the current project files, not retained as historical state:

| Disposition   | Meaning                                                                                                                                     |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| `enabled`     | Explicitly turned on by an operator                                                                                                         |
| `disabled`    | Explicitly turned off by an operator                                                                                                        |
| `superseded`  | Replaced by a different component or approach. The legacy `superceded` spelling is accepted for RPC v1 compatibility but is never rendered. |
| `distributed` | Plugin-specific distributed topology, such as routing ISLE IIIF traffic to an external upstream                                             |
| `cantaloupe`  | Use Cantaloupe as the selected ISLE IIIF implementation                                                                                     |
| `triplet`     | Use Triplet as the selected ISLE IIIF implementation                                                                                        |
| `nested`      | Keep the ISLE Drupal codebase in the template's nested web root                                                                             |
| `git-root`    | Treat the downstream repository root as the Drupal Composer codebase                                                                        |

## Checking component state

```bash theme={null}
# Show all components for the active context's plugin
sitectl component describe

# Target a specific project directory
sitectl component describe --path /path/to/project
```

This reports every registered component: its name, current disposition, and whether the live project files match what sitectl expects. A `drifted` status means the project does not match one complete supported disposition. Sitectl derives that result from the current files; it does not compare them with historical component state.

Use `--verbose` to show the failed checks behind a drifted component:

```bash theme={null}
sitectl component describe --verbose
sitectl component describe --component blazegraph --verbose
```

When a drifted component blocks another change, sitectl prints the files and checks that failed, such as a missing Drupal config sync file or an unexpected value in `docker-compose.yml`.

## Turning components on and off

```bash theme={null}
# Using the top-level set command
sitectl set fcrepo off
sitectl set blazegraph on

# Using a plugin namespace when multiple plugins are involved
sitectl set isle/fcrepo off
```

After a successful `sitectl set`, the relevant <Compose /> and application configuration files are already updated. Review and commit those changes in the downstream template fork.

<Warning>
  Component changes can rewrite owned fields in <Compose />, Drupal configuration,
  JSON, and marked text blocks. Make sure you have a recent backup before enabling
  or disabling components on a production site.
</Warning>

## Applying changes with converge

```bash theme={null}
# Preview what would change
sitectl converge --report

# Apply changes interactively
sitectl converge

# Apply changes for a single component
sitectl converge --component fcrepo
```

`converge` reads the selected dispositions and non-secret settings from
`.libops/site.yaml`, compares them with component-owned project paths, and
builds a typed plan before changing anything. Use `--report` to inspect the
plan. Unknown components and unclassified changes block mutation; service
restarts and destructive operations are identified explicitly.

The canonical Compose template remains the runnable base. Components define the
deterministic transformations that produce the selected application topology.
Context-specific Compose files, such as a tracked development override, remain
ordered execution inputs and are not silently absorbed into component intent.

## The create flow

When you run `sitectl create isle`, sitectl asks you about each component that has a meaningful architectural choice, such as whether to include Fedora or Blazegraph. You can answer interactively or pass flags to skip the prompts. Your choices are applied to the project before the first launch.

Component follow-up flags are non-secret configuration. They can cross the
host/plugin boundary as process arguments, so never pass passwords, tokens, private
keys, or other sensitive values through a component follow-up. Use the template's
documented Compose secret or secret-store flow instead.

## Current ISLE components

<AccordionGroup>
  <Accordion title="fcrepo">
    Fedora Commons repository. The LibOps default is `superseded` with Drupal private files. Use `enabled` for a Fedora-backed Islandora repository or `superseded` with `--isle-file-system-uri` when another filesystem backend replaces Fedora. See [fcrepo](/plugins/isle/fcrepo).
  </Accordion>

  <Accordion title="blazegraph">
    Blazegraph triple store. The LibOps default is `disabled`. Use `enabled` for RDF/SPARQL indexing or `disabled` for stacks that do not use linked data queries. See [Blazegraph](/plugins/isle/blazegraph).
  </Accordion>

  <Accordion title="iiif">
    Controls which IIIF image server implementation the stack uses. The LibOps default is `triplet`. `cantaloupe` keeps the Cantaloupe service and `/cantaloupe/iiif/2` Drupal URL; `triplet` routes `/iiif`, writes Triplet config, and updates Drupal to use `/iiif/3`. See [IIIF components](/plugins/isle/iiif).
  </Accordion>

  <Accordion title="iiif-topology">
    Controls whether the selected IIIF implementation runs in the local Compose stack or behind an external upstream. The default `disabled` disposition means local. Use `distributed` with `--iiif-upstream-url` when Drupal should point to an external Cantaloupe or Triplet service and the base stack should remove the selected local IIIF service. See [IIIF components](/plugins/isle/iiif).
  </Accordion>

  <Accordion title="codebase">
    Controls the Composer-owned Drupal source layout. The LibOps default is `git-root`, where the downstream repository root is the codebase. Use `nested` only for a template that intentionally keeps Drupal under its nested web-root layout; review the resulting Dockerfile, Compose build context, and bind mounts together.
  </Accordion>

  <Accordion title="Derivative microservices">
    Controls whether `fits`, `crayfits`, `homarus`, `houdini`, and `hypercube` run in the base Compose stack or use the managed LibOps microservices. Use `distributed` to remove the service from `docker-compose.yml` and update Alpaca's service URL where applicable. Use `enabled` to restore the service locally. See [derivative microservices](/plugins/isle/derivatives).
  </Accordion>

  <Accordion title="Feature bundles">
    `mergepdf` coordinates its Compose service with the paged-content Drupal action. `hocr-search` coordinates Composer requirements, Drupal modules and configuration, IIIF annotations, and Solr search. Both are local-checkout changes that require a reviewed deploy and application-level follow-up. See [ISLE feature bundles](/plugins/isle/feature-bundles).
  </Accordion>

  <Accordion title="ingress">
    Controls public URL behavior for Traefik-backed applications. The default is `enabled --mode http --domain localhost`, so new stacks start at `http://localhost`. Use `enabled` with `--mode http|https|https-letsencrypt|https-custom|https-mkcert`, `--domain`, `--acme-email`, `--trusted-ip`, `--max-upload-size`, and `--upload-timeout` to update Traefik commands and dynamic router config together with the application settings mapped by the active plugin. PHP/nginx plugins map proxy and upload settings through every backend layer; another runtime needs an app-specific mapping before those values are end to end. `https` is the Cloudflare Origin CA path; `https-custom` reads `certs/cert.pem` and `certs/privkey.pem`; `https-mkcert` generates that pair for development contexts.
  </Accordion>

  <Accordion title="bot-mitigation">
    Controls Cloudflare Turnstile-backed Traefik challenge middleware where the application plugin supports it. Use `on` to install captcha-protect wiring and `off` to remove the middleware.
  </Accordion>

  <Accordion title="dev-mode">
    Controls the local development override. Use `enabled` to write `docker-compose.override.yml` with the app container `UID` environment value and plugin-declared host bind mounts for editable code. Add `--assistant` to include a profiled `cli-sandbox` coding-agent service using the same plugin-owned code mounts. Use `--harness codex|claude|pi|opencode|gemini`, `--model default|MODEL|URL`, and `--egress-profile interactive|managed` to select the agent and its network boundary. The default `interactive` profile is for trusted human-driven development; `managed` is only for the platform Task Agent with an operator-provided literal private model-gateway IPv4 URL. `--compose-access` and `--skip-egress-firewall` are interactive-only escape hatches and must never be enabled for a managed Task Agent. Use `disabled` to remove the override.
  </Accordion>
</AccordionGroup>

Shared ingress behavior is owned by the `ingress` component. Application plugins supply the app-specific services, routers, and environment values that must change when the ingress mode or domain changes. Healthchecks use the resulting Traefik router config to decide which scheme, host, path, and local published port to check.

## Ingress runtime tuning

The ingress component validates upload tuning before it changes the tracked Compose project:

| Option              | Accepted values                                                                                                                       | Default when omitted |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | -------------------- |
| `--max-upload-size` | Digits with an optional case-insensitive `K`, `M`, or `G` suffix. Examples: `1048576`, `128M`, `2G`. Decimals and `T` are rejected.   | `128M`               |
| `--upload-timeout`  | One integer followed by `ms`, `s`, `m`, or `h`. Examples: `500ms`, `300s`, `10m`, `1h`. Unitless and compound durations are rejected. | `300s`               |

For PHP/nginx applications, the component writes this complete tracked mapping:

| Input               | Compose application environment                                                         | Effect                                                                          |
| ------------------- | --------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------- |
| `--max-upload-size` | `PHP_UPLOAD_MAX_FILESIZE`, `PHP_POST_MAX_SIZE`, `NGINX_CLIENT_MAX_BODY_SIZE`            | PHP upload/POST limits and nginx request-body limit use the supplied value.     |
| `--upload-timeout`  | `NGINX_CLIENT_BODY_TIMEOUT`, `NGINX_FASTCGI_READ_TIMEOUT`, `NGINX_FASTCGI_SEND_TIMEOUT` | nginx receives the supplied duration unchanged.                                 |
| `--upload-timeout`  | `PHP_MAX_INPUT_TIME`, `PHP_MAX_EXECUTION_TIME`, `PHP_REQUEST_TERMINATE_TIMEOUT`         | PHP and PHP-FPM receive whole seconds; a subsecond remainder rounds up.         |
| `--upload-timeout`  | Traefik entrypoint `respondingTimeouts.readTimeout`                                     | Each configured HTTP/HTTPS entrypoint receives the supplied duration unchanged. |

This full mapping applies to Drupal, Islandora, OJS, Omeka Classic, Omeka S, and WordPress. ArchivesSpace deliberately disables the shared PHP/nginx application environment because its JVM image does not consume it. For ArchivesSpace, `--upload-timeout` changes Traefik only and `--max-upload-size` does not create a backend limit. Do not describe either value as end to end for another runtime until its plugin maps the application layer explicitly.

These are component defaults, not every image's raw Dockerfile defaults. After `sitectl set`, container environment values override image `ENV` values and confd renders the supported nginx and PHP configuration at startup. The component owns the resulting Compose fields, so manual edits can appear as drift and a later set or reconciliation can replace them. Review and commit the generated diff.

See the [developer component guide](/contributing/components) for how components are defined and what each field in the definition struct means.
