Create a workflow

workflow creation

Workflows are a way for you to modify the default annotation cycle by creating your own custom roles and item statuses to align the processes of your team and projects with the platform.

Only members with the role of Team Admin or higher can create a workflow.

📘

Feature compatibility

  • This feature can be used with the following project types: LLMs and GenAI, Image, Video, Text, and Tiled Imagery.
  • If you want to incorporate Python SDK functions into a project with a custom workflow, make sure you use the following python version or higher: 4.4.25

Existing workflows

On the platform, there are existing roles and statuses that are used in system workflows:

  • Roles - Annotator, QA
  • Statuses - Not Started, In Progress, Quality Check, Returned, Skipped, Completed

There are two workflows available on the platform that contain these roles and statuses: System Workflow (default), and System Workflow (direct completion). The difference between the two is that the latter allows Annotators to complete items.

The default selected workflow will be used for all projects unless you select otherwise during project creation.

With custom workflows, you can use all existing roles and statuses on the platform, as well as custom ones that you’ve created.

Creating your workflow

You can create a new workflow from Team Setup.

  1. Go to the Workflows tab.
  2. Click + New Workflow.
  3. Type in a name for your new workflow.
  4. Type in a description of your workflow to explain its structure (optional).
  5. Create a JSON file according to the workflow JSON structure.
  6. Upload the JSON file that contains your workflow's data.
  7. Click Create.

📘

  • You can have a maximum of 2,000 workflows in a team at one time, including system workflows.
  • Workflows can't be deleted if they're currently in use.

JSON structure

When creating the JSON file, there's a specific structure you need to follow in order to build a functional workflow.

📘

If you want to incorporate custom statuses or roles, make sure to create them on the platform before creating the JSON file.

{
"roles": [],
"statuses": [],
"start_status":"",
"allowed_resources_to_roles":{},
"transitions":[],
 }

These are the list of parameters you can include:

  • "roles" - array of strings - The roles that will exist in your workflow, and subsequently in any project you use the workflow with. You can only include roles that exist in the Roles tab in Team Setup.
  • "statuses" (required) - array of strings - The statuses that will exist in your workflow, and subsequently in any project you use the workflow with. You can only include roles that exist in the Statuses tab in Team Setup.
  • "start_status" (required) - string - The default starting status of all items. This must be a status that's listed in the workflow's statuses field.
  • "allowed_resources_to_roles" - object - Where you define a role’s permissions to view/request items with the specified statuses. The roles and statuses must already be mentioned in the roles and statuses fields of the workflow JSON. You can read about how to structure this object below.
  • "transitions" - array of objects - This is where you define the action that the role needs to take to change the item status from one status to another. The roles and statuses must already be mentioned in the roles and statuses fields of the workflow JSON. You can read about how to structure this object below.

📘

Important to know

  • If you only include the required fields, only users with Project Admin or higher roles can work on the project.
  • Please keep in mind that the order in which you write the role and status names in the workflow’s roles and statuses fields is the exact order that they'll appear in on the platform.

Roles and allowed resources

In the “allowed_resources_to_roles” field of the workflow JSON, you can define each role’s permissions to view/request items with specified statuses. Within this object, each key mentioned is the role you want to write permissions for, as is shown in the structure below:

"allowed_resources_to_roles": {
           "<role_name>": {
               "view_items" : {
                   "statuses": [“<status_1>”,” <status_2>”, “<status_3>”],
               }
           }
       }

In this structure:

  • <role_name> must be replaced with the name of the desired role as it's written in the workflow's roles field.
  • <status_1> must be replaced with the name of a status as it's written in the workflow's statuses field. The specified role will have access to view/request items with that status. Each status can only be mentioned for one role at a time.

🚧

Missing values

  • If you include the ”allowed_resources_to_roles” key, you must have at least one role written within, which includes the ”view_items” and ”statuses” keys, even if the value for ”statuses” is left empty.
  • If you specify a role, but then leave the nested ”statuses” field under ”view_items” empty, then users with that role won't be able to view any items on the platform.
  • If you specify the statuses that a role can access, but you haven’t allowed it to make any transitions from those statuses, then the role will be able to view the items, but won’t be able to update the item’s status in any way.

Here is an example of how this section should look:

    "allowed_resources_to_roles": {
        "Annotator": {
            "view_items": {
                "statuses": [
                    "NotStarted",
                    "InProgress",
                    "Returned"
                ]
            }
        },
        "QA": {
            "view_items": {
                "statuses": [
                    "QualityCheck"
                ]
            }
        }
    }

Transitions

You can define links between two statuses, as well as the ability for a role to change an item’s status from one to another. These transitions will be visible in the editor for the roles that have access to them.

