Run several accounts or UMA sleeves against one shared gain budget per tax unit, reserving budget so no two runs spend the same allowance and screening cross-sleeve wash sales

One command on the Household and UMA coordination server, callable over MCP as coordinate_household. Every result carries the method it used, the rule pack it was pinned to, what is still missing and whether coverage was complete, for a licensed professional to review.

What it needs, and why

Every input is checked before anything is calculated. subject_ref, document_ref, as_of, prices, idempotency_key and cash_target are required; the rest refine the answer.

InputWhat it asks forWhy it mattersIf you omit it
subject_refAccount or household id you are entitled to readThe account or household the analysis is scoped to. Naming one is a request to read it, never a grant.required
document_refPath to the normalized holdings export to analyseAccount metadata, lots and basis come from the export, and nothing resolves until one has been read.required
as_ofAnalysis date, YYYY-MM-DDHolding periods and the 30-day wash-sale window are both measured from the analysis date.required
pricesPrice per share by security id, as decimal stringsA gain cannot be computed without a price per security, and no price is ever fetched or guessed here.required
idempotency_keyCaller-chosen keyRepeating the key returns the first run instead of running again, so a retry cannot spend a gain budget twice.required
cash_targetCash to raise across the householdThe objective is proceeds by a date. The gain budget is the constraint on reaching it, not the goal.required
withdrawal_accountAccount the cash is raised fromCash is raised from a named account, which decides whose lots are sold and whose budget is spent.optional
gain_budgetShared cap on realized gains per tax unitA cap on realized gains is a decision rather than a default, and supplying one requires saying how it is measured.optional
netting_basisWhether the gain budget is measured net of losses or on gains alone one of net_gains, gross_gainsGross and net readings of the same budget give different answers, so the server will not pick one for you.optional
periodTax period the budget applies to, e.g. "2026"A budget belongs to a tax period, and gains already realized in that period consume the allowance.optional
planned_purchasesPurchases already planned but not yet placedA purchase a manager intends but has not placed can still create a wash sale, and only the caller knows about it.optional

Requests it answers

  • “How do I share one gain budget across accounts?”
  • “How do UMA sleeves avoid washing each other's losses?”

An agent with these skills loaded picks the command from phrasing like that, asks for whatever input is missing, and reports the figures with the method that produced them.

Run it

TAXAGENT_TENANT_ID=... TAXAGENT_PRINCIPAL_ID=... TAXAGENT_ACCOUNTS=... scripts/mcp_server.sh --server household

The same command is exposed by taxagent-household, so Claude, Claude Code, Codex, Cursor and any other MCP client can call it directly. Analysis only. No tool in this server places orders, modifies custodian records or files returns. Two engines with different claims: optimize_household solves the whole household at once and, where the search exhausts, proves no other selection does better; coordinate_household serves accounts in a declared order, reserves budget as it goes, and is never optimal. Optimality is over the lots, prices and constraints supplied and for one objective, not a judgement about what the household should do. Budgets are allocated per tax unit: a household spanning several tax units gets several budgets and never one pooled allowance.

Scripted cases that exercise it

3 of the 71 console cases call this command on a real server over JSON-RPC and assert the outcome. Every one runs on every build, and all of them are listed on the case inventory.

CaseWhat it asksWhat it showsOutcome
household-coordinatedTwo accounts, one shared budgetBudget is reserved per tax unit as each account is served, so no two runs spend the same allowance.completed_with_limitations
household-uma-washOne sleeve would wash another sleeve's lossSame account, same taxpayer, two managers. Neither did anything wrong and the loss would still be disallowed, so it is caught first.completed_with_limitations
household-gapFalling short, and the ceiling it was measured againstSequential allocation depends on the order units are served, so the run reports an LP bound on what any allocation could have raised.INFEASIBLE_CONSTRAINTS

Limits it inherits from taxagent-household

  • Sequential allocation. Results depend on the declared unit order and are not a joint optimum.
  • Budgets are allocated per tax unit; a household spanning several tax units gets several budgets, never one.
  • Cross-unit wash-sale prevention covers accounts in scope and planned purchases supplied with the request. Unseen accounts and unreported manager intentions remain outside it.
  • Solved per tax unit and summed. That decomposition is exact, not an approximation: a gain budget belongs to one taxpayer, so no selection in one unit changes what is available in another and the objective is additive. A household spanning several tax units still gets several budgets and never one pooled allowance.
  • Wash-sale scope follows the taxpayer and is handled before the solve, by excluding lots whose loss would be disallowed. Accounts outside the snapshot remain unseen.
  • Optimality is over the supplied lots and constraints. It says nothing about which account should hold which exposure, which is an allocation decision this engine does not make.
  • Beyond 40 budget-consuming lots in a tax unit the search is not exhausted and the status degrades to feasible with a reported gap.

The server, its other 1 command and what it deliberately leaves alone are on the Household and UMA coordination page.