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

# Extend the agent image

> Build a derived agent image that layers extra plugins on top of the base formae image, then deploy it wherever you run the agent.

The base formae agent image at
`ghcr.io/platform-engineering-labs/formae` ships with the standard plugin set:
`aws`, `azure`, `gcp`, `oci`, `ovh`, and `auth-basic`. If you deploy through one
of the cloud install guides to manage one of those clouds, you are done, with no
extra steps.

To manage anything else (`grafana`, `datadog`, `k8s`, `gha`, `gitlab`, `compose`,
`databricks`, and so on) build a derived image that layers the plugin on top of
the base, then point your deployment at the derived image. `formae plugin install`
runs locally on the host that invokes it; for a cloud-deployed agent the derived
image is the supported path.

## Dockerfile pattern

```dockerfile theme={"languages":{"custom":["/languages/pkl.json"]}}
ARG BASE_VERSION=0.87.1
FROM ghcr.io/platform-engineering-labs/formae:${BASE_VERSION}

USER root

RUN apt-get update && \
    apt-get install -y --no-install-recommends jq curl && \
    HOME=/home/pel /bin/bash -e -c "$(curl -fsSL https://hub.platform.engineering/get/setup.sh)" -- install --yes <plugin-name> && \
    apt-get purge -y --auto-remove jq curl && \
    rm -rf /var/lib/apt/lists/* && \
    /opt/pel/bin/formae clean --all

RUN chown -R pel:pel /opt/pel

USER pel
WORKDIR /home/pel
```

Replace `<plugin-name>` with the plugin you want. Add more plugins to the same
`install` invocation by space-separating them.

<Warning>
  The `chown -R pel:pel /opt/pel` is required. The plugin install runs as `root`
  and can leave root-owned files under `/opt/pel`. The agent runs as `pel` and
  refuses to start when its install tree is root-owned, and the image has no `sudo`,
  so restore ownership at build time.
</Warning>

## Build and verify locally

```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
docker build -t formae-extended:test .
docker run --rm formae-extended:test /opt/pel/bin/formae plugin list
```

The plugin you added should appear alongside the standard set. To confirm the
agent loads it at startup:

```bash theme={"languages":{"custom":["/languages/pkl.json"]}}
docker run --rm -p 49684:49684 formae-extended:test
# In another shell:
docker logs <container> 2>&1 | grep "Plugin registered"
```

Look for a `Plugin registered: namespace=<UPPERCASE>` line for the plugin you
added.

## Deploy the derived image

Each install path pulls the agent image from its own registry. Push the derived
image to the registry your deployment reads from, then point the deployment at it
instead of `ghcr.io/.../formae:latest`.

* **AWS (Bootstrap):** push to ECR, then pass the derived image as `--formae-image` when you [install or upgrade the agent](/documentation/guides/install-agent).
* **Azure Container Instances:** push to ACR (or any registry the ACI managed identity can read), then set `--image` on the [Azure deploy](/documentation/guides/install-agent-azure).
* **GCP Cloud Run:** push to an Artifact Registry repository in the same project, then set `--image` on the [GCP deploy](/documentation/guides/install-agent-gcp).
* **Kubernetes / Helm:** push to any registry the cluster can pull from, then override the chart image with `--set image.repository=<your-registry>/formae-extended --set image.tag=<your-tag>` on the [Helm install](/documentation/guides/install-agent-helm).

## Verify the running agent

`formae plugin list` reads the local `/opt/pel` tree only; there is no remote API
for plugin inspection. To verify a cloud-deployed agent loaded the plugin, exec
into the running container or read its startup logs.

| Deployment                | Verification                                                                                                                                                                          |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AWS ECS                   | `aws ecs execute-command --cluster <c> --task <t> --container formae-agent --interactive --command /bin/sh`, then `formae plugin list` (the service needs `--enable-execute-command`) |
| Azure Container Instances | `az container exec --resource-group <rg> --name <name> --exec-command /bin/sh`, then `formae plugin list`                                                                             |
| GCP Cloud Run             | No interactive exec; use `gcloud logging read` and look for the `Plugin registered` line at startup                                                                                   |
| Kubernetes                | `kubectl exec deploy/<release-name> -- formae plugin list`                                                                                                                            |

## Known constraints

* The formae CLI talks only to an agent on the same version. Whoever runs the CLI against a derived-image deployment must run the version the image ships. Update the local CLI with `formae update <version>`.
* `BASE_VERSION` pins the image tag, not the agent binary: a `:0.87.1` image can ship a slightly newer binary because the base resolves the version at build time. To pin the binary deterministically, add an explicit `setup.sh install --yes formae@<exact-version>` step before the plugin install.
