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

# Private Agents

> Run Perfai's scanning agents inside your own Kubernetes cluster, connected outbound to your Perfai tenant — no inbound access, and no data at rest with Perfai.

## Overview

A private agent deployment splits Perfai into two planes:

* **Execution plane** — the agents and browsers that drive and scan your applications. These run in **your** cluster.
* **Control plane** — the console, platform, and your results. These stay hosted by Perfai.

The two planes talk over a single, strictly **outbound** connection your cluster opens to Perfai. Nothing on Perfai's side ever connects back into your network, so you open **no inbound ports** and expose **no endpoints**. The execution plane is stateless — it needs **no database**, and any storage it uses is handled automatically inside the cluster with nothing for you to provision.

<CardGroup cols={2}>
  <Card title="Vision Agent" icon="eye">
    Live + background — drives browsers to explore and map your apps.
  </Card>

  <Card title="Vision Browser" icon="window">
    Live + background — the headless Chromium pods the agents control.
  </Card>

  <Card title="Vision Manager" icon="diagram-project">
    Brokers browser sessions within your cluster.
  </Card>

  <Card title="Security Agent" icon="shield">
    Runs the security scans.
  </Card>
</CardGroup>

## Who it's for

A private agent deployment is the right fit when you need scanning to run inside your own environment. Common cases:

* **Enterprise applications that must stay on-premise** — the agents and all scanning traffic run in your infrastructure, not Perfai's.
* **Multi-tenant applications with regional needs** — run a deployment per region so scanning happens close to each region's data.
* **Data-residency and compliance requirements** — keep application data within your network (pair with the in-cluster model, below, so nothing leaves).
* **Large-scale programs** — teams onboarding **10 or more applications at once** get dedicated, independently-scaled in-cluster capacity.
* **Local model / LLM integration** — run the AI model inside your own cluster for full residency, or use Perfai's managed model with no GPU.

## Architecture

Every connection is initiated **from your cluster outward** to Perfai over TLS. Task instructions and results flow over that link; scanning traffic to your applications stays entirely local to your cluster.

```text theme={null}
  Your Kubernetes cluster                         Perfai (hosted)
  ┌───────────────────────────┐                  ┌────────────────────┐
  │ Vision Agent (live / bg)  │ ──── HTTPS ────▶ │  Control plane     │
  │ Vision Browser (live / bg)│   *.perfai.ai    │  • Web console     │
  │ Vision Manager            │      :443        │  • Your results    │
  │ Security Agent            │ ◀── (responses)  │  • Task queue      │
  └───────────┬───────────────┘                  └────────────────────┘
              │ local only
              ▼
     Your applications under test   (never leave your network)
```

<Info>
  **The only network requirement** is outbound HTTPS/WSS to `*.perfai.ai` on port 443 — this includes AI inference, which is routed through Perfai rather than any third-party endpoint. There is no ingress, no load balancer, and no exposed service for this deployment.
</Info>

## Prerequisites

<AccordionGroup>
  <Accordion title="Cluster">
    * **Kubernetes v1.24 or later** with functional cluster DNS.
    * Install-time access that can create a namespace and namespaced RBAC (role, service account, role binding). Standard cluster-admin at install time is sufficient — the installer creates everything; you don't hand-craft any RBAC.
    * **Storage is handled automatically** — there's nothing to provision.
  </Accordion>

  <Accordion title="Network">
    * **Outbound** HTTPS/WSS to `*.perfai.ai` on `443`.
    * **No inbound** ports. Your cluster's inbound firewall can stay fully closed.
    * Outbound access to pull container images from `ghcr.io/perfai-inc` (or request a mirrored bundle for air-gapped clusters).
  </Accordion>

  <Accordion title="Tooling">
    * `kubectl` and `helm` on the workstation running the install, with access to the target cluster context.
  </Accordion>
</AccordionGroup>

### Before you start — checklist

Confirm each item before creating a deployment:

* [ ] Kubernetes **v1.24+** cluster with working DNS, and a context your `kubectl`/`helm` can reach.
* [ ] Permission to create a **namespace** and **namespaced RBAC** at install time.
* [ ] **Outbound HTTPS to `*.perfai.ai:443`** is allowed (no inbound needed).
* [ ] Outbound access to **`ghcr.io/perfai-inc`** for images (or a mirrored bundle arranged for air-gapped clusters).
* [ ] Enough cluster capacity for your chosen concurrency (see **Cluster sizing**).
* [ ] Decided **where the AI model runs** — Perfai-managed (no GPU) or in your own cluster (needs GPU).