Annotator’s view of the status change in the editor.

Annotator’s view of the status change in the editor.

Transitions will not be visible to users with Project Admin and higher roles, because they can view and change any status available in the project.

Project Admin’s view of the status change in the editor.

Project Admin’s view of the status change in the editor.

In the transitions field, you can define every transition individually using the following structure:

"transitions": [
    {
        "name": "<transition_name>",
        "from": "<status_1>",
        "to": "<status_2>",
        "allowed_roles": [
            "<role_name>"
        ]
    }
]

Required transition fields:

  • "name" - string - The name of your transition (64 characters max). Transition names must be unique and are considered case-insensitive if the corresponding transition shares a from value with another transition.
  • "from" - string - The status that the transition starts from, as written in the workflow's statuses field.
  • "to" - string - The status that the transition changes the original status to, as written in the workflow's statuses field.
  • "allowed_roles" - array of strings - This defines which roles are allowed to make the transitions. A role must already have access to view the from status as written in the workflow’s allowed_resources_to_roles field.

Optional transition fields:

  • "automation" (optional) - object - One per transition. This allows you to define two types of automation in your workflow. Transitions with an automation won't appear in the editor's status dropdown list; the same transition must be written again without the automation (and with a unique name) for it to be available. These are the types of automations you can use:
    • onSave - Defines the status transition that takes place when the item is saved in the editor. If you only have an automated transition from your item's current state, the status dropdown won't be visible in the editor.
    • onRevert - Defines the status transition that takes place when the Revert button is clicked.
    • To include it in a transition:
      "transitions": [
          {
              "automation": {
                  "action": "<automation_type>"
              },
              "name": "<transition_name>",
              "from": "<status_1>",
              "to": "<status_2>",
              "allowed_roles": [
                  "<role_name>"
              ]
          }
      ]
      
  • "constraints" (optional) - array of strings - Each string specifies a condition that a transition might have (Not applicable to users with the role of Project Admin or above). If this condition isn’t met, then the transition can't be made. If you want to include multiple conditions for a transition, they must be included in separate strings, separated by commas. Some constraints are project-specific, but you can still include them all in the same workflow, they'll just only work for the corresponding project types. The constraints you can include, as well as the projects they are valid for, are as follows:
    • NO UNCLASSIFIED INSTANCE - Image, Video, Text - The instances in the item can't be unclassified.
    • NO EMPTY JSON - Image, Video, Text - The item must have at least one instance.
    • NO REQUIRED EMPTY - All projects - There can't be any required fields or attributes whose values are left empty.
    • To include it in a transition:
    "transitions": [
        {
            "constraints": [
                "<constraint_type_1>",
                "<constraint_type_2>",
                "<constraint_type_3>"
            ],
            "name": "<transition_name>",
            "from": "<status_1>",
            "to": "<status_2>",
            "allowed_roles": [
                "<role_name>"
            ]
        }
    ]
    

🚧

Missing fields

If you include the transitions key, you must have at least one transition written within, which includes the name, from, to, and allowed_roles keys, and their values can’t be null or empty.

🚧

Requirements and limitations

  • You may have multiple transitions that share the same name, and either the same from value or allowed_roles value. They just can't share all three values at once.
  • You can’t use the same status for the from and to fields in the same transition.
  • You can't include "automation" and "constraints" in the same transition.
  • The maximum number of transitions in a workflow is 200.

Transition examples

Here is an example where an Annotator can change an item’s status from InProgress to QualityCheck, and a QA can change an item’s status from QualityCheck to Returned.

"transitions": [
        {
            "name": "Send to QA",
            "from": "InProgress",
            "to": "QualityCheck",
            "allowed_roles": [
                "Annotator"
            ]
        },
        {
            "name": "Return to Annotator",
            "from": "QualityCheck",
            "to": "Returned",
            "allowed_roles": [
                "QA"
            ]
        }
]

If you want to be able to transition an item’s status from one status to multiple others, you must create a different transition for each one. For example, if you want the Annotator to transition from NotStarted to QualityCheck and Skipped, you must write the transitions as follows:

"transitions": [
    {
        "name": "Send to QA",
        "from": "NotStarted",
        "to": "QualityCheck",
        "allowed_roles": [
            "Annotator"
        ]
    },
    {
        "name": "Skip item",
        "from": "NotStarted",
        "to": "Skipped",
        "allowed_roles": [
            "Annotator"
        ]
    }
]

