How to Manage Flow Configurations Using the Flow CRUD Operations in OpenDeRisk

You manage flow configurations in OpenDeRisk by using the derisk-client Python library to perform CRUD operations on FlowPanel objects, which encapsulate both flow metadata and the serialized DAG structure.

OpenDeRisk represents every workflow as a FlowPanel, the canonical Pydantic model for an AWEL (Agent Workflow Engine Language) flow. This model lives in packages/derisk-core/src/derisk/core/awel/flow/flow_factory.py and stores everything from unique identifiers to the visual graph data. The derisk-client package exposes a complete CRUD API in packages/derisk-client/src/derisk_client/flow.py, allowing you to create, read, update, delete, and execute flows programmatically via REST endpoints.

Understanding the FlowPanel Data Model

Before calling CRUD functions, you must understand the FlowPanel schema. According to the OpenDeRisk source code, a panel contains metadata fields (uid, label, name, flow_category) and a nested FlowData object (flow_data) that holds the node and edge arrays used by the visual editor.

In derisk/core/awel/flow/flow_factory.py, the model defines:

  • UID generation and basic identity fields (lines 30‑55)
  • flow_data containing nodes, edges, and viewport coordinates (lines 56‑63)
  • State handling (initializing, developing, deployed) managed via the panel lifecycle (lines 122‑150)

When you create or update a flow, you construct a FlowPanel instance in Python, and the client library serializes it to JSON for transmission to the Derisk server.

Creating Flow Configurations

To persist a new flow, use the create_flow() function. This asynchronous method sends a POST request to /awel/flows with your FlowPanel payload. The server validates the structure, generates a unique uid, and returns the persisted object.

The create_flow() implementation resides in packages/derisk-client/src/derisk_client/flow.py (lines 13‑24). It accepts a Client instance—defined in packages/derisk-client/src/derisk_client/client.py—and a FlowPanel object, handling JSON conversion automatically.

from derisk_client import Client
from derisk_client.flow import create_flow
from derisk.core.awel.flow.flow_factory import FlowPanel, FlowData, FlowNodeData, FlowEdgeData, FlowPositionData

client = Client(base_url="https://api.derisk.ai")

# Define a minimal DAG with one node and a self-referencing edge

node = FlowNodeData(
    id="dummy_node_0",
    width=300,
    height=200,
    position=FlowPositionData(x=100, y=100, zoom=1.0),
    position_absolute=FlowPositionData(x=100, y=100, zoom=1.0),
    data={"flow_type": "operator", "type": "dummy", "params": {}},
)
edge = FlowEdgeData(
    source="dummy_node_0",
    target="dummy_node_0",
    source_order=0,
    target_order=0,
    id="edge_0",
)
flow_data = FlowData(nodes=[node], edges=[edge], viewport=FlowPositionData(x=0, y=0, zoom=1.0))

panel = FlowPanel(label="Demo Flow", name="demo_flow", flow_data=flow_data)
created = await create_flow(client, panel)
print(f"Created flow with uid={created.uid}")

Retrieving Flow Configurations

You can fetch flows individually by UID or list all flows for the current user. The get_flow() function (lines 76‑88) retrieves a single FlowPanel by its unique identifier, while list_flow() (lines 99‑119) returns a list of panels with optional filtering by name or uid.

Both methods deserialize the server’s JSON response back into FlowPanel objects, preserving the full flow_data DAG structure so you can inspect node configurations programmatically.

from derisk_client.flow import list_flow, get_flow

# List all flows

flows = await list_flow(client)
print("Available flows:", [f.name for f in flows])

# Fetch a specific flow by UID

specific_flow = await get_flow(client, flows[0].uid)
print(f"Retrieved flow label: {specific_flow.label}")

Updating and Deleting Flows

When modifying an existing flow, use update_flow() (lines 31‑42). This function sends a PUT request to /awel/flows with the modified FlowPanel. The server identifies the target flow via the panel’s uid field and overwrites the stored configuration with your new metadata and DAG data.

To remove a flow permanently, call delete_flow() (lines 53‑63), passing the flow’s uid. This operation is idempotent and returns immediately after the server confirms deletion.

from derisk_client.flow import list_flow, update_flow, delete_flow

# Fetch, modify, and update

flows = await list_flow(client)
flow_to_update = flows[0]
flow_to_update.label = "Production Data Pipeline"

updated = await update_flow(client, flow_to_update)
print(f"New label persisted: {updated.label}")

# Clean up

await delete_flow(client, updated.uid)
print("Flow configuration removed")

Executing Flows

Beyond CRUD, the client library supports flow execution via run_flow_cmd() (lines 124‑169). This function triggers a flow by name or uid, optionally passing input data and registering a streaming callback to handle real-time output chunks.

Execution is asynchronous and supports streaming callbacks, making it suitable for long-running workflows that emit progress updates or partial results.

from derisk_client.flow import run_flow_cmd

def on_stream(chunk: str):
    print("STREAM:", chunk, end="")

await run_flow_cmd(
    client,
    name="demo_flow",               # or uid="..."

    data={"input_key": "value"},    # trigger payload

    streaming_callback=on_stream,
)

Summary

  • FlowPanel is the canonical model for AWEL flows, combining metadata and DAG serialization in derisk/core/awel/flow/flow_factory.py.
  • CRUD operations live in packages/derisk-client/src/derisk_client/flow.py and use async functions: create_flow(), get_flow(), list_flow(), update_flow(), and delete_flow().
  • The client communicates with POST, PUT, and DELETE endpoints under /awel/flows, automatically converting FlowPanel objects to JSON.
  • Execution uses run_flow_cmd() with support for streaming output callbacks.
  • All operations require a configured Client instance from derisk_client.client pointing to your Derisk server endpoint.

Frequently Asked Questions

How is the flow UID generated when creating a new flow?

The UID is generated server-side when create_flow() sends the POST request to /awel/flows. The server validates the incoming FlowPanel, assigns a unique identifier, and returns the populated object including the generated uid field. You should not set the uid manually before creation.

Can I filter the list of flows returned by list_flow()?

Yes. The list_flow() function accepts optional name and uid parameters that are passed as query arguments to the server. When provided, the API returns only flows matching those criteria. Without filters, the function returns all flow configurations accessible to the authenticated user.

What happens to the flow_data field during an update operation?

When you call update_flow(), the entire FlowPanel—including the nested flow_data object containing nodes and edges—is serialized to JSON and sent via PUT /awel/flows. The server performs a full overwrite of the existing flow record identified by the panel’s uid, so any changes to the DAG structure or metadata are persisted atomically.

Is run_flow_cmd part of the CRUD operations?

No, run_flow_cmd() is an execution command rather than a CRUD operation. While create, read, update, and delete manage the static configuration of a flow, run_flow_cmd() triggers the actual runtime execution of the compiled DAG. It accepts a name or uid to identify the target flow and optional streaming callbacks to handle real-time output during execution.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →