# save_scenario

## What it answers

Create or change a saved scenario, as the Model Calculator does. Without scenarioId it creates one (name and range required; payrollGridId/expenseGridId choose grids when several exist). With scenarioId and baseRevision from get_scenario it changes only the fields you give; a stale baseRevision is refused and nothing is overwritten, so read the scenario again. rows are Include/exclude choices by rowKey from get_scenario with includeRows, and replace the stored choices. The Base case cannot be saved, and this tool does not delete or restore scenarios. The scenario belongs to the person who owns this connection: only its creator or an administrator can change it. Requires the connection to allow changes, Agents may change data on the account for the owner, and Model Calculator access (or administrator). Recorded in the change log as made by the agent, with the optional reason. Read parakeeto://methodology for shared response conventions and INVALID_ARGUMENT guidance.

Changes data. Listed only on a connection that is allowed to change data, and runs only when the connection owner may change data on the account.

## Arguments

| Argument | Type | Required | Default | Allowed values |
| --- | --- | --- | --- | --- |
| `account` | string (uuid) | no | — | — |
| `includeDefinitions` | boolean | no | `true` | — |
| `scenarioId` | string | no | — | `minLength: 1`; `maxLength: 64` |
| `baseRevision` | string | no | — | pattern `^[1-9]\d*$` |
| `name` | string | no | — | `minLength: 1`; `maxLength: 200` |
| `range` | object | no | — | — |
| `range.from` | string | yes | — | pattern `^\d{4}-\d{2}-\d{2}$` |
| `range.to` | string | yes | — | pattern `^\d{4}-\d{2}-\d{2}$` |
| `includePending` | boolean | no | — | — |
| `rows` | array of object | no | — | `maxItems: 2000` |
| `rows[].rowKey` | object | yes | — | — |
| `rows[].rowKey.name` | string | yes | — | `maxLength: 500` |
| `rows[].rowKey.startDate` | string or null | yes | — | `maxLength: 10` |
| `rows[].rowKey.occurrence` | string | yes | — | pattern `^\d{1,6}$` |
| `rows[].rowKey.siblings` | string | yes | — | pattern `^[1-9]\d{0,5}$` |
| `rows[].rowKey.hint` | string or null | yes | — | `maxLength: 100` |
| `rows[].included` | boolean | yes | — | — |
| `overrides` | object | no | — | — |
| `overrides.grossCapacity` | string | no | — | pattern `^-?\d+(?:\.\d+)?$` |
| `overrides.modelAbr` | string | no | — | pattern `^-?\d+(?:\.\d+)?$` |
| `overrides.modelUtilization` | string | no | — | pattern `^-?\d+(?:\.\d+)?$` |
| `overrides.deliveryPayrollBudget` | string | no | — | pattern `^-?\d+(?:\.\d+)?$` |
| `overrides.deliveryExpenseBudget` | string | no | — | pattern `^-?\d+(?:\.\d+)?$` |
| `overrides.smPayrollBudget` | string | no | — | pattern `^-?\d+(?:\.\d+)?$` |
| `overrides.smExpenseBudget` | string | no | — | pattern `^-?\d+(?:\.\d+)?$` |
| `overrides.adminPayrollBudget` | string | no | — | pattern `^-?\d+(?:\.\d+)?$` |
| `overrides.adminExpenseBudget` | string | no | — | pattern `^-?\d+(?:\.\d+)?$` |
| `overrides.facilitiesExpenseBudget` | string | no | — | pattern `^-?\d+(?:\.\d+)?$` |
| `payrollGridId` | string (uuid) | no | — | — |
| `expenseGridId` | string (uuid) | no | — | — |
| `reason` | string | no | — | `maxLength: 500` |

## Returned fields

