# Establishing task I/O and write-back contracts

> Establish task input, output, and write-back contracts in Maestro Case so tasks read the right fields and update the case entity consistently.

## Overview

Task input/output (I/O) mapping defines the data contract between the **Case Entity** **[Coming Soon]**  and each task in a case plan. Input mapping controls which Case Entity fields a task receives, and output mapping (write-back) controls which Case Entity fields a task enriches after execution. Establishing clear I/O contracts ensures that every task reads the correct data, writes results to the right fields, and keeps the Case Entity as a reliable single source of truth.

**Audience:** Intermediate — Automation Developers and Solution Architects building case plans in Studio Web.

## Prerequisites

* Access to **Studio Web**.
* A **case project** created in Studio Web with at least one stage and one task defined. See [Create a case project](how-to-trigger-a-case-from-data-fabric.md#step-1-creating-or-opening-the-case-project) for setup instructions.
* A **Case Entity** **[Coming Soon]** with fields defined — either as a native Data Fabric entity, a Virtual Data Object (VDO), or fields passed through a case trigger. See [Case Entity overview](maestro-case-management-component-dictionary.md) for details.
* Familiarity with the supported task types: Human action, RPA, API workflow, Execute Connector, AI Agent, Maestro Agentic Process, and Child Case.

## Step 1: designing the case entity schema for I/O

Before mapping task inputs and outputs, define the Case Entity schema to distinguish between fields populated at case creation (input fields) and fields written by tasks during processing (output fields).

### Identifying input fields

Input fields are populated when the case is created — through a Data Fabric trigger, a connector event, or an API call. These fields provide the starting context for all tasks.

Examples of input fields:

* `policyNumber` — passed from the triggering system.
* `claimantName` — supplied by the case creator.
* `lossDescription` — free-text description provided at submission.

### Identifying output fields

Output fields are written by tasks as the case progresses. Each output field should have a single owning task to prevent write collisions.

Examples of output fields:

* `validationResult` — written by a "Validate Policy" connector task.
* `damageEstimate` — written by an "Estimate Damage" agent task.
* `adjusterDecision` — written by an "Adjuster Review" human task.

### Documenting field ownership

Annotate each output field with the task responsible for writing it. While the schema does not enforce ownership at runtime, this documentation prevents accidental collisions during design.

```json
{
  "entityName": "AutoInsuranceClaim",
  "fields": {
    "policyNumber":      { "type": "string",  "required": true },
    "claimantName":      { "type": "string",  "required": true },

    "policyValid":       { "type": "boolean", "writtenBy": "Validate Policy" },
    "extractedDetails":  { "type": "object",  "writtenBy": "Extract Details" },
    "damageEstimate":    { "type": "decimal", "writtenBy": "Estimate Damage" },
    "adjusterDecision":  { "type": "string",  "writtenBy": "Adjuster Review",
                           "enum": ["approve", "deny", "investigate_more"] },
    "payoutAmount":      { "type": "decimal", "writtenBy": "Calculate Payout" },
    "paymentReference":  { "type": "string",  "writtenBy": "Issue Payment" }
  }
}
```

:::note
Use namespaced field names (for example, `validation.result` vs. `categorization.result`) when multiple tasks produce structurally similar output. This avoids ambiguity and prevents the last-writer-wins problem.
:::

## Step 2: configuring input mapping for a task

Input mapping selects specific Case Entity fields and passes them as parameters to the task implementation (workflow, form, connector, or agent). This controls what data the task can see.

### Opening the task configuration panel

1. In the Case Plan designer, select the target stage.
2. Select the task you want to configure.
3. Open the **Input/Output** section of the task configuration panel.

### Mapping case entity fields to task parameters

1. In the **Input** section, select **Add input mapping**.
2. For each task parameter, choose the corresponding Case Entity field from the field picker.
3. Repeat for every parameter the task requires.

For example, a "Validate Receipts" task might use the following input mapping:

| Task Parameter | Case Entity Field |
|---|---|
| `receipts` | `caseEntity.lineItems[*].receiptUrl` |
| `policyId` | `caseEntity.department` |
| `totalAmount` | `caseEntity.totalAmount` |
| `currency` | `caseEntity.currency` |

### Following the principle of least privilege

Pass only the fields the task needs. Avoid mapping the entire Case Entity **[Coming Soon]**  to a single task. Scoping inputs reduces the risk of unintended data exposure and makes the task contract explicit.

## Step 3: configuring output mapping (write-back) for a task

Output mapping takes the task's result and writes specific values back to the Case Entity **[Coming Soon]** . This is the write-back mechanism that enriches the central source of truth.

### Defining output field mappings

1. In the same **Input/Output** section of the task configuration panel, locate the **Output** section.
2. Select **Add output mapping**.
3. For each result field the task produces, choose the target Case Entity field.

For example, a "Validate Receipts" task might use the following output mapping:

| Case Entity Field | Task Output Field |
|---|---|
| `caseEntity.validationResult` | `taskOutput.validationResult` |
| `caseEntity.validationStatus` | `taskOutput.status` |
| `caseEntity.invalidReceipts` | `taskOutput.failedItems` |

### Ensuring one-writer-per-field

Assign each Case Entity output field to exactly one task. If two tasks write to the same field, the last writer wins and earlier data is lost.

### Protecting read-only fields

Fields populated at case creation (for example, `claimantName`, `policyNumber`) should never appear as output targets. Do not map task outputs to these fields.

## Step 4: verifying the write-back chain across stages

Once individual task mappings are in place, validate that the data flows correctly from one stage to the next through the Case Entity **[Coming Soon]** .

### Tracing the data flow

Walk through each stage and confirm:

1. **Task A** in Stage 1 reads input fields from the Case Entity.
2. **Task A** writes its result to a specific Case Entity field via output mapping.
3. The **Case Manager** evaluates stage rules (rules first, Case Manager Agent fallback) using the updated Case Entity fields.
4. **Task B** in Stage 2 reads the field that Task A wrote, as its own input.

The pattern follows this sequence:

**Task writes to entity** &#8594; **Entity state changes** &#8594; **Rules evaluate** &#8594; **Next stage activates** &#8594; **Downstream task reads updated entity**

### Validating rule dependencies

For each stage entry, complete, exit, and re-entry rule, confirm that the Case Entity field it references in its **IF** clause is populated by an upstream task's output mapping. If a rule references a field that no task writes to, the rule can never evaluate to true.

For example:

* **Stage Entry rule:** **IF** `caseEntity.adjusterDecision == "approve"` — confirm the "Adjuster Review" task maps its decision output to `caseEntity.adjusterDecision`.
* **Stage Exit rule:** **IF** `caseEntity.policyValid == false` — confirm the "Validate Policy" task maps its result to `caseEntity.policyValid`.

## Step 5: handling re-entry scenarios

By default, every task in a re-entered stage re-executes and overwrites its previous output in the Case Entity. Use the per-task **`runOnlyOnce`** flag to opt specific tasks **out** of re-execution when their previous output is still valid.

### Tasks that should re-execute on re-entry

Leave `runOnlyOnce: false` (the default) for tasks whose output may change after rework. These tasks re-run and overwrite their previous output in the Case Entity **[Coming Soon]**.

### Preserving outputs from tasks that should not re-run

Set `runOnlyOnce: true` on tasks whose previous output is still valid (for example, an initial categorization that does not depend on corrected data). These tasks are skipped on re-entry; their Case Entity fields remain unchanged.

| Task | `runOnlyOnce` | Behavior on Re-entry |
|---|---|---|
| Validate Receipts | `false` *(default)* | Re-executes and overwrites `validationResult` |
| Categorize Expenses | `true` | Skipped; retains previous `categories` value |
| Check Policy Limits | `false` *(default)* | Re-executes and overwrites policy check output |

## Expected outcome

After completing these steps:

* Every task in the case plan has explicit input mappings that scope the data it receives from the Case Entity **[Coming Soon]** .
* Every task has explicit output mappings that write results back to designated Case Entity fields.
* Each Case Entity output field has a single owning task, preventing write collisions.
* Stage rules reference Case Entity fields that upstream tasks reliably populate.
* Re-entry behavior is configured so that tasks produce fresh or preserved output as appropriate.
* The Case Entity serves as the single source of truth throughout the entire case lifecycle.

## Use case example

**Scenario:** Auto insurance claims processing with four stages — FNOL Intake, Investigation, Assessment, and Settlement.

| Stage | Task | Input (from Case Entity **[Coming Soon]** ) | Output (to Case Entity) |
|---|---|---|---|
| FNOL Intake | Validate Policy | `policyNumber` | `policyValid` |
| FNOL Intake | Extract Details | `lossDescription, photos` | `extractedDetails` |
| Investigation | Analyze Photos | `photos, vehicleInfo` | `photoAnalysis` |
| Investigation | Field Inspection | `claimId, vehicleInfo, lossDescription` | `fieldInspection` |
| Assessment | Estimate Damage | `photoAnalysis, fieldInspection, extractedDetails` | `damageEstimate` |
| Assessment | Adjuster Review | `damageEstimate, photoAnalysis, policeReport` | `adjusterDecision` |
| Settlement | Calculate Payout | `damageEstimate, policyNumber` | `payoutAmount` |
| Settlement | Issue Payment | `payoutAmount, claimantName` | `paymentReference` |
| Settlement | Notify Claimant | `claimantEmail, payoutAmount, paymentReference` | — |

In this example, the "Estimate Damage" task in the Assessment stage consumes three fields written by upstream tasks in earlier stages (`photoAnalysis`, `fieldInspection`, `extractedDetails`). The Case Manager uses `adjusterDecision` — written by the "Adjuster Review" task — to evaluate the Settlement stage's Entry rule.

## Code snippet

The following JSON illustrates a complete I/O mapping configuration for two tasks within the FNOL Intake stage:

```json
{
  "stage": "FNOL Intake",
  "tasks": [
    {
      "name": "Validate Policy",
      "type": "connector",
      "required": true,
      "runOnlyOnce": false,
      "input": {
        "policyNumber": "caseEntity.policyNumber"
      },
      "output": {
        "caseEntity.policyValid": "taskOutput.isValid"
      }
    },
    {
      "name": "Extract Details",
      "type": "agent",
      "required": true,
      "runOnlyOnce": true,
      "input": {
        "description": "caseEntity.lossDescription",
        "photos": "caseEntity.photos"
      },
      "output": {
        "caseEntity.extractedDetails": "taskOutput.structuredData"
      }
    }
  ]
}
```

## Troubleshooting

| Symptom | Likely Cause | Resolution |
|---|---|---|
| Downstream task receives empty or null input | Upstream task output mapping does not populate the expected Case Entity field | Verify that the upstream task's output mapping targets the correct Case Entity field name. |
| Stage rule never evaluates to true | The Case Entity field referenced in the rule is not written by any task | Add an output mapping from the responsible task to the referenced field. |
| Task overwrites data written by another task | Two tasks map their output to the same Case Entity field | Assign a unique Case Entity field to each task. Use namespaced field names to avoid collisions. |
| Re-entry produces stale results | Task has `runOnlyOnce` set to `true` but its output depends on corrected data | Set `runOnlyOnce` to `false` for tasks that must re-validate or re-process updated data. |
| Read-only field is overwritten during processing | A task output mapping targets a field that should be immutable (for example, `policyNumber`) | Remove the output mapping. Ensure input-only fields are never used as output targets. |
| Agentic Case Manager run succeeds, but no tasks trigger | The agent's output does not match the required `caseManagerDecisions.tasksToRun` shape (for example, a plain array of task names) | Match the exact contract in [Case Manager input and output contract](case-manager-input-output-contract.md). |

![Warning shown on the Case Manager Agent task's Outputs section when caseManagerDecisions is missing or malformed](https://dev-assets.cms.uipath.com/assets/images/maestro/case-agent-properties-54e1071b.webp)

This warning appears on the **Outputs** section of the Case Manager Agent task properties when `caseManagerDecisions` is missing or does not return the correct value format. See [Case Manager input and output contract](case-manager-input-output-contract.md) for the exact shape to use.

## Limitations

* Variable filtering in the Monitoring view applies only to instances that run after you enable the filter. Existing instances are not retroactively filtered.
* The `writtenBy` annotation in the entity schema is a design-time convention for documentation purposes. Maestro does not enforce single-writer rules at runtime.
* Field-level access control on the Case Entity **[Coming Soon]**  is not available in this preview release. All tasks with output mappings to a field can write to it.

## Next steps

* [How to configure stage rules](how-to-model-primary-secondary-stages.md#step-2-configuring-primary-stage-rules) — Learn how to use Case Entity fields in entry, complete, exit, and re-entry rules.
* [How to configure re-entry behavior](how-to-configure-a-rework-loop-re-entry.md) — Define which tasks re-execute when a case returns to a previously completed stage.
* [Case Entity overview](maestro-case-management-component-dictionary.md) — Understand the three out-of-the-box data objects (Case Entity **[Coming Soon]** , Case Documents, Case Comments) and how to bring data into a case.
* [Task types reference](maestro-case-management-component-dictionary.md#task-types) — Review all supported task types and their configuration options.
