Skip to content

Managed Flows

Managed flows let the AI Engineering team build a flow once, on the internal prod Agentlab instance, and roll it out in a controlled way to other instances: global and client instances. Every rollout is dry-run against the target before anything is written. Every rollout can be rolled back and leaves an audit trail.

This page is for the people operating that process: designating flows, capturing and promoting revisions, and cleaning up afterwards.

The one rule

A managed flow is edited only on the source instance (prod). Its copies on target instances are locked, and there is no unlock. global has no human users, and every write to it comes from this pipeline. If a target copy needs to change, change the source and promote.

How It Fits Together

flowchart LR
    subgraph Source["prod (source)"]
        Flow["Flow"]
    end
    subgraph Studio["Karli Studio · Managed Flows"]
        MF["Managed flow"]
        Rev["Revisions
(immutable snapshots)"] B1["Binding → global"] B2["Binding → client instance"] MF --> Rev MF --> B1 MF --> B2 end Flow -- "designate" --> MF B1 -- "rollout" --> G["global"] B2 -- "rollout" --> C["client instance"]
  • Managed flow — a flow on prod that has been designated for promotion.
  • Revision — an immutable snapshot of the source flow. Only revisions are promoted, never the live source flow directly.
  • Target instance — an Agentlab instance a managed flow is promoted to.
  • Binding — the link between a managed flow and one flow on one target instance. There is at most one binding per managed flow and instance.
  • Rollout — one attempt to apply a revision through a binding. Rollbacks, deactivations and deletions are recorded as rollouts too, so they all appear in the same history.

Access

Managed Flows is under the settings menu at the foot of Karli Studio's navigation rail. You need one of two Keycloak realm roles:

Role Can
Managed Flow Admin Everything a developer can do, plus: add targets, configure bindings (target project, flow name, variable renaming), confirm adoptions, deactivate, reactivate and delete bindings. Only admins see the managed flow toggle in Agentlab.
Managed Flow Developer Capture revisions, view diffs, dry-run and create rollouts, roll back, view everything.

These roles are separate from Karli's usual admin rights: a Karli super admin has no Managed Flows access unless they are granted a role as well. Without a role, the page shows No access to Managed Flows.

Target Instance Grants

An admin can only add targets on instances a super admin has granted to them. Until then, the add-target dialog says that no target instances have been granted yet. That's expected, not a bug. This also applies to super admins who are managed-flow admins themselves.

There's no Studio screen for grants yet; a super admin sets them through the API (PUT /api/v1/admin/users/{userId}/target-instances).

Revoking a grant only prevents new targets. Existing bindings stay live and keep receiving rollouts. To take a target out of service, deactivate or delete its binding.

The Managed Flows Page

The page has two views, switched at the top. Studio remembers which one you used last.

  • By flow — one entry per managed flow, with tabs for its targets, revisions, configuration and history.
  • All agents — every binding across every flow in one table, filterable by status. This is the quickest way to answer "is this flow on that instance managed?"

If Studio can't reach the middleware, the page shows The middleware is unreachable with a Reconnect button. Rollouts are disabled until it reconnects.

Designating a Flow

Designation happens in Agentlab, on prod:

  1. Open the flow's Publish dialog.
  2. Enable Managed flow and publish.

The toggle only appears for Managed Flow Admins, and only on the source instance. On a target instance it never shows, whatever your role.

Designation copies nothing anywhere. The flow appears on the Managed Flows page, and everything else (targets, project, variables) is configured there. In Agentlab it picks up a Managed source badge and stays fully editable — the badge only records that this is where promotions originate.

To undesignate, turn the toggle off again. This archives the managed flow and deactivates all its bindings. Re-designating the same flow later revives it with its old revisions and bindings. If a target copy was edited in the meantime, the next rollout to global is blocked on drift.

Can't delete a flow on prod?

A designated flow can be edited but not deleted. Agentlab only shows the generic Error deleting items / Please try again. Retrying won't help: undesignate it first.

Capturing a Revision

When the source flow is ready, choose Capture revision and add a note saying what changed. The note appears in the history and the rollout dialog. If the source hasn't changed since the last revision, there's nothing to capture and the button stays disabled.

The Revisions tab lists all revisions and where each is currently running (Active on).

Reading the Diff

There are two diffs, and neither lets you pick the pair freely:

  • Diff on a revision row compares it with the revision before it.
  • Diff on a target row compares the latest revision with what's currently on that target. The dialog title still says "Compare revisions".

Nodes that contain environment-bound-looking values are marked environment-bound suspected. Click the node to see the value and its kind: URL, IP or ABSOLUTE_PATH. Values inside custom component code are included. Hostnames and collection names are not detected. The diff flags these values but doesn't block anything. Treat every flag as a bug in the flow (see Variables).

Adding a Target

Add target creates a binding. Pick the target instance; the list only shows instances granted to you and not already bound. Then choose the kind of binding. There are two, and the choice matters.

Create new is for a flow that doesn't exist on the target yet. The first rollout creates the target project if needed, creates the flow, checks that it builds, and publishes it. A Karli agent for it is then created automatically. That agent is operated centrally: it is not self-service, not public, and it has the same admins as the source flow.

Adopt existing flow is for a flow that already exists on the target, for example one copied over by hand before this feature existed. Adopting keeps that flow's ID and therefore its chat history. Using Create new for such a flow would put a second copy next to the existing one.

When adopting:

  • Pick the flow from the project menu. Flows that are already managed are greyed out: a flow can belong to only one live binding.
  • The binding does nothing until an admin confirms it (Confirm, then Confirm adoption). The dialog states which of two situations applies:

    • Existing Karli agent — will be taken over. From now on, rollouts overwrite the flow behind that agent. Chat sessions are kept.
    • No Karli agent yet — one will be created on the first rollout.

    Confirm by typing the instance slug. If the flow's agent situation changed after you opened the dialog, confirming is refused; close and reopen the dialog.

Target Project and Flow Name

Both are set in the add-target dialog. The target project can be an existing project or a new name; it is resolved or created by name on the first rollout.

A Create new binding fails its first rollout if a flow of the same name already exists in the target project. It won't adopt that flow and it won't create a duplicate. Either adopt the existing flow, or set a Target flow name. Both fields can be changed in Edit until the first rollout. After that they disappear from the dialog without explanation. Agent name, subtext and icon are edited on the agent itself and survive rollouts.

Rollout applied, but no agent?

Creating the agent requires the target instance to belong to a company in Karli. If it doesn't, the flow is still deployed and the rollout shows Applied, but no agent exists. The only sign is an AGENT_MATERIALIZE_FAILED line when you expand that rollout in History. Once the instance has a company, the next rollout creates the agent.

Variables

Anything that differs between environments (API keys, endpoints, collection names) must be a global variable in Agentlab, never a value typed into a component, and never a literal in custom component code. There is deliberately no way to override component values per target, so a hard-coded value is hard-coded everywhere. A flow that breaks this rule passes every check and then fails on an instance nobody is watching.

If a variable has a different name on the target than on prod, map it under Edit → Variable renaming. The fields suggest the variables that exist on each instance, but you can type any name. Editing the mapping is recorded as a mapping change, not as drift.

Promoting

Create rollout, then choose revision, targets and trigger:

  • Now — applies immediately. Studio waits until the rollout has finished, which can take a moment on large flows.
  • From version — the rollout waits until the target is upgraded to at least that Agentlab version, and applies during the upgrade. If it fails then, the upgrade stops. Use this when a revision only works on a newer Agentlab than the target currently runs. The version field isn't validated, so type it carefully (e.g. 1.3.2).

Waiting rollouts can't be cancelled

Once the dialog is closed, a waiting rollout doesn't appear anywhere in Studio until it has run, and Studio can't cancel it (the API can: POST /api/v1/rollouts/{id}/cancel). Only schedule version-gated rollouts you're sure about.

Dry-run is mandatory: Roll out stays disabled until a dry-run has passed for every selected target. Changing anything in the dialog resets the dry-run. The dry-run shows each check with its result and writes nothing. A result of BLOCKED_GATE means "waiting for the version", not failure.

The checks the dry-run and the rollout run against the target:

  • The target is reachable, set up as a promotion target, and reports its Agentlab version. An instance that can't report a version never passes a version gate.
  • The binding is usable. An unconfirmed adoption fails here.
  • Drift — nobody changed the target copy since the last rollout. See below for which instances this protects.
  • Variables — every referenced global variable exists on the target (directly or through the mapping) with the right type (Credential vs. Generic), and required model providers are enabled.
  • Build — the revision builds on the target, component by component. This catches the component and template differences that break flows after an upgrade.

Only if everything passes is the flow written. An existing target flow is updated in place, so its ID and chat history are preserved.

Drift only protects global

On global, a hand-edited target copy blocks the rollout. On every other instance, the dry-run notes the drift and the rollout overwrites the edits. That's by design, since client edits to managed flows are expected to be overwritten, but know it before you promote to a client.

When a Newer Revision Overtakes a Waiting Rollout

This setting only appears for From version rollouts, as If superseded. Say revision 4 is waiting for global to upgrade, and meanwhile revision 5 ships:

  • Take latest (default) — revision 5 is applied instead.
  • Do not roll out — the rollout fails and a human decides.
  • Anyway — revision 4 is applied as pinned. Use deliberately.

A rollout retired this way is marked superseded, not cancelled. The history still shows the revision that was requested, not the one actually applied. Check the target's revision on the Targets tab.

The Group label field in the rollout dialog currently has no effect.

Rolling Back

Rollback starts from the Revisions tab: Roll back on the revision you want to return to.

Rollback applies to every target

Rollback applies to all targets that aren't already on that revision, not just one. The dialog lists what will be overwritten before you confirm. There's no dry-run.

A rollback is an ordinary rollout of the older revision that ignores supersede rules. Sessions and the target flow ID are preserved.

Status and History

Badge Meaning
Live Running the latest revision
Behind Live, but a newer revision exists
Creation pending Create new binding, first rollout hasn't happened yet
Confirmation needed Adopted binding not yet confirmed
Disabled Deactivated: handed back to local ownership

The History tab lists every rollout, newest first, with who started it. Filter by state, target and date. Expanding a rollout shows its individual events and, for failures, the failure class and detail.

Server-generated text (check details, failure messages, event names) is always English, including in the German UI.

When a Rollout Is Refused

Failure classes appear verbatim in the expanded history entry:

Class What it means What to do
DRIFT The target copy on global was changed outside the pipeline. Find out who changed it and why. If the change should stay, carry it over to the source, capture, promote.
PRECONDITION The setup is wrong: a missing or wrongly typed variable, a disabled model provider, an unconfirmed adoption, a name collision on a Create new binding, or an instance that isn't set up as a promotion target. The detail names the item. Missing variables and providers on global are an ops ticket, and the detail is precise enough to write it.
VALIDATION A component doesn't build on the target. Fix on the source, or use From version with a newer Agentlab.
INFRASTRUCTURE The target didn't answer, or answered nonsense. Nothing was written. Retry once the target is healthy.
DATA The write went through, but reading the flow back doesn't match what was sent. Rare. Diff the latest revision against the target and look at the flow on the instance before retrying.

Nothing is written on PRECONDITION or VALIDATION.

An error mentioning MANAGED_FLOWS_MODE means the target instance is configured for the wrong role (source vs. target). That's an ops issue, not a problem with the flow.

Deactivating and Deleting Bindings

There are two actions on a target row. Neither deletes the target flow. Either way, the flow keeps serving, keeps its chat history, and becomes editable on the target instance again. Handing the flow back to local ownership is the point.

Deactivate keeps the binding greyed out, and the agent stays. No rollouts reach the flow. Reactivate reverses it.

Delete binding removes the binding from the view. The dialog asks what happens to the agent:

  • Keep the agent — it keeps working; only its link to the managed flow goes. To manage the flow again later, add the target and adopt it.
  • Remove the agent — only offered if the pipeline created the agent. An agent that existed before its flow was adopted is never removed. This is irreversible: the agent's configuration, user and group assignments, permissions, feedback and files are deleted. Chat messages remain in the database but can no longer be reached from the UI. Adding the target again later creates a new, empty agent. You confirm by ticking a checkbox and typing the instance slug.

Edits to the target copy made while deactivated, or between delete and re-adopt, still count as drift on global. The check can't be sidestepped this way.

Residual Lock

Deactivating or deleting always succeeds in Studio, even if the target is unreachable. If the target couldn't be told to release the flow, the flow may still be locked there. After a delete, the dialog says so directly and offers Retry. On a remaining binding, a warning icon appears next to the badge, and admins can use Retry unmark.

Managed Flows in Agentlab

Both roles are marked in Agentlab, in the flow list and in the header above the canvas.

Badge Meaning
Managed source Promoted from this instance to its targets. Informational only — the flow stays fully editable and behaves normally in every other respect.
Managed (lock icon) Maintained by the promotion pipeline. The flow is locked here; edits happen on the source instance.

Hover either badge for a one-line explanation.

On a target instance, a Managed flow is locked: it can't be edited, renamed, moved or deleted by hand, and there is no unlock. Agentlab doesn't explain each individual refusal, so the badge is the thing to look for:

  • The canvas is non-interactive and the lock toggle is missing from the flow settings.
  • Rename and move do nothing, with no message.
  • Delete shows Error deleting items / Please try again.

Changes go through the source instance. A flow carrying the badge may also be a residual lock rather than an active binding — the All agents view in Studio tells you which.