## Cluster sizing

Size the cluster by **how many applications you want to onboard at the same time**. Each concurrent onboarding runs one interactive browser plus a small pool of background browsers, following a strict 1:1 agent-to-browser rule.

<Note>
  **Bare minimum — 4 vCPU · 8 GB memory.** Enough to stand the cluster up and run a **single onboarding serially** (no parallelism).
</Note>

For real throughput with the background pool enabled (N = concurrent apps):

| Concurrent apps | Recommended (allocatable) | Pods |
| --------------- | ------------------------- | ---- |
| 1               | 4 vCPU · 16 GiB           | 8    |
| 2               | 8 vCPU · 32 GiB           | 14   |
| 3               | 12 vCPU · 48 GiB          | 20   |
| 4               | 16 vCPU · 64 GiB          | 26   |

Scaling is linear — roughly **4 vCPU and 16 GiB per additional concurrent app**. When you create a deployment in the console, it computes and shows the exact requirement for the concurrency you choose.

<Frame>
  <img className="docs-frame-img" src="https://mintcdn.com/perfai/mhLzv2Xevqbw5FSq/docs/images/pa-01-new-deployment.png?fit=max&auto=format&n=mhLzv2Xevqbw5FSq&q=85&s=9b8d30945cab79da4dd96ee559c8a421" alt="New deployment modal — concurrency stepper with the recommended cluster (vCPU, memory, pods)" width="1920" height="945" data-path="docs/images/pa-01-new-deployment.png" />
</Frame>

<Warning>
  **GPU is only needed if you self-host the AI model.** With Perfai's managed model (the default) no GPU is required. If you run the model inside your own cluster for full data residency, add GPU node(s) sized to that model.
</Warning>

## Security & data residency

* **Outbound-only.** No inbound path into your network exists in this design.
* **Per-deployment credential.** Each deployment gets its own credential, scoped so it can only reach your tenant's own data — enforced at the infrastructure layer, not just in application code.
* **Hardened pods.** All components run non-root, with a read-only root filesystem and all Linux capabilities dropped. No privileged containers, no host access.
* **TLS everywhere** on the link to Perfai.

### Where the AI model runs

Perfai's agents use an AI model to interpret and navigate your applications. You choose where it runs when you create the deployment:

<Tabs>
  <Tab title="Perfai-managed model (default)">
    The agents call a Perfai-managed model endpoint over the same outbound link to `*.perfai.ai` — **no third-party AI provider is ever contacted from, or exposed to, your network.** Simple; no GPU required.

    Page content the agent reasons over is processed by Perfai (acting as your data processor) and does leave your environment.
  </Tab>

  <Tab title="Model in your cluster">
    The agents call a model you host inside your own environment. **No application content ever leaves your network** — only task and result metadata is exchanged with Perfai.

    Requires GPU node(s) sized to your chosen model. Choose this if strict data residency is a requirement.
  </Tab>
</Tabs>

## Set up a deployment

Deployments are created and managed from the Perfai console; installation into your cluster is a single Helm command.

<Steps>
  <Step title="Create a deployment in the console">
    Open your tenant → **Private Agents** → **New private agent**. Set how many apps you want to onboard concurrently and where the AI model runs. The console shows the cluster size required and generates the values for this deployment.

    <Frame>
      <img className="docs-frame-img" src="https://mintcdn.com/perfai/mhLzv2Xevqbw5FSq/docs/images/pa-02-provisioning.png?fit=max&auto=format&n=mhLzv2Xevqbw5FSq&q=85&s=01ad88e8fff97ee186eed843adcd81f3" alt="New deployment form — name, concurrency, and where the AI model runs" width="1920" height="945" data-path="docs/images/pa-02-provisioning.png" />
    </Frame>
  </Step>

  <Step title="Download the values file">
    It is pre-filled with this deployment's identity, sizing, and a one-time connect secret.

    <Warning>The connect secret is shown once and is baked into the downloaded file. Save it securely now.</Warning>

    <Frame>
      <img className="docs-frame-img" src="https://mintcdn.com/perfai/mhLzv2Xevqbw5FSq/docs/images/pa-03-values-file.png?fit=max&auto=format&n=mhLzv2Xevqbw5FSq&q=85&s=c757843d20826a72c89111b5469a8e00" alt="Setup panel — download the pre-filled values file for this deployment" width="1920" height="1080" data-path="docs/images/pa-03-values-file.png" />
    </Frame>
  </Step>

  <Step title="Install into your cluster">
    Run the generated command against your cluster context:

    ```bash theme={null}
    helm upgrade --install perfai-agents \
      oci://ghcr.io/perfai-inc/charts/perfai-agents \
      --namespace perfai --create-namespace \
      --values perfai-<deployment-id>-values.yaml
    ```
  </Step>

  <Step title="Wait for the agents to connect">
    The pods start and connect outbound to your tenant. The deployment moves from **Pending** to **Connected** automatically in the console.
  </Step>