If you want to incorporate the "onSave" automation - in this example, the item is saved in the NotStarted state, which transitions the status to InProgress.

    "transitions": [
        {
            "automation": {
                "action": "onSave"
            },
            "name": "Automatically move to In Progress",
            "from": "NotStarted",
            "to": "InProgress",
            "allowed_roles": [
                "Annotator"
            ]
        }
    ]

If you want to incorporate the "onRevert" automation - in this example, this transition is fired when a user clicks Revert, undoing all actions and annotations in the file, and reverting the status back to NotStarted.

"transitions": [
    {
        "automation": {
            "action": "onRevert"
        },
        "name": "Revert all",
        "from": "InProgress",
        "to": "NotStarted",
        "allowed_roles": [
            "Annotator"
        ]
    },
    {
        "automation": {
            "action": "onRevert"
        },
        "name": "Revert all",
        "from": "Returned",
        "to": "NotStarted",
        "allowed_roles": [
            "Annotator"
        ]
    }
]

To include constraints in a transition - in this example, the following transition can't be made unless all three conditions are met.

"transitions": [
    {
        "constraints": [
            "NO UNCLASSIFIED INSTANCE",
            "NO EMPTY JSON",
            "NO REQUIRED EMPTY"
        ],
        "name": "Send to QA",
        "from": "NotStarted",
        "to": "QualityCheck",
        "allowed_roles": [
            "Annotator"
        ]
    }
]

Sample JSON

As an example, take a look at the default System workflow JSON below, where Annotators can't complete items.

{
    "roles": [
        "Annotator",
        "QA"
    ],
    "statuses": [
        "NotStarted",
        "InProgress",
        "QualityCheck",
        "Returned",
        "Completed",
        "Skipped"
    ],
    "start_status": "NotStarted",
    "allowed_resources_to_roles": {
        "Annotator": {
            "view_items": {
                "statuses": [
                    "NotStarted",
                    "InProgress",
                    "Returned"
                ]
            }
        },
        "QA": {
            "view_items": {
                "statuses": [
                    "QualityCheck"
                ]
            }
        }
    },
    "transitions": [
        {
            "automation": {
                "action": "onRevert"
            },
            "name": "revert",
            "from": "InProgress",
            "to": "NotStarted",
            "allowed_roles": [
                "Annotator"
            ]
        },
        {
            "automation": {
                "action": "onRevert"
            },
            "name": "revert",
            "from": "Returned",
            "to": "NotStarted",
            "allowed_roles": [
                "Annotator"
            ]
        },
        {
            "automation": {
                "action": "onSave"
            },
            "name": "automaticly to in progress",
            "from": "NotStarted",
            "to": "InProgress",
            "allowed_roles": [
                "Annotator"
            ]
        },
        {
            "constraints": [
                "NO UNCLASSIFIED INSTANCE", "NO EMPTY JSON", "NO REQUIRED EMPTY"
            ],
            "name": "Send to QA",
            "from": "NotStarted",
            "to": "QualityCheck",
            "allowed_roles": [
                "Annotator"
            ]
        },
        {
            "constraints": [
                "NO UNCLASSIFIED INSTANCE", "NO EMPTY JSON", "NO REQUIRED EMPTY"
            ],
            "name": "Send to QA",
            "from": "InProgress",
            "to": "QualityCheck",
            "allowed_roles": [
                "Annotator"
            ]
        },
        {
            "name": "Skip item",
            "from": "NotStarted",
            "to": "Skipped",
            "allowed_roles": [
                "Annotator"
            ]
        },
        {
            "name": "Skip item",
            "from": "InProgress",
            "to": "Skipped",
            "allowed_roles": [
                "Annotator"
            ]
        },
        {
            "constraints": [
               "NO UNCLASSIFIED INSTANCE", "NO EMPTY JSON", "NO REQUIRED EMPTY"
            ],
            "name": "Send to QA",
            "from": "Returned",
            "to": "QualityCheck",
            "allowed_roles": [
                "Annotator"
            ]
        },
        {
            "name": "Skip item",
            "from": "Returned",
            "to": "Skipped",
            "allowed_roles": [
                "Annotator"
            ]
        },
        {
            "constraints": [
                "NO UNCLASSIFIED INSTANCE, NO EMPTY JSON, NO REQUIRED EMPTY"
            ],
            "name": "Mark as Complete",
            "from": "QualityCheck",
            "to": "Completed",
            "allowed_roles": [
                "QA"
            ]
        },
        {
            "name": "Skip item",
            "from": "QualityCheck",
            "to": "Skipped",
            "allowed_roles": [
                "QA"
            ]
        },
        {
            "name": "Return to Annotator",
            "from": "QualityCheck",
            "to": "Returned",
            "allowed_roles": [
                "QA"
            ]
        }
    ]
}