# Writing a case file A **case file** is a plain-text JSON file that holds everything the Settlement Sandbox knows about one divorce: the two people, every asset, and one or more ways of dividing them. You can build a case entirely inside the sandbox, or write the file yourself (or have an AI assistant write it) and open it. This guide covers the second path, completely. - **Format version:** `settlement-sandbox/1` - **Machine-readable schema:** [`case.schema.json`](case.schema.json) - **Examples to copy:** [`examples/minimal.json`](examples/minimal.json) and [`examples/full-example.json`](examples/full-example.json) --- ## Contents 1. [Quick start](#1-quick-start) 2. [Opening the file](#2-opening-the-file) 3. [JSON rules in one minute](#3-json-rules-in-one-minute) 4. [The whole file at a glance](#4-the-whole-file-at-a-glance) 5. [Top-level fields](#5-top-level-fields) 6. [Parties](#6-parties) 7. [Settings](#7-settings) 8. [Assets](#8-assets) 9. [Qualities: how an asset is treated](#9-qualities-how-an-asset-is-treated) 10. [Kinds: shortcuts that fill in qualities](#10-kinds-shortcuts-that-fill-in-qualities) 11. [Scenarios](#11-scenarios) 12. [Who gets what: `alloc`](#12-who-gets-what-alloc) 13. [Payments between the parties: `transfers`](#13-payments-between-the-parties-transfers) 14. [Revisions](#14-revisions) 15. [How the numbers are worked out](#15-how-the-numbers-are-worked-out) 16. [What the importer fixes, and what stops it](#16-what-the-importer-fixes-and-what-stops-it) 17. [Recipes for common assets](#17-recipes-for-common-assets) 18. [A complete example](#18-a-complete-example) 19. [Checklist before you open the file](#19-checklist-before-you-open-the-file) 20. [Having an AI assistant write the file](#20-having-an-ai-assistant-write-the-file) 21. [Privacy](#21-privacy) --- ## 1. Quick start This is a complete, valid case file. Save it as `my-case.json` and open it in the sandbox. ```json { "schema": "settlement-sandbox/1", "name": "Minimal example", "parties": [ { "id": "A", "name": "Alex" }, { "id": "B", "name": "Sam" } ], "assets": [ { "id": "checking", "name": "Joint checking", "kind": "cash", "value": 24000 }, { "id": "alex_401k", "name": "Alex 401(k)", "kind": "pretax", "value": 180000, "q": { "titled": "A" } }, { "id": "home", "name": "Family home", "kind": "home", "value": 520000, "q": { "basis": 340000 } } ] } ``` That's all that's required. Everything left out gets a sensible default: - **No `scenarios`:** one scenario is created where everything is divided **as titled**. Assets in A's name go to A, B's go to B, and joint assets are split 50/50. - **No `q` (qualities):** each asset is treated according to its `kind`. A `pretax` account is taxed as income when withdrawn, a `home` has selling costs and a $250,000 gain exclusion, and so on. - **No `settings`:** the target is an even split, later payments are discounted at 4.5% a year, and the warning thresholds are $5,000 and $20,000. Add detail only where it changes the answer. --- ## 2. Opening the file 1. Go to the Settlement Sandbox. 2. Choose **File › Open case file…** and pick your `.json` file. You can also **drag the file onto the page**. 3. The sandbox checks the file before loading it: - **If something is wrong**, nothing is loaded. A list shows each problem, where it is, and how to fix it. - **If something was unclear but fixable** (for example `"$103,400"` written as text), the case opens. A list shows every guess the sandbox made, so you can confirm each one. - **If everything is right**, the case simply opens. **In Chrome or Edge**, the sandbox asks for permission to edit the file. Allow it, and every change you make is saved back into that same file as you work. Any corrections from step 3 are written into it the next time it saves. **In Firefox and Safari**, the file is read but not written back. Use **File › Save** to download an updated copy. The file never leaves your computer. See [Privacy](#21-privacy). --- ## 3. JSON rules in one minute JSON is strict. The sandbox forgives a few common slips (see [section 16](#16-what-the-importer-fixes-and-what-stops-it)), but writing it correctly avoids surprises. | Rule | Right | Wrong | |---|---|---| | Text in **double** quotes | `"name": "Joint checking"` | `'name': 'Joint checking'` | | Field names in double quotes | `"value": 24000` | `value: 24000` | | Numbers bare, no `$`, no commas | `"value": 103400` | `"value": "$103,400"` | | Rates and shares as **fractions** | `"income": 0.22` (22%) | `"income": 22` | | `true`, `false`, `null` bare and lowercase | `"liquid": true` | `"liquid": "yes"`, `True` | | Commas **between** items, not after the last | `[1, 2, 3]` | `[1, 2, 3,]` | | No comments | | `// my note` | | Dates as `YYYY-MM-DD` | `"asOf": "2026-10-01"` | `"asOf": "10/1/26"` | | Save as UTF-8 plain text, `.json` extension | `my-case.json` | `my-case.json.txt`, a Word document | **Negative numbers** are allowed where they make sense: debts (`"value": -8500`) and assets that lose value (`"growth": -0.12`). **Order doesn't matter**, neither of fields inside an object nor of assets in the list. --- ## 4. The whole file at a glance ``` { "schema": "settlement-sandbox/1" optional, recommended "id": "any-text" optional "name": "Smith" optional "asOf": "2026-10-01" optional "marriedOn": "2009-05-16" optional "notes": "..." optional "parties": [ party, party ] optional (exactly two) "settings": { ... } optional "assets": [ asset, asset, ... ] required (can be empty) "scenarios": [ scenario, ... ] optional "activeScenario": "scenario-id" optional "revisions": [ ... ] written by the app } party { "id": "A" | "B", "name": "...", "tax": { "income": 0.22, "gains": 0.20, "withdraw": 0.18, "borrow": 0.07 } } asset { "id": "...", "name": "...", "kind": "...", "group": "...", "value": 0, "ref": 0, "note": "...", "source": "...", "q": { qualities } } scenario { "id": "...", "name": "...", "notes": "...", "alloc": { "asset-id": allocation, ... }, "transfers": [ transfer, ... ], "costs": [ cost, ... ], "terms": { "marketAdjust": true | false | null } } allocation "A" | "B" | "split" | "out" | 0.6 | { "in": true, "a": 0.6 } transfer { "label": "...", "from": "A" | "B", "amount": 0, "months": 0, "trigger": "date" | "sale", "deadline": 60, "rate": 0, "secured": false, "insured": false, "funding": "cash" | "borrowed" | "retirement" | "other" } cost { "label": "...", "amount": 0, "paidBy": "A" | "B" | "split", "funding": "cash" | "other" } ``` --- ## 5. Top-level fields | Field | Type | Required | Default | Meaning | |---|---|---|---|---| | `schema` | text | no | `"settlement-sandbox/1"` | Format version. If present, must start with `settlement-sandbox/`. | | `id` | text | no | generated | Any identifier for the case. | | `name` | text | no | `"Untitled case"` | Shown in the top bar, the report and the MOU. Often the family name. | | `asOf` | date `YYYY-MM-DD` | no | today | The date the values are as of. Printed on the report and the MOU. It's also the **valuation date** the market-change terms refer to. | | `marriedOn` | date `YYYY-MM-DD` or `null` | no | `null` | Date of marriage. Used only to note divorced-spouse Social Security after 10 years. | | `notes` | text | no | `""` | Notes about the case. Kept private unless you choose to include notes when sharing or exporting. | | `parties` | list of 2 | no | Party A, Party B | See [Parties](#6-parties). | | `settings` | object | no | see below | See [Settings](#7-settings). | | `assets` | list | **yes** | | See [Assets](#8-assets). An empty list `[]` is allowed. | | `scenarios` | list | no | one, as titled | See [Scenarios](#11-scenarios). | | `activeScenario` | text | no | first scenario | `id` of the scenario shown when the file opens. | | `revisions` | list | no | `[]` | Frozen snapshots the app saves. Leave it out when writing by hand. See [Revisions](#14-revisions). | | `updatedAt` | text | no | | Written by the app. Leave it out. | --- ## 6. Parties A case has exactly **two** parties. Their ids are always `"A"` and `"B"`; everything else in the file (titles, allocations, payments) refers to them by those letters. Which person is A doesn't matter, but stay consistent. ```json { "parties": [ { "id": "A", "name": "Alex", "tax": { "income": 0.24, "gains": 0.2, "withdraw": 0.18 } }, { "id": "B", "name": "Sam", "tax": { "income": 0.22, "gains": 0.15, "withdraw": 0.15, "borrow": 0.068 } } ], "assets": [] } ``` | Field | Type | Default | Meaning | |---|---|---|---| | `id` | `"A"` or `"B"` | by position | Which party this is. | | `name` | text | `"Party A"` / `"Party B"` | Shown everywhere. | | `tax.income` | fraction 0–1 | `0.22` | Income tax rate (federal + state) on interest received from later payments, and on retirement withdrawals unless `withdraw` is set. | | `tax.withdraw` | fraction or `null` | `null` (same as `income`) | The rate expected **when pre-tax retirement money comes out**, usually in retirement, often lower than today's. This rate drives most of the after-tax view, so set it deliberately. | | `tax.gains` | fraction 0–1 | `0.20` | Capital gains rate, federal + state, for assets sold at a gain. | | `tax.borrow` | fraction or `null` | `null` | What this person would pay to borrow, e.g. the rate on a buyout loan. When set, a deferred payment is also valued against it, which shows what the delay is worth to the payer. | Rates are fractions: 22% is `0.22`. The importer converts `22` or `"22%"` to `0.22` and tells you it did. --- ## 7. Settings ```json { "settings": { "target": 0.5, "discount": 0.045, "warn": 5000, "bad": 20000, "cashFloor": 40000, "horizon": 5, "refLabel": "Disclosure", "measure": "after-tax" }, "assets": [] } ``` | Field | Type | Default | Meaning | |---|---|---|---| | `target` | fraction 0–1 | `0.5` | Party A's target share of the total. `0.5` is an equal split; `0.55` means A should get 55%. | | `discount` | fraction 0–1 | `0.045` | Yearly rate used to value a payment made later in today's dollars. Roughly what a safe investment earns, or what the payer would pay to borrow. | | `warn` | dollars | `5000` | A gap from the target larger than this raises a warning. | | `bad` | dollars | `20000` | A gap larger than this is flagged as serious. | | `cashFloor` | dollars | `40000` | Cash each party should have after the split. Less raises a warning. | | `horizon` | years | `5` | How far ahead to compare what each side's share grows into, using each asset's `growth`. `0` turns the comparison off. | | `refLabel` | text | `"Reported"` | Name for the reference values (see `ref` under [Assets](#8-assets)), e.g. `"FIF"` or `"Disclosure"`. Shown on cards, in the asset table and on the MOU. | | `measure` | `"after-tax"` or `"face"` | `"after-tax"` | The main measure. The board shows it, **Balance it** aims for it, and its bar comes first. Both measures are always shown. | --- ## 8. Assets Every asset, account, debt and item of property is one entry in `assets`. Include things that won't be divided too (separate property, children's accounts) if you want them listed; mark them with `separate` and they stay out of the split. ```json { "id": "alex_401k", "name": "Alex 401(k)", "kind": "pretax", "value": 412000, "ref": 412000, "note": "Divides by QDRO.", "source": "Statement 9/30", "q": { "titled": "A" } } ``` | Field | Type | Required | Default | Meaning | |---|---|---|---|---| | `id` | text | no | made from the name | Unique within the file. **Scenarios refer to assets by id**, so give one whenever you write scenarios. Keep it short and stable: letters, digits, `_` or `-` (e.g. `alex_401k`). | | `name` | text | **yes** | | What people see. | | `kind` | one of the [kinds](#10-kinds-shortcuts-that-fill-in-qualities) | no | `"custom"` | A shortcut that fills in typical qualities. | | `group` | text | no | from `kind` | The asset's **type** in the money-by-type summary: `"liquid"`, `"realestate"`, `"retirement"`, `"vehicles"`, `"other"`, `"debts"`, or any name of your own. See [Types](#types-for-the-money-by-type-summary). | | `value` | dollars | **yes** | | Current value. **Debts are negative.** Use `0` if unknown and set `"estimate": true`. | | `ref` | dollars or `null` | no | `null` | A reference value to compare against, typically the figure on the financial disclosure. When `value` changes later, the sandbox shows both. | | `note` | text | no | `""` | Anything worth remembering. Private unless you include notes when sharing or exporting. | | `source` | text | no | `""` | Where the value came from, e.g. `"Statement 9/30"`, `"Appraisal 3/2026"`. | | `q` | object | no | from `kind` | The asset's [qualities](#9-qualities-how-an-asset-is-treated). Only list the ones that differ from its kind. | | `history` | list | no | | Written by the app as values change: `[{ "at": "2026-10-01", "value": 412000 }]`. Leave it out when writing by hand. | | `updatedAt` | text | no | | Written by the app. | **What counts as one asset?** One account, one property, one vehicle, one debt. Split a single account into two entries only if its parts are treated differently (for example a 401(k) with a separate Roth portion). **Values are the whole asset**, not anyone's half. Who gets how much is decided in each scenario's `alloc`. ### Types for the money-by-type summary The report and the MOU show how much of each type of property each party ends up with. Every asset has one type. Its `kind` picks a default, and `group` overrides it. Retirement is shown as two rows by its `tax` quality: **Already-taxed retirement** (`"none"`, e.g. a Roth IRA) and **Untaxed retirement** (`"income"`: taxed when withdrawn). | `group` | Shown as | Default for these kinds | |---|---|---| | `liquid` | Liquid (cash and investments) | `cash`, `brokerage`, `metal` | | `realestate` | Real estate | `home` | | `retirement` | Retirement | `pretax`, `ira`, `roth`, `pension` | | `vehicles` | Vehicles | `vehicle` | | `other` | Other property | `personal`, `business`, `receivable`, `custom` | | `debts` | Debts | `debt` | Any other text makes a type of its own with that name, listed after Vehicles and before Other property. For example, `"group": "Business"` or `"group": "Collectibles"`: ```json { "id": "shop", "name": "Pottery studio LLC", "kind": "business", "group": "Business", "value": 60000 } ``` The type is **descriptive only**. It doesn't change any value or flag. To show a mortgage against the house rather than under Debts, give the mortgage `"group": "realestate"`. Real estate is then shown net of what's owed. --- ## 9. Qualities: how an asset is treated Qualities are what make a dollar of one asset worth more or less than a dollar of another. The sandbox never looks at an asset's name or kind to decide anything; it only looks at these qualities. Put them in the asset's `q` object. Anything you leave out comes from the asset's `kind`, and then from the defaults below. | Quality | Type | Default | What it does | |---|---|---|---| | `tax` | `"none"`, `"income"`, `"gain"` | `"none"` | How tax applies when the asset becomes cash. **`"none"`**: no tax (cash, Roth, most cars). **`"income"`**: the whole amount is taxed as income when withdrawn (401(k), traditional IRA, most pensions). **`"gain"`**: the gain over `basis` is taxed when sold (home, brokerage, business, metals). | | `rate` | fraction or `null` | `null` | Overrides the owner's tax rate for this asset only. Example: `0.33` for collectibles (28% federal cap plus state). `null` means use the owner's `tax.income` or `tax.gains` from [Parties](#6-parties). | | `basis` | dollars or `null` | `null` | Cost basis for `"gain"` assets: what was paid plus improvements. `null` means unknown, which is treated as $0 (and flagged), so tax is overstated until you fill it in. | | `exclusion` | dollars | `0` | Gain **each owner** can exclude from tax when selling. Use `250000` for a primary home (the single-filer exclusion). It applies per owner, so a home split 50/50 gets up to $250,000 excluded on each half. | | `cost` | fraction 0–1 | `0` | Cost to turn the asset into cash: selling costs, commissions, a dealer's spread. `0.06` is 6%. | | `realize` | `true`/`false` | `false` | Whether the asset is expected to be **sold or cashed out**. Only then do `cost` and gain tax count in the after-tax view. Leave `false` for things people keep (a home someone will live in, a car). `"income"` assets are always treated as eventually withdrawn, whatever this says. | | `liquid` | `true`/`false` | `false` | Usable as cash now without penalty or sale. Drives the "cash after the split" figures and the cash-cushion warning. | | `penalty` | fraction 0–1 | `0` | Extra penalty for early access, e.g. `0.10` for retirement money taken before 59½. For information only: it's mentioned in warnings, not subtracted. | | `divisible` | `true`/`false` | `true` | Whether the asset can be split by percentage. Set `false` for a car or a piano; the sandbox then only lets it go to one side (or flags it if split). | | `growth` | fraction −1 to 1 | `0` | Expected change in value per year. `0.03` for a home appreciating 3%, `-0.12` for a car losing 12%. Used to show who keeps the growth while a later payment is outstanding. | | `estimate` | `true`/`false` | `false` | The value isn't confirmed. Shown as "estimate", and the flags show how much the balance would move if it were 10% higher. | | `titled` | `"A"`, `"B"`, `"joint"` | `"joint"` | Whose name the asset is in. Used for the default "as titled" division: A's go to A, B's to B, joint split 50/50. It doesn't change any value. | | `separate` | `"A"`, `"B"`, `"other"`, `null` | `null` | Separate (non-marital) property of A, of B, or of someone else such as a child (`"other"`). `null` means marital. Separate items start **outside** the split. If you include one anyway, it's flagged. | | `realizeMonths` | months ≥ 0 | `0` | For assets with `realize: true`: when the sale or cash-out is expected. `0` means now. Otherwise the sale is figured at the expected future price (value grown by `growth`), with selling costs and tax on that price, then brought back to today's dollars at `settings.discount`. Growth can use up an exclusion, which this shows. | | `volatile` | `true`/`false` | `false` | The value rises and falls with the markets (investment and retirement accounts, metals). When such an asset is split, the scenario has to say whether each share follows the markets until the account is actually divided; see [Terms](#terms). | | `divideBy` | `"qdro"`, `"ira"`, `"retitle"`, `"sale"`, `null` | `null` | How the asset changes hands. **`"qdro"`**: a court order to an employer plan or pension (QDRO, or DRO for government plans). **`"ira"`**: a direct transfer from one IRA to the other spouse's IRA under the decree. **`"retitle"`**: a deed, title or account ownership change. **`"sale"`**: sold and the proceeds divided. Used for flags and the wording of the MOU. | | `splitWhenPaid` | `true`/`false` | `false` | For pensions: divide each payment when it's paid, instead of putting a value on the pension today. No one has to agree on its present value; both share how it turns out. Flags remind you to settle survivor benefits. | ### Quick guide: which tax? | The asset is… | `tax` | Also set | |---|---|---| | Cash, checking, savings, money market, CDs | `"none"` | `liquid: true` | | 401(k), 403(b), 457 (employer plans) | `"income"` | kind `pretax`: `penalty: 0.10`, `divideBy: "qdro"`, `volatile: true` | | Traditional or rollover IRA, SEP, SIMPLE | `"income"` | kind `ira`: `penalty: 0.10`, `divideBy: "ira"`, `volatile: true` | | Roth IRA | `"none"` | kind `roth`: `penalty: 0.10`, `divideBy: "ira"` | | Roth 401(k) | `"none"` | `divideBy: "qdro"`, `volatile: true` | | Pension | `"income"` (or `"none"` if you've decided its value is after-tax) | `estimate: true`, `divideBy: "qdro"`, and `splitWhenPaid` if payments will be divided when paid | | HSA | `"none"` if it'll be used for medical costs, otherwise `"income"` | | | Home or other real estate | `"gain"` | `basis`, `cost: 0.06`, `exclusion` for a primary home, `realize` and `realizeMonths` if it will be sold | | Brokerage account, stocks, funds, crypto | `"gain"` | `basis`, `realize: true`, `liquid: true` | | Gold, coins, art, collectibles | `"gain"` | `rate: 0.33`, `cost`, `basis` | | Car, furniture, personal items | `"none"` | `divisible: false` | | Business | `"gain"` | `basis`, `estimate: true` | | Debt (mortgage, car loan, card balance carried) | `"none"` | negative `value` | --- ## 10. Kinds: shortcuts that fill in qualities A `kind` is only a starting point. It fills in qualities, and anything you put in `q` wins. These are all the kinds and exactly what each one sets. Qualities not listed stay at the defaults in the table above. | `kind` | Shown as | Qualities it sets | |---|---|---| | `cash` | Cash or bank account | `liquid: true`, `divideBy: "retitle"` | | `brokerage` | Taxable investments | `tax: "gain"`, `realize: true`, `liquid: true`, `growth: 0.05`, `volatile: true`, `divideBy: "retitle"` | | `pretax` | Employer retirement plan (401k, 403b, 457) | `tax: "income"`, `penalty: 0.1`, `growth: 0.05`, `volatile: true`, `divideBy: "qdro"` | | `ira` | Traditional or rollover IRA | `tax: "income"`, `penalty: 0.1`, `growth: 0.05`, `volatile: true`, `divideBy: "ira"` | | `roth` | Roth IRA | `penalty: 0.1`, `growth: 0.05`, `volatile: true`, `divideBy: "ira"` | | `pension` | Pension | `tax: "income"`, `estimate: true`, `divideBy: "qdro"` | | `home` | Home or real estate | `tax: "gain"`, `exclusion: 250000`, `cost: 0.06`, `growth: 0.03`, `divideBy: "retitle"` | | `vehicle` | Vehicle | `divisible: false`, `growth: -0.12`, `estimate: true`, `divideBy: "retitle"` | | `metal` | Precious metals | `tax: "gain"`, `rate: 0.33`, `cost: 0.03`, `realize: true`, `liquid: true`, `estimate: true`, `volatile: true`, `divideBy: "retitle"` | | `personal` | Personal property | `divisible: false`, `estimate: true`, `divideBy: "retitle"` | | `business` | Business interest | `tax: "gain"`, `estimate: true`, `divideBy: "retitle"` | | `receivable` | Money owed to you | (defaults only) | | `debt` | Debt | (defaults only); enter the value as a negative number | | `custom` | Something else | (defaults only) | The `growth` defaults are placeholders for comparison only. They don't change today's balance, except for assets sold later (`realizeMonths`). Set your own. Note that `home` does **not** set `realize`. A home someone keeps and lives in counts at full value. Set `"realize": true` if the plan is to sell it, so selling costs and any tax count. --- ## 11. Scenarios A scenario is one way of dividing everything: who gets each asset, and any payments between the two of you. A file can hold as many scenarios as you like. Each has its own division but **shares the same assets and values**, so changing a value updates every scenario. ```json { "id": "keep_house", "name": "Sam keeps the house", "notes": "Sam keeps the house and pays Alex in two parts.", "alloc": { "home": "B", "joint_checking": "split", "alex_401k": "A" }, "transfers": [ { "label": "Buyout at signing", "from": "B", "amount": 130000, "funding": "borrowed" } ] } ``` | Field | Type | Default | Meaning | |---|---|---|---| | `id` | text | generated | Unique. Used by `activeScenario`. | | `name` | text | `"Scenario"` | Shown in the scenario picker, summary and MOU. | | `notes` | text | `""` | Shown in the report. Included in the MOU and in share links only if you choose. | | `alloc` | object | everything as titled | [Who gets what](#12-who-gets-what-alloc). | | `transfers` | list | `[]` | [Payments between the parties](#13-payments-between-the-parties-transfers). | | `costs` | list | `[]` | [Costs paid to others](#costs-paid-to-others). | | `terms` | object | `{ "marketAdjust": null }` | [Terms](#terms) that apply to the whole division. | ### Terms ```json { "name": "With terms", "terms": { "marketAdjust": true } } ``` | Field | Type | Default | Meaning | |---|---|---|---| | `terms.marketAdjust` | `true`, `false` or `null` | `null` | For split accounts whose value moves with the markets (`volatile: true`). **`true`**: each share is adjusted for investment gains and losses from the valuation date (`asOf`) until the account is actually divided. **`false`**: each share is a fixed dollar amount as of `asOf`. **`null`**: not decided yet, which is flagged. The MOU states the choice. Plans often take months to divide an account, so this can matter a lot. | --- ## 12. Who gets what: `alloc` `alloc` maps each asset's **id** to where it goes. You can write each entry in a short form or the full form; the app always saves the full form. | You write | Means | Saved as | |---|---|---| | `"A"` | All to party A | `{ "in": true, "a": 1 }` | | `"B"` | All to party B | `{ "in": true, "a": 0 }` | | `"split"` | Half each | `{ "in": true, "a": 0.5 }` | | `0.62` | A gets 62%, B gets 38% | `{ "in": true, "a": 0.62 }` | | `"out"` | Not part of this division | `{ "in": false, "a": … }` | | `{ "in": true, "a": 0.62 }` | Full form | same | - **`a` is always party A's share**, as a fraction from 0 to 1. Party B gets `1 − a`. - **`in: false`** leaves the asset out of this scenario entirely. Its value isn't counted for either side. - **No `alloc` at all, or an empty one**, divides everything as titled: A's assets to A, B's to B, joint ones split 50/50, separate property left out. - **Once you list any asset, list them all.** An asset missing from a non-empty `alloc` is left **out** of that scenario, and the importer warns you. Write `"out"` to make leaving something out explicit. - **Keys should be asset ids.** If a key matches an asset's **name** instead, the importer uses that asset and tells you. - **Indivisible assets** (`divisible: false`) should be `"A"` or `"B"`. Splitting one is allowed but flagged. Example with every form: ```json { "name": "Mixed forms", "alloc": { "home": "B", "joint_checking": "split", "alex_401k": 0.62, "sam_ira": { "in": true, "a": 0 }, "piano": "out" } } ``` --- ## 13. Payments between the parties: `transfers` Payments even out a division: a buyout of the house, an equalizing payment, a balance paid when something sells. ```json { "name": "Two-part buyout", "transfers": [ { "label": "Buyout at signing", "from": "B", "amount": 130000, "months": 0, "funding": "borrowed" }, { "label": "Buyout balance", "from": "B", "amount": 90000, "months": 36, "rate": 0.04, "secured": true, "insured": true, "funding": "borrowed" }, { "label": "Balance due when the house sells", "from": "B", "amount": 40000, "trigger": "sale", "months": 24, "deadline": 60, "secured": true } ] } ``` | Field | Type | Required | Default | Meaning | |---|---|---|---|---| | `label` | text | no | `"Payment"` | Shown everywhere, including the MOU. | | `from` | `"A"` or `"B"` | **yes** | | Who pays. The other party receives. | | `amount` | dollars ≥ 0 | **yes** | | How much. Always positive; to reverse the direction, change `from`. | | `trigger` | `"date"` or `"sale"` | no | `"date"` | **`"date"`**: due `months` after signing. **`"sale"`**: due when something is sold; `months` is then only the expected timing. | | `months` | number ≥ 0 | no | `0` | When it's paid (or expected to be, for `"sale"`). `0` means at signing. | | `deadline` | months or `null` | no | `null` | For `"sale"` payments: the latest month it must be paid by, even if nothing has sold. Without one the payment can stay open indefinitely, which is flagged. | | `rate` | fraction 0–1 | no | `0` | Yearly interest on a later payment, compounded. `0` means interest-free. | | `secured` | `true`/`false` | no | `false` | Whether a later payment is secured, e.g. by a recorded lien or mortgage. Unsecured later payments are flagged. | | `insured` | `true`/`false` | no | `false` | Whether life insurance on the payer covers the unpaid amount. | | `funding` | `"cash"`, `"borrowed"`, `"retirement"`, `"other"` | no | `"cash"` | Where the payer gets the money. **`"cash"`** comes out of the payer's liquid assets, and is flagged if they don't have enough. **`"borrowed"`** is a new loan or sale proceeds. **`"retirement"`** is a withdrawal from retirement money; the flags show the tax and whether the 10% early-withdrawal penalty applies (it doesn't for money the payer receives from the other's employer plan by court order). **`"other"`** is anything else. | | `id` | text | no | generated | | **Six years.** Transfers between spouses are tax-free when they happen within a year of the divorce, or within 6 years if the divorce decree requires them. Payments set later than 72 months, or due on a sale with no `deadline`, are flagged. **Why `months` and `rate` matter:** a dollar paid in three years is worth less than a dollar today. In the after-tax view, later payments are counted at today's value using `settings.discount`. A payment with a `rate` below the discount rate is flagged as a partly interest-free loan, along with how much value it shifts. ### Costs paid to others Money that leaves the two of you to carry out the division: preparing each QDRO, closing costs on a buyout loan, appraisals, deed and recording fees. A cost comes off the payer's share in both views. ```json { "name": "With costs", "costs": [ { "label": "QDRO preparation", "amount": 900, "paidBy": "split", "funding": "cash" }, { "label": "Closing costs on the buyout loan", "amount": 4200, "paidBy": "B", "funding": "other" } ] } ``` | Field | Type | Required | Default | Meaning | |---|---|---|---|---| | `label` | text | no | `"Cost"` | Shown in the report and the MOU. | | `amount` | dollars ≥ 0 | **yes** | | | | `paidBy` | `"A"`, `"B"`, `"split"` | no | `"split"` | Who pays. `"split"` is half each. | | `funding` | `"cash"` or `"other"` | no | `"cash"` | `"cash"` reduces the payer's cash after the split; `"other"` (financed, or paid from something else) doesn't. | | `id` | text | no | generated | | --- ## 14. Revisions When you click **Save revision**, share a link, or export an MOU, the app stores a frozen copy of that scenario and of all asset values in `revisions`. That way you can see later exactly what a scenario said on a given day, even after values change. **Don't write revisions by hand.** If a file you write contains a `revisions` list, entries missing their data are dropped with a warning. Each revision looks like this, for reference: ``` { "id": "...", "label": "Before mediation", "kind": "manual" | "share" | "mou" | "backup", "at": "2026-10-15T23:52:00.000Z", "scenarioId": "...", "scenarioName": "...", "asOf": "2026-10-15", "link": "https://… (share revisions only)", "data": { "parties": [...], "settings": {...}, "assets": [...], "scenario": {...} } } ``` --- ## 15. How the numbers are worked out Two balances are shown for every scenario. **Face value** counts every dollar the same, like the financial disclosure. Each party's total is their share of each asset's `value`, plus or minus payments at their full `amount`. **After tax** estimates what each party could actually spend, in today's dollars. For party P holding share *s* of an asset with value *v*: | Asset | After-tax value to P | |---|---| | Debt (negative value) | *v·s* (counted at face) | | `tax: "income"` | *v·s* × (1 − `cost`) × (1 − rate), where rate is `q.rate`, else P's `tax.withdraw`, else P's `tax.income` | | `tax: "gain"` and `realize: true` | price = *v·s* × (1 + `growth`)^(`realizeMonths`/12); proceeds = price × (1 − `cost`); gain = proceeds − `basis`·*s* (not below 0); taxable = gain − `exclusion` (not below 0); value = (proceeds − taxable × rate) ÷ (1 + `discount`)^(`realizeMonths`/12), where rate is `q.rate` or P's `tax.gains` | | `realize: true`, any other tax | price × (1 − `cost`), discounted the same way | | Anything else | *v·s* | **Payments.** A payment of amount *A* due in *m* months at interest *i*, with discount rate *d* and *y* = *m*/12: - amount due: FV = *A* × (1 + *i*)^*y* - payer: − FV ÷ (1 + *d*)^*y* - receiver: (*A* + (FV − *A*) × (1 − receiver's `tax.income`)) ÷ (1 + *d*)^*y* - at signing (*m* = 0): simply −*A* and +*A* **Costs** reduce the payer's total by their `amount` (half each for `"split"`) in both views. **Money by type** shows what each party ends up with by kind of money, at face value and after tax. Only assets in the split are counted, and the rows add up exactly to the totals above: | Row | What's in it | |---|---| | Liquid (cash and investments) | Assets of type `liquid`, plus payments received at signing, minus payments made at signing with `"funding": "cash"` and costs with `"funding": "cash"` | | Already-taxed retirement | `retirement` assets whose `tax` isn't `"income"` | | Untaxed retirement | `retirement` assets with `"tax": "income"`, minus payments at signing with `"funding": "retirement"` | | Delayed payments | Payments made after signing (`months` above 0): + to receive, − to pay; after tax, at today's value. No total, since they move between the two | | Real estate, Vehicles, your own types, Other property, Debts | Assets of that [type](#types-for-the-money-by-type-summary) | | Borrowed to pay / Paid from other assets | Payments at signing with `"funding": "borrowed"` / `"other"` | | Costs (financed) | Costs not paid from cash | Rows that are zero for both parties are left out. **The gap** is party A's total minus `target` × the combined total. Positive means A is ahead, negative means B is. It's shown for both lenses, colored by `warn` and `bad`. **Cash after the split** (used for the low-cash flag) is each party's share of `liquid` assets (after tax), plus payments received at signing, minus payments made at signing with `funding: "cash"`, minus costs with `funding: "cash"`. **Flags** are raised automatically when: - the gap exceeds `warn` or `bad`, on either lens - face value and after tax disagree by more than `warn`; the assets responsible are listed - a later payment's `rate` is below `discount` (an interest-free or cheap loan), also valued at the payer's `borrow` rate when set - a payment due on sale has no `deadline` - a payment falls after 72 months, outside the 6-year window for tax-free transfers - a later payment isn't `secured`, or isn't `insured` - a payment is funded from retirement money: the tax, and whether the 10% penalty applies - the payer keeps assets with positive `growth` while a payment is outstanding - a `"gain"` asset has no `basis` - a `"gain"` asset that will be sold owes tax, or has room left under its exclusion - a `"gain"` asset that won't be sold carries an untaxed gain to whoever keeps it - an indivisible asset is split - an asset divided by `"qdro"` changes hands (an order is needed; add its cost), or an `"ira"` asset does (it must be a direct transfer) - a `volatile` asset is split and `terms.marketAdjust` is `null` - a pension is traded at an estimated value instead of `splitWhenPaid`, or is split when paid (survivor benefits) - a home with an exclusion is co-owned until a later sale (each owner's exclusion, and the $500,000 joint exclusion while married) - expected `growth` makes the two sides drift apart by more than `warn` over `horizon` years - retirement tax rates move the after-tax balance (shown for 5 points higher for each person), or both are still the 22% default - the marriage lasted 10 years or more (`marriedOn`): divorced-spouse Social Security - separate property is included, or marital property is left out - a cash-funded payment exceeds the payer's cash - a party's cash falls below `cashFloor` - any `estimate` values exist, with how far each would move the balance These are planning estimates, not tax or legal advice. --- ## 16. What the importer fixes, and what stops it The sandbox checks every file when you open it. ### Fixed automatically, with a warning The case opens, and a list shows what was changed. Check each one. | You wrote | Read as | |---|---| | Comments (`// …`) or trailing commas | Ignored | | `"$103,400"`, `"103400"`, `"85k"`, `"1.2m"` | `103400`, `103400`, `85000`, `1200000` | | A rate or share above 1 and up to 100, e.g. `22` or `62` | A percentage: `0.22`, `0.62` | | `"22%"` | `0.22` | | `"yes"`, `"no"`, `"true"`, `"false"` (in quotes) | `true` / `false` | | A party id written as `"a"` or `"b"` | `"A"` / `"B"` | | A party's **name** where `"A"`/`"B"` belongs (in `from`, `titled`, `separate`, `alloc`) | That party's id | | `"titled": "J"` or `"Joint"` | `"joint"` | | `"separate": "none"` / `"marital"` / `""` | `null` | | `"separate": "kids"` / `"child"` | `"other"` | | `"tax": "pre-tax"` / `"traditional"` / `"ordinary"` | `"income"` | | `"tax": "capital gains"` / `"taxable"` | `"gain"` | | `"tax": "roth"` / `"tax-free"` | `"none"` | | A misspelled field name close to a real one (`"vaule"`) | The real field (`"value"`) | | A misspelled `kind` close to a real one (`"vehical"`) | The real kind | | An unknown `kind` | `"custom"` | | A **positive** value on a `"debt"` | Made negative | | `"funding": "refinance"` / `"loan"` / `"savings"` / `"401k"` | `"borrowed"` / `"borrowed"` / `"cash"` / `"retirement"` | | `"divideBy": "QDRO"` / `"DRO"` / `"deed"` / `"sell"` / `"transfer"` | `"qdro"` / `"qdro"` / `"retitle"` / `"sale"` / `"ira"` | | `"trigger": "on sale"` / `"fixed"` | `"sale"` / `"date"` | | `"paidBy": "both"` / `"shared"` | `"split"` | | A date like `"Oct 1, 2026"` | `"2026-10-01"` | | `"qualities"` instead of `"q"` | `"q"` | | `"category"` instead of `"group"` | `"group"` | | `"group": "Real estate"`, `"Retirement"` (a type's label, any capitalization) | Its key: `"realestate"`, `"retirement"` (no warning) | | `"group": "cash"` / `"house"` / `"cars"` / `"liabilities"` | `"liquid"` / `"realestate"` / `"vehicles"` / `"debts"` | | A `group` close to a standard one (`"retirment"`) | Kept as its own type, with a warning suggesting the standard one | | An `alloc` key that is an asset's **name** | That asset's id | | An asset missing from a non-empty `alloc` | Left out of that scenario | | A whole file that's just a list of assets `[ … ]` | Wrapped in a new case | | A field the sandbox doesn't use (not close to a real one) | Kept in the file unchanged, so nothing is lost if a newer version wrote it | ### Stops the file from opening Nothing is loaded and nothing changes. The list shows where each problem is. | Problem | Fix | |---|---| | Not valid JSON (the message gives the line and column) | Look just before that spot for a missing comma, quote or bracket. | | The file is a list that isn't a list of assets | Wrap everything in `{ "assets": [ … ] }`. | | `schema` isn't `settlement-sandbox/…` | Fix it or remove it. | | More than two parties, a party id other than A/B, or both parties with the same id | Exactly two parties: `"A"` and `"B"`. | | Two assets, or two scenarios, with the same `id` | Make every id unique. | | An asset without a `value` | Add one; use `0` and `"estimate": true` if unknown. | | A value that isn't a number (`"lots"`) | Write a number. | | A `tax` that isn't `none`, `income` or `gain` (and isn't a recognized synonym) | Use one of the three. | | A `divideBy` or `trigger` that isn't one of its allowed values | See [Qualities](#9-qualities-how-an-asset-is-treated) and [transfers](#13-payments-between-the-parties-transfers). | | A rate or share above 100, or below 0 (growth: below −1) | Write it as a fraction. | | A `from` that isn't A, B, or a party's name | Use `"A"` or `"B"`. | | A negative payment `amount` | Make it positive and change `from` to reverse the direction. | | An `alloc` entry that isn't one of the allowed forms | See [section 12](#12-who-gets-what-alloc). | To check a file before opening it, you can validate it against [`case.schema.json`](case.schema.json) in any JSON Schema tool or editor (VS Code does this if the file has `"$schema": "https://settlement-sandbox.com/case.schema.json"`). A file that passes the schema opens with no warnings. The `$schema` field is allowed and ignored. --- ## 17. Recipes for common assets Copy, then change the id, name and numbers. Each recipe is a complete asset entry. **Checking, savings or money market** ```json { "id": "joint_checking", "name": "Joint checking", "kind": "cash", "value": 24000, "source": "Statement 9/30" } ``` **Account in one person's name, treated as joint** ```json { "id": "sam_checking", "name": "Sam checking", "kind": "cash", "value": 14600, "q": { "titled": "B" }, "note": "Treated as joint by agreement." } ``` Use `"split"` for it in `alloc`, or leave `alloc` out and change `titled` to `"joint"`. **401(k), 403(b) or 457** ```json { "id": "alex_401k", "name": "Alex 401(k)", "kind": "pretax", "value": 412000, "q": { "titled": "A" } } ``` **Traditional or rollover IRA** ```json { "id": "sam_ira", "name": "Sam rollover IRA", "kind": "ira", "value": 96000, "q": { "titled": "B" } } ``` **Roth IRA** ```json { "id": "sam_roth", "name": "Sam Roth IRA", "kind": "roth", "value": 58000, "q": { "titled": "B" } } ``` **Pension valued as a lump sum** ```json { "id": "sam_pension", "name": "Sam teacher pension", "kind": "pension", "value": 140000, "q": { "titled": "B" }, "note": "Present value; actuarial valuation pending." } ``` If you've decided the pension figure is already after tax, add `"tax": "none"` to `q`. **Pension divided payment by payment when paid** ```json { "id": "sam_pension", "name": "Sam teacher pension", "kind": "pension", "value": 140000, "q": { "titled": "B", "splitWhenPaid": true } } ``` Give it a share in `alloc` (e.g. `0.5`); the value only matters for the balance today. **Family home someone will keep** ```json { "id": "home", "name": "Family home", "kind": "home", "value": 640000, "q": { "basis": 410000 } } ``` **Family home that will be sold** ```json { "id": "home", "name": "Family home", "kind": "home", "value": 640000, "q": { "basis": 410000, "realize": true } } ``` **Family home that will be sold in about two years** ```json { "id": "home", "name": "Family home", "kind": "home", "value": 640000, "q": { "basis": 410000, "realize": true, "realizeMonths": 24 } } ``` `basis` is the purchase price plus improvements (a new roof, a remodel, a pool), not repairs. **Rental or second property** (no primary-home exclusion) ```json { "id": "rental", "name": "Rental condo", "kind": "home", "value": 300000, "q": { "basis": 180000, "exclusion": 0, "realize": true } } ``` **Mortgage on the home** (a separate debt entry, usually allocated with the home) ```json { "id": "mortgage", "name": "Mortgage", "kind": "debt", "value": -210000 } ``` **Brokerage account, stocks or crypto** ```json { "id": "brokerage", "name": "Joint brokerage", "kind": "brokerage", "value": 85000, "q": { "basis": 52000 } } ``` **Gold, coins or other collectibles** ```json { "id": "gold", "name": "Gold, 3 oz", "kind": "metal", "value": 12000, "q": { "basis": 5400 } } ``` **Car** ```json { "id": "suv", "name": "2021 SUV", "kind": "vehicle", "value": 22000, "q": { "titled": "A" }, "source": "KBB private party" } ``` **Car loan** ```json { "id": "car_loan", "name": "SUV loan", "kind": "debt", "value": -8500, "q": { "titled": "A" } } ``` **Credit card balance that is carried, not paid off monthly** ```json { "id": "visa", "name": "Visa balance", "kind": "debt", "value": -3200 } ``` **Small business or side business** ```json { "id": "biz", "name": "Sam's design studio", "kind": "business", "value": 40000, "q": { "titled": "B", "basis": 0 } } ``` **A bonus or other pay earned during the marriage but paid later** ```json { "id": "bonus", "name": "Year-end bonus (earned, not yet paid)", "kind": "receivable", "value": 6500, "q": { "tax": "income", "titled": "A", "estimate": true } } ``` **This year's tax refund or balance due on a joint return** ```json { "id": "tax_2026", "name": "2026 joint return: refund (+) or balance due (−)", "kind": "receivable", "value": 0, "q": { "estimate": true } } ``` **Money someone owes the couple** ```json { "id": "loan_to_brother", "name": "Loan to Alex's brother", "kind": "receivable", "value": 15000, "q": { "estimate": true } } ``` **Separate property** (stays out of the split) ```json { "id": "piano", "name": "Inherited piano", "kind": "personal", "value": 12000, "q": { "titled": "B", "separate": "B" } } ``` **A child's account** (listed, never divided) ```json { "id": "kid_529", "name": "529 college plan", "kind": "custom", "value": 30000, "q": { "separate": "other" } } ``` **Something whose value isn't known yet** ```json { "id": "coins", "name": "Coin collection", "kind": "personal", "value": 0, "q": { "estimate": true, "separate": "A" } } ``` **A proposal you want listed but not counted unless you include it** ```json { "id": "solar_credit", "name": "Solar credit (proposal)", "kind": "receivable", "value": 7800 } ``` Then write `"solar_credit": "out"` in each scenario's `alloc` until you want to test it. --- ## 18. A complete example [`examples/full-example.json`](examples/full-example.json) is the case behind **Try the example**: Alex, a software engineer, and Sam, who runs a bakery and used to teach. It uses nearly every field: two parties with their own tax rates, settings, 25 assets (a home with a home equity line, a rental with its mortgage, a business, unvested company stock, crypto, an HSA, a teacher pension split when paid, a boat to be sold, a timeshare worth half its listing, a loan to a relative, separate property of each spouse and a child's college account), value history, three scenarios (Sam keeps the house; sell the house; split everything in half), payments at signing, two years later and at a sale, costs, and a saved revision. It opens with no warnings. Copy it and replace the values. [`examples/minimal.json`](examples/minimal.json) is the [quick start](#1-quick-start) file. --- ## 19. Checklist before you open the file - [ ] The file is saved as plain text with a `.json` extension. - [ ] It starts with `{` and ends with `}`. - [ ] Exactly two parties, with ids `"A"` and `"B"`. - [ ] Every asset has a `name`, a `value`, and (if you write scenarios) a unique `id`. - [ ] Dollar amounts are plain numbers: no `$`, no commas, no quotes. - [ ] Debts are negative. - [ ] Rates and shares are fractions: `0.22`, not `22`. - [ ] `"gain"` assets have a `basis` if you know it. - [ ] Assets that will be sold have `"realize": true`. - [ ] Separate property and children's assets have `separate` set. - [ ] Each scenario's `alloc` lists every asset, or is left out entirely. - [ ] Every payment has `from` and `amount`; later payments have `months`. - [ ] Payments due on a sale have a `deadline`. - [ ] Each person's retirement tax rate (`tax.withdraw`) is set. - [ ] Split investment and retirement accounts have a `terms.marketAdjust` decision. Then open it. If anything's off, the sandbox will tell you exactly where. --- ## 20. Having an AI assistant write the file An AI assistant can turn statements, a financial disclosure or a spreadsheet into a case file. Give it this guide (or its address) along with your information, and a prompt like: > Using the Settlement Sandbox case file format described in CASE-FILE-FORMAT.md, write a case file for the information below. Use party "A" for [name] and "B" for [name]. Give every asset a short id. Use the closest `kind` for each asset and only add `q` qualities that differ from that kind. Debts are negative. Rates are fractions. Include cost basis where known. Leave out `scenarios` so everything starts as titled. Output only the JSON. > > [your assets, values, whose name each is in, and anything that's separate property] Then open the result in the sandbox and review any warnings it shows. Keep in mind what you share with an assistant: this is sensitive financial information. --- ## 21. Privacy - **The case file stays on your computer.** The sandbox reads it in your browser; it isn't uploaded anywhere. - The latest state is also kept in your browser's local storage, so a reload doesn't lose work. **File › Close case** clears it. - **Share links** carry a copy of the case inside the link itself, after the `#`. Browsers don't send that part to the server, so it isn't stored or logged there. Anyone holding the link can see what's in it, so share it like you would the file. Add a passphrase for extra protection. - Don't put real case files anywhere they'll be published along with the site.