Flows API

  • Tier: Premium, Ultimate
  • Offering: GitLab.com, GitLab Self-Managed, GitLab Dedicated

Use this API to create and manage flows in the GitLab Duo Agent Platform. Flows are combinations of AI agents that work together to complete developer tasks, such as fixing bugs, writing code, or resolving vulnerabilities.

Trigger a flow

The requirement for a composite identity service account is controlled by a feature flag. The availability of the callback_hook_id and client_reference attributes is controlled by a separate feature flag. For more information, see the history.

Triggers and starts a new flow.

Prerequisites:

  • If the enforce_composite_identity_for_api_started_workflows feature flag is enabled and start_workflow is true, the flow must have a composite identity service account. The service account is either configured for the flow in the AI Catalog, or is the service account behind the request’s composite identity. Otherwise, GitLab returns 403 Forbidden and does not start the flow.
POST /ai/duo_workflows/workflows

Supported attributes:

AttributeTypeRequiredDescription
additional_contextarray of objectsNoAdditional context for the flow. Each element must be an object with at minimum a Category (string) and Content (string, serialized JSON) key.
agent_privilegesinteger arrayNoPrivilege IDs the agent is allowed to use. Defaults to all privileges. See List all agent privileges.
ai_catalog_item_consumer_idintegerNoID of the AI Catalog item consumer that configures which catalog item to execute. Requires project_id. Cannot be used with workflow_definition; if both are provided, ai_catalog_item_consumer_id takes precedence. See Look up the consumer ID.
ai_catalog_item_version_idintegerNoID of the AI Catalog item version that sourced the flow configuration.
allow_agent_to_request_userbooleanNoWhen true (default), the agent may pause to ask the user questions before proceeding. When false, the agent runs to completion without user input.
callback_hook_idintegerNoID of a webhook with GitLab Duo flow webhook callbacks turned on. GitLab sends flow lifecycle events to that webhook, so you do not have to poll for the flow status. The webhook must belong to the project or namespace the flow runs in, or to one of its ancestor groups. This attribute is an experiment.
client_referencestringNoOpaque string echoed back in every callback payload, to correlate callbacks with the request that triggered the flow. Maximum 255 characters. Has no effect without callback_hook_id. This attribute is an experiment.
environmentstringNoExecution environment. One of: ide, web, chat_partial, chat, ambient.
goalstringNoDescription of the task for the agent to complete. Example: Fix the failing pipeline.
imagestringNoContainer image to use for the flow. Applies only when the flow runs in a CI pipeline. Must meet the custom image requirements. Example: registry.gitlab.com/gitlab-org/duo-workflow/custom-image:latest.
issue_idintegerNoIID of the issue to associate the flow with. Requires project_id.
merge_request_idintegerNoIID of the merge request to associate the flow with. Requires project_id.
namespace_idstringNoID or path of the namespace to associate the flow with.
pre_approved_agent_privilegesinteger arrayNoPrivilege IDs the agent can use without asking for user approval. Must be a subset of agent_privileges.
project_idstringNoID or path of the project to associate the flow with.
sourcestringNoWhere the session was triggered from. One of the GitLab feature entry points (for example, merge_request_code_conflict) or the client surface that created the session (duo_cli_interactive, duo_cli_run, duo_cli_acp, ide_extension). Persisted as the session’s source_type.
source_branchstringNoSource branch for the flow. Applies only when the flow runs in a CI pipeline. When not specified, a flow whose goal is a pipeline or merge request, such as fix_pipeline/v1 or code_review/v1, runs on that pipeline’s or merge request’s branch. For fix_pipeline/v1, the merge_request and pipeline entries in additional_context are also filled in from the pipeline. Other flows run on the project’s default branch.
start_workflowbooleanNoWhen true, starts the flow immediately after creation.
workflow_definitionstringNoFlow type identifier. Example: developer/v1. Cannot be used with ai_catalog_item_consumer_id; if both are provided, ai_catalog_item_consumer_id takes precedence.

If successful, returns 201 Created and the following response attributes:

AttributeTypeDescription
agent_privilegesinteger arrayPrivilege IDs assigned to the agent.
agent_privileges_namesstring arrayNames corresponding to agent_privileges.
ai_catalog_item_version_idintegerID of the AI Catalog item version. null if not set.
allow_agent_to_request_userbooleanWhen true, the agent may pause for user input.
environmentstringExecution environment. null if not set.
gitlab_urlstringBase URL of the GitLab instance.
idintegerID of the flow.
imagestringContainer image for CI pipeline execution. null if not set.
mcp_enabledbooleanWhether MCP (Model Context Protocol) tools are enabled for this flow.
namespace_idintegerID of the associated namespace. null if not set.
pre_approved_agent_privilegesinteger arrayPrivilege IDs the agent can use without asking for approval.
pre_approved_agent_privileges_namesstring arrayNames corresponding to pre_approved_agent_privileges.
project_idintegerID of the associated project. null if not set.
statusstringCurrent flow status. One of created, running, paused, finished, failed, stopped, input_required, plan_approval_required, or tool_call_approval_required. GitLab might add new values.
summarystringShort text summary of the workflow.
titlestringTitle of the session.
web_urlstringURL of the session in the GitLab UI. null if the session is not for a project.
workflow_definitionstringFlow type identifier.
workloadobjectInformation about the workload.
workload.idintegerID of the workload. null if no workload was created, for example when start_workflow is not true.
workload.messagestringStatus message for the workload. null if no workload was created.

If the user must complete identity verification before they can use GitLab Duo Agent Platform, GitLab returns 403 Forbidden with a message:

json
{
  "message": "403 Forbidden - Identity verification is required to use GitLab Duo Agent Platform"
}

GitLab returns 400 Bad request when callback_hook_id is set and either of the following is true:

  • The duo_flow_callback_hooks feature flag is not enabled for the top-level group of the project or namespace the flow runs in.
  • The ID does not reference a webhook that has GitLab Duo flow callbacks turned on in the project or namespace the flow runs in, or in one of its ancestor groups.

Look up the consumer ID

Before you can use ai_catalog_item_consumer_id, you must use the GraphQL API to retrieve the ID from the AI Catalog. The item must already be enabled for the project.

graphql
query {
  aiCatalogConfiguredItems(projectId: "gid://gitlab/Project/<project_id>") {
    nodes {
      id
      item { name }
    }
  }
}

The id field is a Global ID in the format gid://gitlab/AiCatalogItemConsumer/<numeric_id>. Use the numeric suffix as the ai_catalog_item_consumer_id value.

Example request using a built-in flow type:

shell
curl --request POST \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --header "Content-Type: application/json" \
  --data '{
    "project_id": "5",
    "goal": "Fix the failing pipeline by correcting the syntax error in .gitlab-ci.yml",
    "workflow_definition": "developer/v1",
    "start_workflow": true
  }' \
  --url "https://gitlab.example.com/api/v4/ai/duo_workflows/workflows"

Example request using a catalog-configured flow:

shell
curl --request POST \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --header "Content-Type: application/json" \
  --data '{
    "project_id": "5",
    "goal": "Fix the failing pipeline by correcting the syntax error in .gitlab-ci.yml",
    "ai_catalog_item_consumer_id": 12,
    "start_workflow": true
  }' \
  --url "https://gitlab.example.com/api/v4/ai/duo_workflows/workflows"

Example response:

json
{
  "id": 1,
  "web_url": "https://gitlab.example.com/group/project/-/automate/agent-sessions/1",
  "project_id": 5,
  "namespace_id": null,
  "agent_privileges": [1, 2, 3, 4, 5, 6],
  "agent_privileges_names": [
    "read_write_files",
    "read_only_gitlab",
    "read_write_gitlab",
    "run_commands",
    "use_git",
    "run_mcp_tools"
  ],
  "pre_approved_agent_privileges": [],
  "pre_approved_agent_privileges_names": [],
  "workflow_definition": "developer/v1",
  "status": "running",
  "allow_agent_to_request_user": true,
  "image": null,
  "environment": null,
  "ai_catalog_item_version_id": null,
  "workload": {
    "id": "abc-123",
    "message": "Workflow started"
  },
  "mcp_enabled": false,
  "gitlab_url": "https://gitlab.example.com"
}

Restart a flow

  • Status: Experiment

