Blocks (formerly known as actions) are the building blocks of Workflows. Workflows are made up of individual blocks, which are each responsible for a specific task. A Workflow allows you to run a sequence of tasks that can reference contextual data from your workspace.
Cortex offers a searchable library of blocks that can be added to your Workflows:
Core blocks
Perform actions such as requiring a manual approval on a step within a Workflow.
Cortex blocks
Perform Cortex-based actions, such as getting Scorecard scores for an entity.
Note that Cortex blocks use the permissions of the Workflow's initiating user. If the user does not have permissions to execute the action associated with a given block, the block will fail.
Third-party integration blocks
For example, you can add a block that creates a new repository in GitHub, or you can add a block that creates a new incident in ServiceNow.
PagerDuty: Create an incident, create a team, list escalation policies, and more.
ServiceNow: Create an incident, list groups, get user information, and more.
Slack: Get channel info, list users, send a message, and more.
Before adding an integration-based block, make sure you have configured the integration with the correct permissions described in Cortex's documentation for that integration.
While viewing the blocks library, click the integration block you want to add.
The necessary permissions needed for the block are included in the block library. For example:
At the bottom of the modal, click Insert.
The block is inserted into your Workflow, and a configuration form appears in the side panel.
In the side panel, configure the block metadata:
Block name: Add a name for your block.
Slug: Add a unique identifier for your block
When the integration supports multiple configurations, you'll be prompted to select the configuration alias to use with the block. The block will authenticate using the selected configuration, so ensure that you select the configuration with the required permissions.
Additional input fields differ depending on which block you choose.
These inputs are all template-able using Mustache-syntax ({{ ... }}). For fields that are not textual, click the "Path" icon on the right of the input to switch to Mustache-based templating.
Number input
Number input in templating mode
At the bottom of the side panel, click Save.
Additional instructions for Slack blocks
For additional information on configuring a Slack block, see below.
Slack
The Slack block sends a Slack message to a given channel.
Use cases: Notify users or teams about Workflow events or results. For example, you could send a Slack message when a service drops below a Scorecard threshold, or you could notify a new developer when onboarding is complete.
Prerequisites
Before configuring a Slack block:
Make sure the Cortex Slack Bot is added to the channel you want to send messages to via the Workflow.
Make sure the Slack Bot has the chat:write.public permission scope enabled.
Configure a Slack block
To configure a Slack block:
Click Slack from the list of blocks.
Enter a name.
The slug field will automatically pre-populate based on the name you enter.
Under Channel name, select a channel.
The channels listed in the dropdown are pulled from your organization's integration with Slack.
Under Message text, enter the message that will be sent in Slack via this block.
You can enter a simple string or use templating for a more dynamic message. For example, you can templatize to include the email address of the person who initiated the Workflow, reference prior blocks, or reference outputs.
Click Save.
When testing your new Slack block, if you receive the error Cannot send message to Slack channel without invitation, please try reinstalling the Slack integration to ensure that the correct permissions are configured.
Configure a core block
Expand the tiles below for instructions on configuring each type of block.
Branch
A Branch allows you to set up to five conditional paths for a Workflow.
Configure a branch
To configure a branch:
Click Branch from the list of blocks.
On the right side of the page, enter a Block name.
The slug field will automatically pre-populate based on the name you enter.
Click +Add Path.
On the right side of the page, the "Conditional paths" section will expand. Enter a name, a slug, and a path expression.
The path expression is compatible with CEL syntax. The path expression does not accept dashed values; if you reference a block's slug that contains a dash, wrap the slug in quotes and square brackets.
For example, if you want to reference a block with the slug slug-example, the expression would begin with actions["slug-example"].
Note: Autocomplete will provide correctly formatted options based on the blocks defined in your Workflow.
Under the Path expression text box, click Save.
You will be redirected to the block editor page, showing your newly-added path in the Workflow visual.
Optionally, add additional paths and a fallback path.
Click + under a path to add the next type of block. You can add any type, including another branch.
When you are finished adding paths, click Save at the bottom of the block editor.
If you want to add additional blocks that occur after the paths within your branch, click + below the branch box in the Workflow editor.
How paths work
The paths defined run sequentially. The first path that returns true will execute, even if subsequent paths would also return true. The Workflow will then continue performing blocks in that path. You can also set a fallback path that will run if all other paths fail.
Primary and nested branches function the same way.
Nested branches
To nest a branch:
In the visual Workflow, click the + that is branched off your original branch.
On the right side of the page in the Workflow editor, select Branch.
Enter a name for your branch, then click Save.
There are no limits on how many branches you can nest.
Data transformation
A Data transformation performs data transformations using jq. Except for the block name and slug, the only field required is the jq expression.
Use cases: Manipulate or format data between steps. For example, transform user input before sending it to an API or before using it in another Workflow block.
Configure a data transformation
To configure a data transformation:
Click Data transformation from the list of blocks.
Enter a name.
The slug field will automatically pre-populate based on the name you enter.
Enter a jq expression. This field can pass any sort of jq expression, as long as the variables and context are referenced differently.
Although you would typically use {} to template the context of your Workflow, in this field you’ll need to reference such values as jq query values.
Click Save.
HTTP request
The HTTP request makes and records a request to a given URL, allowing you to integrate with external APIs or internal systems.
For use cases requiring asynchronous operations (e.g., provisioning cloud resources, CI/CD pipelines), use the HTTP async action.
Configure an HTTP request
To configure an HTTP request:
Click HTTP request from the list of blocks.
Enter a name.
The slug field will automatically pre-populate based on the name you enter.
Select an HTTP method. The options are DELETE, GET, PATCH, POST, or PUT.
Configure the fields:
URL: Enter a static URL or use a template to reference other blocks.
If you use {{actions.url.outputs.result}}, for example, you can set the URL to the output of a jq action. In this example:
.actions indicates a reference to a Workflow block
.url is the slug for the Workflow block we’re referencing
.outputs is the location of the actual output of the jq expression
.result is the result field where the output is stored
Because Mustache performs HTML escaping by default, special characters referenced in a value with two curly braces ({{}}) will be converted to their associated HTML encoding. For example, {{=}} would become =. To reference a non-escaped value, use three curly braces ({{{=}}}).
Headers: Click one of the options provided, or enter your own.
When using a secret with a header, prefix the secret with context..
Payload: This field appears if you are using an HTTP request that sends a payload. The payload that you supply can also be templated and can reference an entity that the Workflow is being run with. Some additional steps are required to properly template raw JSON in the payload field:
Single primitive values will work as expected. To add JSON objects or arrays, create a Data Transformation block that accesses the relevant JSON and pipes it into the tojson built-in.
For example, .context.initiatedBy | tojson would enable a user to add the full initiatedBy object () into an HTTP request payload. When templating this value, three curly braces are needed in order to reference a non-escaped value. Continuing our earlier example, if the Data Transformation block we just created has the slug transform-to-json, then the payload would include {{{actions.transform-to-json.outputs.result}}}.
Click Save.
If using special characters when templating, make sure to include three curly braces to reference a non-HTML-escaped value.
HTTP action (async)
The HTTP async request makes and records a request to a given URL. This block will pause execution until a callback API is invoked or a timeout occurs, enabling long-running Workflows.
You can pass the callback URL to the external service by using the template variable {{callbackUrl}}. This can be passed as part of the URL, in a header, or in the payload.
For example, when passing the variable in a URL, it would look like the following format: https://example.com/?url={{callbackUrl}}.
Configure an HTTP async request
Click HTTP action (async) from the list of blocks.
Enter a name.
The slug field will automatically pre-populate based on the name you enter.
Select an HTTP method. The options are DELETE, GET, PATCH, POST, or PUT.
Configure the fields:
URL: Enter a static URL or use a template to reference other blocks.
If you use {{actions.url.outputs.result}}, for example, you can set the URL to the output of a jq action. In this example:
.actions indicates a reference to a Workflow block
.url is the slug for the Workflow block we’re referencing
.outputs is the location of the actual output of the jq expression
.result is the result field where the output is stored
Because Mustache performs HTML escaping by default, special characters referenced in a value with two curly braces ({{}}) will be converted to their associated HTML encoding. For example, {{=}} would become =. To reference a non-escaped value, use three curly braces ({{{=}}}).
Optionally include additional headers: Click one of the provided headers, or enter your own.
When using a secret with a header, prefix the secret with context..
Payload: This field appears if you are using an HTTP request that sends a payload. The payload that you supply can also be templated and can reference an entity that the Workflow is being run with. Some additional steps are required to properly template raw JSON in the payload field.
Single primitive values will work as expected, but to add JSON objects or arrays, follow these steps you first need to create a Data Transformation action that accesses the relevant JSON and pipes it into the tojson built-in.
For example, .context.initiatedBy | tojson would enable a user to add the full initiatedBy object () into an HTTP request payload. When templating this value, three curly braces are needed in order to reference a non-escaped value. Continuing our earlier example, if the data transformation action we just created has the slug transform-to-json, then the payload would include {{{actions.transform-to-json.outputs.result}}}.
Timeout: Configure a timeout for this action. The maximum is 30 days and the minimum is 1 minute.
After a timeout, the block will fail with the status timed_out. If you have notifications enabled, you will receive a notification if you initiate a Workflow and it times out.
Click Save.
If using special characters when templating, make sure to include three curly braces to reference a non-HTML-escaped value.
Handling the callback
Once the HTTP Async Request block runs, Cortex sends the configured request and pauses the Workflow. To resume execution, the external system must call the callback URL provided by Cortex and follow the required schema.
The callback request must:
Use the POST method
Include a valid Cortex API key in the Authorization header (Bearer <token>)
Match the expected request body shape. Below is an example:
See the full Cortex API reference for callback details and status options (SUCCESS, FAILURE, CANCELLED).
If the callback is missing required fields, improperly formatted, or lacks authentication, Cortex will not accept it, and the Workflow will remain paused or fail.
JavaScript
Configure a JavaScript block
Use a JavaScript block to insert custom code or add looping and other logic to your Workflows.
The JavaScript runtime supports the ES2020 specification and has an implementation of Fetch API, allowing you to make HTTP requests directly in the script rather than needing to add an additional HTTP request block to your Workflow.
On the right side of the page, configure the fields:
Block name: Enter a descriptive name for your block.
Slug: The slug field will automatically pre-populate based on the name you enter.
JavaScript: Enter the script you want to run. The script must end with a return statement. The value from the return statement is exposed via outputs.result.
For example, in the script return {"a": 1, "b": 2}, the result can be referenced from subsequent blocks as actions.<SLUG>.outputs.a.
You can reference previous blocks and run context by accessing actions and context. For example, actions["jq"].outputs.result
If you want the block to fail, you can use the throw statement. For example:
let previous = actions.previous.outputs.result;
if (previous == null) {
throw "Some error";
}
Click Save.
Manual approval
A Manual approval pauses the Workflow to get approval from a member of a given Team. Like with user inputs, the Workflow will proceed to the next block once it has been approved.
Configure a manual approval
To configure a manual approval:
Click Manual approval from the list of blocks.
Enter a name.
The slug field will automatically pre-populate based on the name you enter.
Under Teams allowed to approve, select one or more teams who are allowed to approve the request from this block. Any member of a given team can approve the block.
Click Save.
You can have multiple manual approvals within a given Workflow. If you have two blocks with two different sets of teams set as approvers, each team will only be able to approve the block they are defined under.
Pending approval
When a manual approval block is triggered, users that belong to teams designated as approvers will see Pending approvals at the top of their Workflows page.
This section displays any blocks that are pending your approval. If manual approval actions exist within a Workflow, but do not require your approval, they will not appear here, even if you are designated to approve a different block in the same Workflow.
You can open any Workflow in the pending approval list to Approve or Reject the block.
Once all of your approval requests have been approved or rejected, this tab will disappear from the Workflows page.
Scaffolder
The Scaffolder uses a Cortex Scaffolder template to perform a given function. You must have the Execute Scaffolder permission to configure a Scaffolder block.
Use cases: Standardize and bootstrap service creation
Workflow example: You could create a new service by running multiple Scaffolder templates, each representing a different repository, using data collected from the user via a user input block..
To configure a Scaffolder:
Click Scaffolder from the list of blocks.
Enter a name.
The slug field will automatically pre-populate based on the name you enter.
Under Scaffolder template, select a template from the dropdown.
This dropdown pulls in all templates available from the Scaffolder page.
Configure the remaining fields. The fields differ depending on the template's specifications and available Git providers. The option to create a repo also may or may not be visible, depending on whether the template requires a pull request.
Click Save.
If using the Scaffolder to create a new repo and the desired repo already exists, Cortex will surface an error and prevent the flow from continuing.
Define Scaffolder template overrides
You can also define Scaffolder template overrides for a block — these will override template fields with output variables from a previous Workflow step, or from the context of the Workflow.
To add an override:
In the bottom of the block configuration, click Add variable.
In the override variable modal, click the Variable dropdown to select the Scaffolder template fields to override. Note that the options in this dropdown will be pulled from fields in the Scaffolder template you selected in the first step.
Under Path, enter the path to the actual value we want in the Workflow.
For example, if you wanted to override the Project name variable for a Scaffolder with the tag of the entity you’re running, the path would be context.entity.tag — that will obtain and supply the value.
If you want to override the options that are available to a user running the Workflow, toggle on Is value override.
For example, if you wanted to restrict the project name to some set of values based on a particular HTTP fetch, you would toggle this setting on.
When toggled on, the value being grabbed in lieu of project_name is the value of the variable. When toggled off, the value grabbed would be the option provided for that variable, i.e. the project name.
Running a workflow with a Scaffolder step
When you run a workflow with a Scaffolder block, the Scaffolder will prompt you for user input. Some fields, such as Commit message and Pull request title, only appear if your Scaffolder step creates a Pull Request rather than a repository.
After the inputs are provided, the Scaffolder will run.
User input
The User input block pauses the Workflow and prompts the user for specific inputs. Once user inputs are entered, the Workflow will proceed to the next block.
Use cases: Collect new developer details (name, email, GitHub username) during onboarding, or gather IAM policy requirements before creating a policy in AWS.
Workflow example: Onboard a new developer > Collect user information in User input block > Subsequent actions use this data to create accounts and send notifications.
Note that users with the Edit Workflows permission are inherently able to obtain secret values using complex data transformation on secrets or echoing services.
To configure a user input block:
Click User input from the list of actions.
Enter a name.
The slug field will automatically pre-populate based on the name you enter.
Click Add user input.
Configure the "Create input field" form:
Name: Enter a name for the input field.
Key: Enter a value to be used when templating. This must be unique across fields in a given user input block.
Description: Enter a description of the input field.
Type: Select from the following:
Number: A numerical value.
If you select this type, you can then choose Integer or Decimal for the number format, and select a minimum and maximum value.
Paragraph: Multi-line, freeform text.
Secret: Capture a secret value.
Select: Manually configured or predefined data selection.
Toggle on Allow multiple to enable multiple selections for a given input field.
Text: Short, freeform text.
Toggle: Boolean value.
Date: Date in YYYY-MM-DD format.
Placeholder: Enter text to display when a field is empty.
Default value: Enter a value that will automatically populate the field.
Validation regex: Set validation options for the input field.
If you chose the Secret type, enter the secret value that a user will need to input to run this action.
Path to override value: Optionally, enter the previous block output path to override the value of a given input.
For example, if the key is name, then entering actions.name-action.outputs.name in the previous block output path field will use the output from a previous step as the name.
Is override value editable: Enable this option if you want to allow users to edit the override value before continuing to execute the Workflow.
Click Add input at the bottom of the "Edit input field" modal.
Click Save.
Additional steps for the Select type
If you chose the type Select while configuring the user input block, additional fields must be configured depending on which Data source you select:
Manual data source: You can manually define each option for the input. You can select any of these defined options as the default value.
Cortex entity data source: You can filter the entities that will be available for user selection. If you don't set filters, the input will apply to all entities in your catalog.
Cortex user data source: You can filter by teams and users to determine the options available to users. If you don't set filters, the input will apply to all Cortex users and Teams.
Slack channels data source: You can choose to include or exclude one or more Slack channels from the available options. The default values will include all Slack channels registered in Cortex.
Duplicating a block
There may be an instance where you want to repeat a task within your Workflow. It is possible to duplicate an existing block.
To duplicate a block:
In Cortex, navigate to the Workflow that contains the block you want to copy.
Click the 3 dots icon on the right side of the block.
In the dropdown menu, click Duplicate block.
A copy of the block will be duplicated in place within the Workflow.
If needed, drag and drop the block to reorder it in the Workflow.
Using request signing with Workflow blocks
If you're using a Workflow as a way to trigger hooks into internal tooling, we recommend validating that the request is actually originating from Cortex using request signing. Signing secrets are added to requests coming from Workflow blocks.
We add the following headers to each request made by Cortex. Use these headers to verify that the request is valid and originated from Cortex:
x-cortex-timestamp
This header uses the current timestamp in millis, and is used to prevent replay attacks. Cortex will sign the requests using the format <timestamp>.<body>.
x-cortex-timestamp-only-signature-256
This header calculates the SHA256 signature using only the timestamp. Use this header in environments where the HTTP request body is unavailable due to platform limitations.
x-cortex-signature-256
This header uses the SHA256 algorithm. For security best practices, we recommend using this header rather than x-cortex-signature.
x-cortex-signature
This header uses the SHA1 algorithm and exists for backward compatibility. SHA1 is considered unsafe and this signature should be considered deprecated.
To configure a signing secret:
In Cortex, navigate to Settings > Secrets, then scroll down to the "Request signing secret" section.
Enter a secret into the text field, then click Save secret.