</Steps>

## Verify and route

Confirm the agents are healthy in the console — the deployment shows a per-agent status (Vision live, Vision background, Security) with a live "last seen" heartbeat. You can also check in-cluster:

```bash theme={null}
kubectl get pods -n perfai
```

All agent and browser pods should be `Running` / `Ready`. Use **Test connection** in the console for an on-demand health check.

<Frame>
  <img className="docs-frame-img" src="https://mintcdn.com/perfai/mhLzv2Xevqbw5FSq/docs/images/pa-04-status-dashboard.png?fit=max&auto=format&n=mhLzv2Xevqbw5FSq&q=85&s=b653ce38924d51ab28e5fe87c1629985" alt="Status tab — per-agent connection status for the deployment" width="1920" height="945" data-path="docs/images/pa-04-status-dashboard.png" />
</Frame>

**Route your tenant to the deployment.** Open **Org Settings → Request Routing** and point this tenant at your deployment. From then on, **every app this tenant onboards runs on your in-cluster agents** — there is no per-app configuration. Switching back to Perfai Cloud is instant and affects new scans only.

<Frame>
  <img className="docs-frame-img" src="https://mintcdn.com/perfai/mhLzv2Xevqbw5FSq/docs/images/pa-05-request-routing.png?fit=max&auto=format&n=mhLzv2Xevqbw5FSq&q=85&s=8c65be4fd57444c6c04d75378bee97ca" alt="Org Settings → Request Routing — point the tenant at a deployment" width="1920" height="1080" data-path="docs/images/pa-05-request-routing.png" />
</Frame>

## Credential rotation

Each deployment has its own credentials — a **connect secret** the agents authenticate with and an **AI-gateway key** for model access. Rotate them on a regular schedule (**quarterly is a good default**) or immediately if a values file may have been exposed.

<Steps>
  <Step title="Generate new credentials">
    In the console, open the deployment and click **Rotate credential**. Perfai mints a fresh connect secret **and** a fresh AI-gateway key for this deployment, then downloads a new values file.

    <Frame>
      <img className="docs-frame-img" src="https://mintcdn.com/perfai/mhLzv2Xevqbw5FSq/docs/images/pa-06-rotate-credential.png?fit=max&auto=format&n=mhLzv2Xevqbw5FSq&q=85&s=44d7c27166dfc973e608e61573ab0ca5" alt="Rotate credential control on a connected deployment" width="1920" height="945" data-path="docs/images/pa-06-rotate-credential.png" />
    </Frame>
  </Step>

  <Step title="Update your configuration">
    Re-run the install with the new values file — a rolling, zero-downtime update:

    ```bash theme={null}
    helm upgrade perfai-agents \
      oci://ghcr.io/perfai-inc/charts/perfai-agents \
      --namespace perfai \
      --values perfai-<deployment-id>-values.yaml
    ```
  </Step>

  <Step title="Validate access">
    Use **Test connection** in the console and confirm the deployment returns to **Connected** with every agent reporting.
  </Step>

  <Step title="Retire the old credential">
    The previous secret keeps working for a short grace window so in-flight scans finish, then stops accepting new connections automatically. Once the deployment is back to **Connected**, delete the old values file from wherever you stored it.
  </Step>
</Steps>

<Note>
  **This rotates keys, not just a password** — both the connect secret and the AI-gateway key are replaced. **Impact on running work:** the update is zero-downtime and the old credential stays valid during the grace window, so scans in progress are never interrupted.