Restarts a failed or stopped flow by starting a new flow with the same flow parameters. The new flow runs from the beginning. The original flow is not modified and keeps its failed or stopped status.

Only project-level flows with a failed or stopped status can be restarted. Restarting a flow with any other status, or a group-level flow, returns 403 Forbidden. Restarting the same flow again while a restart is still in progress returns 409 Conflict.

POST /ai/duo_workflows/workflows/:workflow_id/restart

Supported attributes:

AttributeTypeRequiredDescription
workflow_idintegerYesID of the flow to restart.

If successful, returns 201 Created and the same response attributes as Trigger a flow. The response describes the new flow, so id is the ID of the new flow rather than the one you restarted.

Example request:

shell
curl --request POST \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --url "https://gitlab.example.com/api/v4/ai/duo_workflows/workflows/42/restart"

Get workflow trace as JSONL

  • Status: Experiment

Returns the ui_chat_log entries of a workflow session as JSON Lines (JSONL). Each line is a valid JSON object representing one entry from the ui_chat_log array. Use this endpoint to parse or pipe the trace into tools like jq.

By default, the endpoint returns the complete conversation across all threads of the session, including messages from before any context compaction. Use the thread attribute to return a single thread instead.

GET /ai/duo_workflows/workflows/:workflow_id/trace.jsonl

Supported attributes:

AttributeTypeRequiredDescription
workflow_idintegerYesID of the workflow.
threadstringNoWhich thread to return. Omit for the full trace across all threads. Use latest for the most recent thread only, or a thread ID for a specific thread.

If successful, returns 200 OK with:

  • Content-Type: application/x-ndjson
  • Body: One JSON object per line, each representing a ui_chat_log entry. Returns an empty body if the workflow has no checkpoints or no ui_chat_log entries.

If the user must complete identity verification before they can use GitLab Duo Agent Platform, GitLab returns 403 Forbidden with a message:

json
{
  "message": "403 Forbidden - Identity verification is required to use GitLab Duo Agent Platform"
}

Example request:

shell
curl --request GET \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --url "https://gitlab.example.com/api/v4/ai/duo_workflows/workflows/1/trace.jsonl"

Example response (each line is a separate JSON object):

jsonl
{"status":"success","content":"Analyze the issue","message_type":"human"}
{"status":"success","content":"I'll start by reading the codebase.","message_type":"ai"}

You can pipe the output into jq to filter entries by type:

shell
curl --request GET \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --url "https://gitlab.example.com/api/v4/ai/duo_workflows/workflows/1/trace.jsonl" \
  | jq 'select(.message_type == "ai")'

List all agent privileges

Lists all available agent privileges with their IDs, names, descriptions, and whether each is enabled by default.

GET /ai/duo_workflows/workflows/agent_privileges

This endpoint has no supported attributes.

If successful, returns 200 OK and the following response attributes:

AttributeTypeDescription
all_privilegesarray of objectsAll available agent privileges.
all_privileges[].default_enabledbooleanWhether the privilege is enabled by default.
all_privileges[].descriptionstringHuman-readable description of what the privilege permits.
all_privileges[].idintegerPrivilege ID.
all_privileges[].namestringMachine-readable privilege name.

Example request:

shell
curl --request GET \
  --header "PRIVATE-TOKEN: <your_access_token>" \
  --url "https://gitlab.example.com/api/v4/ai/duo_workflows/workflows/agent_privileges"

Example response:

json
{
  "all_privileges": [
    {
      "id": 1,
      "name": "read_write_files",
      "description": "Allow local filesystem read/write access",
      "default_enabled": true
    },
    {
      "id": 2,
      "name": "read_only_gitlab",
      "description": "Allow read only access to GitLab APIs",
      "default_enabled": true
    },
    {
      "id": 3,
      "name": "read_write_gitlab",
      "description": "Allow write access to GitLab APIs",
      "default_enabled": true
    },
    {
      "id": 4,
      "name": "run_commands",
      "description": "Allow running any commands",
      "default_enabled": true
    },
    {
      "id": 5,
      "name": "use_git",
      "description": "Allow git commits, push and other git commands",
      "default_enabled": true
    },
    {
      "id": 6,
      "name": "run_mcp_tools",
      "description": "Allow running MCP tools",
      "default_enabled": true
    }
  ]
}