Agentic Data Plane
Preview

Manage Resources with GitOps

GitOps keeps the definition of your Agentic Data Plane resources in Git and reconciles the live environment toward those files, instead of running imperative create, update, and delete commands by hand. With the Agentic Data Plane CLI, rpk ai <resource> apply -f creates what is missing and updates what has drifted, and rpk ai <resource> diff -f is a read-only dry-run that reports what apply would change. In these commands, <resource> is one of the resource command groups that support GitOps:

  • LLM providers (rpk ai llm-provider)

  • MCP servers (rpk ai mcp-server)

  • OAuth providers (rpk ai oauth-provider)

  • OAuth clients (rpk ai oauth-client)

  • Agents (rpk ai agent)

  • Agent triggers (rpk ai trigger)

  • Policies (rpk ai policy)

After reading this page, you will be able to:

  • Export an Agentic Data Plane resource to a YAML manifest you can commit to Git

  • Reconcile resources with apply, and preview changes with diff

  • Gate continuous integration on configuration drift

Prerequisites

  • The Agentic Data Plane CLI installed and connected to an Agentic Data Plane environment.

  • Permission to create and update the resources you manage. The reconcile commands call the same APIs as create and update. See Roles and Permissions Reference.

  • Any secrets your manifests reference already created in Agentic Data Plane. Manifests name secrets by reference, for example, OPENAI_API_KEY; the CLI does not create secrets.

How apply and diff reconcile

A manifest is plain resource YAML: the same shape a get -o yaml dump produces. The CLI compares each manifest against the live resource of the same name and resolves one of three outcomes:

Create

No resource of that name exists, so apply creates it.

Update

The resource exists and a writable field differs from what the manifest describes, including a field the manifest omits, so apply updates the differing fields.

Unchanged

The resource exists and every writable field already matches the manifest.

A trigger belongs to an agent, so its manifest is the one case where the resource’s name also names its parent. Write it as the full resource name that rpk ai trigger get -o yaml prints, agents/<agent-id>/triggers/<trigger-id>, and apply creates the trigger on that agent. A manifest with a missing or malformed name fails before anything is written.

The reconcile rules are deliberate, and they are not the same as a full-object replace:

A manifest is the complete desired state

Every writable field is compared, including the fields your manifest leaves out. An omitted field is compared against the value that creating the resource from that manifest would have produced, usually empty or zero, and reconciled to it. Omitting a field does not leave the live value alone, and to clear a field you can either write it explicitly with an empty value or leave it out.

Server-managed fields are left alone

Fields the server owns and ignores on input, such as created_at, updated_at, and a resource’s own URL, are excluded from the comparison, so they never show as drift. A field the server merely fills in when you leave it unset is different: it is writable, so it is compared, and it shows as drift until your manifest declares it, as described after these rules.

Collections replace wholesale

Lists, maps, and provider or backend variants are replaced as a unit, not merged element by element.

Create-only fields are immutable

A field that can be set only at creation time, such as an LLM provider’s type, an MCP server’s backend kind, an OAuth provider’s client_id, an agent’s managed-or-self-managed kind, or a trigger’s kind, cannot change on an existing resource. Changing one is an error that tells you to delete and recreate the resource.

Request-only fields are instructions, not state

A few fields tell the gateway to do something rather than describe what a resource is. An MCP server’s remote.user_oauth.automatic_setup asks the gateway to set up OAuth for the server itself instead of attaching a provider by name. Set it in a manifest when you want automatic setup, and leave provider_name out: on an existing server an empty provider_name preserves the provider already attached, and setting both is an error. Omitting automatic_setup leaves an existing attachment untouched, so an unrelated edit such as a scopes change never re-runs OAuth setup. See User-delegated OAuth.

Secrets stay by reference

Manifests reference secrets by name, for example, api_key_ref and client_secret_ref, and never contain secret values, so a manifest is safe to commit to Git.

The apply command does not delete resources that are absent from your manifests; there is no prune. What diff does not detect is a resource that exists in the environment but is missing from your manifests.

Because every writable field counts, keep each manifest complete. Trimming a field from a manifest is a request to clear it, and a field the server fills in when a create leaves it unset shows as drift until you declare it. An LLM provider’s transcript settings, a managed agent’s maximum iterations, and an OAuth client’s PKCE requirement for a native redirect URI all behave this way, and for most of them apply cannot settle the drift, because the server reapplies its own value. An MCP server’s remote.user_oauth.provider_name behaves the same way once a provider is attached: omitting it reports drift on every run, and apply cannot clear it, because an empty value preserves the provider the server already has. Leave provider_name out only when the manifest requests automatic setup. A get -o yaml dump already carries all of these fields, so start from a dump rather than a hand-written manifest.

Export a resource to a manifest

Start from a live resource so the manifest is complete. Dump it to YAML and redirect it to a file:

rpk ai llm-provider get openai -o yaml > openai.yaml

A dumped OpenAI provider looks like this, ready to commit:

'@type': type.googleapis.com/redpanda.api.adp.v1alpha1.LLMProvider
created_at: "2026-06-20T10:15:30Z"
display_name: OpenAI
enabled: true
name: openai
openai_config:
  api_key_ref: OPENAI_API_KEY
provider_models:
- name: gpt-4o
- name: gpt-4o-mini
type: LLM_PROVIDER_TYPE_OPENAI
updated_at: "2026-06-20T10:15:30Z"
url: https://openai.aigw.d0example1cluster234.clusters.rdpa.co/openai/v1

The @type line records the resource kind. It is optional when you apply with a resource command, because rpk ai llm-provider apply already implies the kind, but keeping it lets a reader and any validator know what the file describes.

The created_at, updated_at, and url fields are server-managed and read-only. The apply command ignores them, so you can leave them in the file or strip them. The api_key_ref value is a reference to a secret, not the key itself.

Preview changes with diff

Edit the manifest, then preview the effect before you touch the environment. For example, change the display name:

display_name: OpenAI (production)

Run diff to see the plan:

rpk ai llm-provider diff -f openai.yaml
~ openai (update: display_name)

The diff command marks each manifest with one of three symbols and changes nothing:

Symbol Meaning

+

The apply command would create the resource.

~

The apply command would update the resource. The changed fields follow in parentheses.

=

The resource already matches; apply would leave it unchanged.

The diff command exits with a non-zero status when any change is pending, and zero when the environment already matches every manifest. That exit code is what lets continuous integration gate on drift.

Apply changes

Reconcile the environment toward the manifest:

rpk ai llm-provider apply -f openai.yaml

The apply command prints one line per manifest as it works:

updated openai (display_name)

A first-time apply of a resource that does not yet exist prints created openai instead, and a manifest that already matches the environment prints unchanged openai. The CLI plans every manifest before it changes anything, so a malformed manifest aborts the run before any write. If a later write fails, the lines already printed tell you exactly what was applied.

Apply many manifests at once

The -f flag is repeatable and accepts a file, a directory, or a stream:

# A directory of manifests; the CLI reads every .yaml and .yml file, sorted by name.
rpk ai mcp-server apply -f ./manifests/

# Several paths in one run.
rpk ai llm-provider apply -f openai.yaml -f anthropic.yaml

# Standard input, for piping a manifest from another tool.
rpk ai oauth-provider apply -f -

A single file can hold more than one manifest. Separate documents with a line containing only ---.

Gate continuous integration on drift

Because diff exits non-zero when the environment differs from your manifests, a continuous-integration job can fail the build whenever the live environment has drifted from Git:

# Fails the job if an apply would change anything.
rpk ai llm-provider diff -f ./llm/
rpk ai mcp-server diff -f ./mcp/

A common pipeline runs diff on a pull request to preview changes, then runs apply after the merge to roll them out:

# Deploy step, after merge to the main branch.
rpk ai llm-provider apply -f ./llm/
rpk ai mcp-server apply -f ./mcp/

Manifests are declarative

A manifest describes the full intended state, so an omitted field means zero, not the convenience default that create fills in. A manifest that omits enabled creates a disabled resource, and diff then reports no drift, because the disabled state matches the manifest. The same reading applies to a resource that already exists: omitting enabled from a manifest you apply to an enabled resource disables it.

For a trigger, a disabled resource is a paused one: it fires no scheduled runs and receives no Microsoft Teams messages until enabled: true reaches it. The imperative rpk ai trigger create command is the exception, because its --enabled flag defaults to true.

To avoid surprises:

  • Start from a get -o yaml dump, which is already complete, rather than hand-writing a manifest from scratch.

  • Set enabled: true explicitly when you want an active resource.

One subtlety follows from this: a dump of an already-disabled resource omits enabled, because false is the field’s zero value and the dump omits zero values. Reapplying that dump elsewhere also produces a disabled resource.

Troubleshooting

Symptom Resolution

The apply or diff command reports that a field is immutable and tells you to delete and recreate the resource.

You changed a create-only field, such as an LLM provider’s type or an OAuth provider’s client_id. Restore the original value, or delete the resource and recreate it from the new manifest.

The apply or diff command fails to decode the manifest and mentions unknown or misspelled fields.

A key in the manifest is not a field of the resource. The CLI rejects unknown keys rather than dropping them silently. Fix the key. Start from a get -o yaml dump to get the exact field names.

The diff command reports no drift, but you know the environment has extra resources.

The diff and apply commands never prune. They act only on the resources your manifests name. Delete unwanted resources with rpk ai <resource> delete.

A field you changed in the environment keeps coming back after apply.

The apply command reconciles every writable field toward the manifest, so a change made outside Git is reverted on the next apply. If you want to keep the change, write it into the manifest.

The diff command reports drift on a field you never set, and apply does not clear it.

The server fills that field in on create and reapplies its own value on update, so the manifest and the environment cannot agree until the manifest declares it. Copy the value from a get -o yaml dump into your manifest.