</Note>

To **fully revoke** a deployment's credentials, remove the deployment from the console and uninstall it from the cluster (`helm uninstall perfai-agents -n perfai`) — that invalidates its connect secret and gateway key immediately.

## Operating

* **Scale concurrency** — increase the concurrency on the deployment; the console issues an updated command to add matched agent/browser capacity.
* **Add more environments** — create additional deployments for other clusters or environments; each is independent.
* **Rotate credentials** — see [Credential rotation](#credential-rotation) above.
* **Uninstall:**

  ```bash theme={null}
  helm uninstall perfai-agents -n perfai
  ```

## Upgrades

New agent releases are surfaced in the console, and you apply them on your own schedule — because the deployment is outbound-only, Perfai never pushes an upgrade into your cluster.

<Steps>
  <Step title="See when an upgrade is available">
    The **Status** tab shows your running agent versions. When a newer release is available, the console shows an **Upgrade available** notice with the exact command.
  </Step>

  <Step title="Apply the upgrade">
    Run the `helm upgrade` against your cluster. It is a rolling, zero-downtime update — in-flight scans finish before a pod restarts:

    ```bash theme={null}
    helm upgrade perfai-agents \
      oci://ghcr.io/perfai-inc/charts/perfai-agents \
      --version <new-version> --namespace perfai \
      --values perfai-<deployment-id>-values.yaml
    ```
  </Step>
</Steps>

<Note>
  Older agents keep working while you upgrade — the Perfai control plane stays backward-compatible, so there is no forced upgrade window. To roll back, run `helm rollback perfai-agents`.
</Note>

## Troubleshooting

<AccordionGroup>
  <Accordion title="The deployment stays 'Pending' in the console">
    The pods haven't completed their outbound connection yet. Check that the pods are running (`kubectl get pods -n perfai`) and that outbound HTTPS to `*.perfai.ai:443` is allowed from the cluster. Once the pods are `Ready`, click **Test connection** to re-run the health check.
  </Accordion>

  <Accordion title="Pods are stuck 'ImagePullBackOff' or 'ErrImagePull'">
    The cluster can't pull the agent images. Confirm outbound access to `ghcr.io/perfai-inc` and that you installed with the **latest** values file from the console (an older or hand-edited file can carry stale image-pull credentials). Re-download the values file and re-run `helm upgrade`.
  </Accordion>

  <Accordion title="An agent shows 'Awaiting' and never connects">
    The agent pod is up but hasn't checked in. Verify the values file matches this deployment (each deployment has its own identity), that outbound `:443` is open, and use **Test connection** to re-probe. If it persists, `kubectl logs` the agent pod for connection or authentication errors.
  </Accordion>

  <Accordion title="A pod is 'Pending' with insufficient CPU/memory">
    The cluster doesn't have room for the chosen concurrency. Add node capacity to match the **Cluster sizing** table, or lower the concurrency on the deployment and re-apply.
  </Accordion>

  <Accordion title="Scans don't run on my in-cluster agents">
    Routing may still point at Perfai Cloud. Open **Org Settings → Request Routing** and confirm the tenant is pointed at your deployment. Routing changes affect **new** scans only.
  </Accordion>
</AccordionGroup>

## FAQ

<AccordionGroup>
  <Accordion title="Does our application data leave our network?">
    Scanning traffic to your applications stays entirely in your cluster. Whether page content leaves your environment depends only on the AI-model choice: with the in-cluster model, nothing leaves; with the Perfai-managed model, content the agent reasons over is sent to Perfai's managed model endpoint over the same `*.perfai.ai` outbound link — never to a third-party provider directly.
  </Accordion>

  <Accordion title="Do we need to open any inbound ports?">
    No. The deployment requires outbound access only. Your inbound firewall can remain fully closed.
  </Accordion>

  <Accordion title="Do we need GPUs?">
    Only if you self-host the AI model. The default managed model needs no GPU.
  </Accordion>

  <Accordion title="Can we deploy to multiple clusters or regions?">
    Yes. Create a separate deployment per cluster/environment; each connects independently to the same tenant.
  </Accordion>

  <Accordion title="What happens if the outbound link drops?">
    Work pauses and resumes automatically when connectivity returns — the design is resilient to transient interruptions. No results are lost.
  </Accordion>
</AccordionGroup>