The result is an envelope: `ok: true` with `data`, or `ok: false` with `error`. Error codes: `MODEL_CALCULATOR_ACCESS_REQUIRED`, `PAYROLL_GRID_MISSING`, `PAYROLL_GRID_REQUIRED`, `PROJECT_GRID_REQUIRED`, `EXPENSE_GRID_REQUIRED`, `PAYROLL_ENTRY_REFERENCE_STALE`, `ACCOUNT_NOT_FOUND`, `ACCOUNT_CONFIGURATION_MISSING`, `NO_IMPORTED_TIME`, `NOTHING_IMPORTED`, `ACCOUNT_REQUIRED`, `NO_REACHABLE_ACCOUNTS`, `FEATURE_NOT_ENTITLED`, `PERMISSION_DENIED`, `CALCULATION_FAILED`, `INTERNAL_ERROR`, `INVALID_ARGUMENT`.

- `data`: object
  - `data.account`: string (uuid)
  - `data.created`: boolean
  - `data.scenario`: object
    - `data.scenario.id`: string
    - `data.scenario.name`: string
    - `data.scenario.readOnly`: boolean
    - `data.scenario.revision`: string or null (pattern `^[1-9]\d*$`)
    - `data.scenario.window`: object or null
      - `data.scenario.window.from`: string (pattern `^\d{4}-\d{2}-\d{2}$`)
      - `data.scenario.window.to`: string (pattern `^\d{4}-\d{2}-\d{2}$`)
    - `data.scenario.includePending`: boolean or null
    - `data.scenario.createdByName`: string or null
    - `data.scenario.updatedAt`: string (date-time) or null
    - `data.scenario.canManage`: boolean
  - `data.definitions`: map of string to string, optional
    - `data.definitions.*`: string
  - `data.caveats`: array of object
    - `data.caveats[].code`: string
    - `data.caveats[].message`: string
    - `data.caveats[].reference`: string, optional

On failure:

- `error`: object
  - `error.code`: string (`"MODEL_CALCULATOR_ACCESS_REQUIRED"`, `"PAYROLL_GRID_MISSING"`, `"PAYROLL_GRID_REQUIRED"`, `"PROJECT_GRID_REQUIRED"`, `"EXPENSE_GRID_REQUIRED"`, `"PAYROLL_ENTRY_REFERENCE_STALE"`, `"ACCOUNT_NOT_FOUND"`, `"ACCOUNT_CONFIGURATION_MISSING"`, `"NO_IMPORTED_TIME"`, `"NOTHING_IMPORTED"`, `"ACCOUNT_REQUIRED"`, `"NO_REACHABLE_ACCOUNTS"`, `"FEATURE_NOT_ENTITLED"`, `"PERMISSION_DENIED"`, `"CALCULATION_FAILED"`, `"INTERNAL_ERROR"`, `"INVALID_ARGUMENT"`)
  - `error.argument`: string, optional (`minLength: 1`)
  - `error.message`: string
  - `error.accounts`: array of object, optional
    - `error.accounts[].id`: string (uuid)
    - `error.accounts[].name`: string
  - `error.payrollGrids`: array of object, optional
    - `error.payrollGrids[]`: same shape as `error.accounts[]`
  - `error.projectGrids`: array of object, optional
    - `error.projectGrids[]`: same shape as `error.accounts[]`
  - `error.expenseGrids`: array of object, optional
    - `error.expenseGrids[]`: same shape as `error.accounts[]`
  - `error.context`: object, optional
    - `error.context.account`: object
      - Further fields: see the response.
    - `error.context.imports`: array of object
      - Further fields: see the response.
    - `error.context.hasTimeEntries`: boolean
    - `error.context.reports`: array of object
      - Further fields: see the response.

## Definitions

Returned in `definitions` when `includeDefinitions` is true (the default). It is a map of string to string: each key names a field and each value is its definition text.

## Caveats

Always empty for this tool.

Read every caveat before interpreting a figure. See [methodology](</methodology.md>) on how to communicate caveats and data-quality conditions.

## Example call

```json
{
  "name": "save_scenario",
  "arguments": {
    "name": "Hire two designers",
    "range": {
      "from": "2026-01-01",
      "to": "2026-12-31"
    }
  }
}
```

Add `account` with an identifier from `list_accounts`; omit it only when the connection reaches exactly one account.
