# MCP tools

> Every tool Truenote's MCP server offers, with its scopes and arguments, from the server's own definitions.

Canonical: https://usetruenote.com/docs/mcp-tools

Truenote's MCP server is `https://app.usetruenote.com/mcp` (Streamable HTTP; OAuth 2.1 discovered from the URL, or a personal access token as a bearer). Every tool is checked against the connection's scopes and exclusions and written to the audit log. Amounts arrive formatted ("$1,234.56"); write tools take plain dollars.

## Read tools

### `get_overview`: Financial overview

Where the household stands right now, in one call: net worth (cash, investments, debts), this month's spending and income (household and each business separately), the spending plan at a glance, bills due in the next two weeks, goals, the next quarterly estimated tax payment, bank connections that need attention, the checklist's next tasks, what they own and owe by kind (property, retirement, investments, cash; mortgage, loans, cards) with home equity, how much of the last twelve months' income was kept (saving), the emergency fund in months of the plan's spending, and the spotlight (the dated event the person's home page counts down to). Start here for any general question about the person's finances. Sections the connection isn't allowed to see are listed in notIncluded. Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: none (any connection).

### `list_accounts`: List accounts

Every connected account (checking, savings, cards, loans, brokerage) with its institution, latest balance, the entity it belongs to (household or a business), and for debts the rate, minimum payment and due date; plus manual accounts (a house, a car) and net worth totals. Balances are what the account is worth to the person: debts are negative. Use the ids with query_transactions or get_holdings. Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `accounts:read`.

Arguments:

- `type`: Only this account type
- `includeHidden`: Also closed accounts and archived manual ones, and accounts the person hid from totals if this connection is allowed to see hidden accounts

### `query_transactions`: Search transactions

Transactions newest first, filtered by date range, account, category, entity, merchant, amount, direction or text, 50 per page (pass nextCursor to continue). Each row has its id (for categorize_transactions), resolved category and entity, and flow: spending, income, transfer (between the person's own accounts) or excluded; ownerContribution marks a business's spending paid from a personal account (the owner put that money into the business). totals covers every match, not just the page: prefer spending_summary for "how much on X" questions. Without from/to it searches all history (about a year). Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `transactions:read`.

Arguments:

- `from`: First day, inclusive (YYYY-MM-DD)
- `to`: Last day, inclusive
- `accountId`: 
- `categoryId`: A category id from get_context (subcategories included), or none for uncategorized
- `entityId`: An entity id from get_context
- `merchant`: Merchant or description contains
- `text`: Description, merchant or note contains
- `minAmount`: At least this many dollars, either direction
- `maxAmount`: At most this many dollars
- `direction`: Money in or money out
- `pending`: 
- `ownerContribution`: true: only owner contributions, a business's spending paid from a personal account (with entityId, totals is what the owner put into that business)
- `limit`: Rows per page (default 50)
- `cursor`: nextCursor from the previous page

### `spending_summary`: Spending summary

Spending (net of refunds) over a date range grouped by category, merchant, entity or month, biggest first, with each group's share. By default it's the household's spending only (the personal entities, the same number get_overview's month reports); pass entityId for one business, or scope=all for the household and every business together. The result says which scope it used. Transfers between the person's own accounts, card payments and transactions they left out don't count; income isn't spending. Default range: this month so far. Use groupBy=month for trends. Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `transactions:read`.

Arguments:

- `from`: Default: the first of this month
- `to`: Default: today
- `groupBy`: 
- `scope`: household (default): personal spending only; all: household and businesses
- `entityId`: Only this entity (e.g. one business); overrides scope
- `categoryId`: Only this category and its subcategories
- `limit`: Groups to list (default 25)

### `get_recurring`: Recurring bills and income

Subscriptions, bills and paychecks the bank detected as recurring, with frequency, last and average amount (positive), last and next date, and flow: spending, income, or transfer (card payments and moves between the person's own accounts, like savings or a brokerage). monthlyOutflow and monthlyInflow count spending and income streams only (card payments would double-count the card's own subscriptions); monthlyTransfers is the rest. Covers the household and businesses alike. Use for "what are my subscriptions", "what's due" or "what do we spend every month". Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `transactions:read`.

Arguments:

- `direction`: inflow: income; outflow: bills
- `includeInactive`: Also streams that stopped

### `get_net_worth_history`: Net worth history

Net worth over time from daily balance snapshots: assets, liabilities and a breakdown by account type (cash, investments, credit, loans, other, manual assets). Interval month (default; last day of each month) or week over up to three years, or day over up to 93 days. Default range: the last year. heldBack means an account joined later and is held at its first value before that. Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `accounts:read`.

Arguments:

- `from`: 
- `to`: 
- `interval`: 

### `get_holdings`: Investment holdings

Positions in each investment account: symbol, quantity, price, value, cost basis and gain, with account and overall totals; optionally the 25 latest investment transactions (buys, sells, dividends; positive amounts are cash out of the account): for a date range, a kind or a symbol, query_investment_transactions. Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `investments:read`.

Arguments:

- `accountId`: 
- `includeTransactions`: 

### `query_investment_transactions`: Search investment transactions

Buys, sells, dividends, interest, deposits and fees in the investment accounts (about two years), newest first, filtered by date range, account, type (buy, sell, cash, fee, transfer, cancel), subtype (dividend, interest, deposit, sell…), symbol or text, 50 per page (pass nextCursor to continue). Money into the account is +$ (a sell's proceeds, a dividend), out is -$ (a buy). totals covers every match, not just the page: count, and the amount by type and subtype (this year's dividends: from Jan 1, subtype dividend). A sell carries its proceeds, not the gain: the bank doesn't send the cost of the shares sold (the year's 1099-B has it); get_holdings has the cost basis of what's still held. Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `investments:read`.

Arguments:

- `from`: First day, inclusive (YYYY-MM-DD)
- `to`: Last day, inclusive
- `accountId`: An investment account's id from list_accounts
- `type`: 
- `subtype`: dividend, interest, deposit, sell…
- `symbol`: Ticker, like VTI or BTC
- `text`: Description contains
- `limit`: Rows per page (default 50)
- `cursor`: nextCursor from the previous page

### `get_liabilities`: Debts

Credit cards, student loans, the mortgage and other loans: amount owed, APR, minimum payment, next due date, last payment and statement, original principal and maturity. Use for payoff or interest questions. Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `liabilities:read`.

### `get_context`: The household's context

What accounts can't say, in one call: the profile (household members, a baby's due date, state, filing status, risk tolerance, "about us"), entities (household and businesses), income sources with tax set-aside rates, goals, categories and rules (with ids for the write tools), pinned and recent notes, plans, and the open checklist (tasks with due dates). Read this before giving advice or writing anything. Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `context:read`.

### `get_plan`: Spending plan

The household's spending plan: regular monthly take-home (salaries, counting two paychecks a month for every-two-weeks pay; 1099 work after its tax set-aside; bonuses and the third paychecks two months a year bring are windfalls and don't count: extraYearly), split into groups with a target share (e.g. Expenses 45%, Wants 25%, Save & invest 30%). Each group has its lines (an amount per payment, how often, the monthly figure, the every-two-weeks transfer, an end date), what's planned, the target, and what's left over. Also: what's unplanned overall, the transfers to set up every two weeks, and what frees up when lines end. This is where the money is meant to go, not a budget of transactions; use it for "can we afford X", "how much is left for Y" or "what changes when the car is paid off". Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `context:read`.

### `plan_vs_actual`: Plan vs actual

A month of the household's money against the spending plan (get_plan), the way the person runs it: bills get paid, money gets set aside, the rest is everyday spending. bills: lines with match text (each line's kind is in get_plan), paid when a household payment out contains the text (lines sharing text each take the payment nearest their amount; status paid, due while the month is going, unpaid once it's over, not_this_month for a quarterly or yearly bill not paid this month); expected is what this month's bills ask. setAside: lines filling a bucket (its contributions), or naming an account (transfers in; for an investment account its own deposits and withdrawals; or payments out containing their match text); lines sharing a bucket or account split what arrived in plan order; via null means nothing to follow; status met, in_progress (this month) or short (a month that's over). everyday: every other spending line together (planned), against all other household spending whatever its category (actual), less bucket charges (chargedToBuckets: they count against the bucket, list_buckets) and tax payments (taxPayments: get_tax_projection); status over, ahead_of_pace (past the share of the month gone, monthGonePct, by more than a tenth) or on_track; categories breaks it down biggest first, a category a line names collecting its children, with each one's planned, trailing 3 full months' average (averageOf) and transaction count: the place to see what the plan is missing or which estimate is off (to change one, upsert_plan_line, after asking). left: the plan's monthly take-home (plannedIncome) less bills (paid, or still due), set-asides (made, or still to make this month), everyday spending and taxes: what the month leaves for goals and plans. income is what actually came in (bonuses too). Business spending is never included. month defaults to this one; use a past month for "how did September go". Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `context:read`, `transactions:read`.

Arguments:

- `month`: A month like 2026-10 (default: this month; never one that hasn't started)

### `get_tax_projection`: Yearly tax projection

The household's federal income tax for a year, projected from today, and whether they'll get money back or owe at filing time. Federal only: stateNote says whether the household's state has an income tax this leaves out (tell the person when it does). outcome says refund, owe or even and how much. statement is the math line by line, top to bottom: each W-2's wages (pay + bonus − 401(k) and other pre-tax), each business's profit (deposits found by payerMatch + money received elsewhere + what's still expected − expenses), total income, half of self-employment tax, AGI, the standard (or itemized) deduction, the qualified business income deduction, taxable income, income tax by bracket, the child tax credit, self-employment tax, the additional Medicare tax, then withholding (to date from a paystub + the paychecks after it × per paycheck + a bonus still to come), estimated payments found in the accounts (estimatedPayments lists each with its date and quarter; one paid in February to April may be last year's balance due rather than this year's estimate: ask, and record it with update_tax_settings priorYearPayments) and made elsewhere, and the result. breakEven gives, for each W-2 job with paychecks left after today, how much more (positive) to withhold per paycheck at that job alone to owe nothing (the person raises W-2 withholding instead of paying quarterly estimates; negative means that much could come off). Each breakEven entry closes the whole gap by itself: they are alternatives (this job OR that one), never to be added together or done at both; to share it across jobs, split the total owed yourself. safeHarbor and safeHarborSummary say whether an underpayment penalty is likely (90% of this year's tax, or 100%/110% of last year's, quarter by quarter; withholding counts as paid evenly through the year, estimated payments from their date). jobs and businesses are the inputs per source (ids for upsert_income_source); settings are the year's household figures (update_tax_settings). Read warnings (inputs that are missing: fix them with the person), assumptions and ignores (what this estimate leaves out) before relying on the number, and say it's an estimate. year defaults to this one. Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `context:read`, `transactions:read`.

Arguments:

- `year`: Tax year (default: this one)

### `list_buckets`: Savings buckets

Buckets: the person's own virtual split of a savings (or checking) account (automation reads deposits and transfers out only on savings), like Ally's savings buckets but kept by Truenote for any bank, since banks only report the account's total. For each account split into buckets: its balance, each bucket's balance (from Truenote's ledger), its optional target and date with progress and the monthly amount needed to make it, what the spending plan puts in a month (fundedBy: the plan lines), and the latest ledger entries. unassigned is the account's balance less what the buckets hold (where interest lands, like Ally's "Core Savings"); negative means the buckets claim more than the account holds, which the person should fix with a correction or a move. A bucket below zero had more taken out than it held: it holds nothing, the extra came out of unassigned, and shortfall is what such buckets are short together. owed is what buckets were charged for spending paid from another account (a vet bill on the card) that hasn't been moved back out of this account yet: until it is, unassigned is that much higher. Entries marked auto were made by bucket automation (a bucket rule, or a deposit split by what each bucket is due: its plan lines a month, caught up from its start, else its target's monthly amount by its date, never past its target; what's left goes to the overflow bucket, else stays unassigned). Buckets are for lumpy, irregular spending (a vet bill, a vacation, car repairs, Christmas) rather than a monthly budget line. Use for "how much is in the vacation bucket", "can we cover this from savings" or "what's not assigned". Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `accounts:read`, `context:read`.

Arguments:

- `accountId`: Only this account's buckets
- `includeArchived`: 
- `recentEntries`: Latest ledger entries per bucket (default 3)

### `list_review_items`: Review queue

What bucket automation wasn't sure enough to do on its own, waiting for the person (or you, on their behalf) to decide. kind: deposit (money came into a bucketed savings account from outside the person's accounts, more than its buckets are due: the proposal fills what each is due and puts the rest in the overflow bucket), charge (spending that looks like a bucket's, e.g. a vet visit → Pets: the proposal charges it, and rule is the bucket rule approving can save so the next one is automatic), withdrawal (money moved out of a bucketed savings account that doesn't exactly pay back what buckets are owed: paysBack lists the charges it would settle, owedCharges every unpaid charge it could settle instead; the rest comes out of Unassigned unless allocations name buckets; waiting true means it matches spending still in the queue, so decide that spending first and leave this one). Each item says why (reason). Certain things never show up here: money moved in from the person's own accounts is split by what each bucket is due automatically, bucket rules charge their matches, an exact pay-back settles itself, and interest stays in Unassigned. Ask the person before deciding anything you're unsure of. status resolved lists the latest decisions instead. Amounts are formatted strings in the account's currency; for transactions, money in is +$ and money out is -$.

Scopes: `accounts:read`, `transactions:read`, `context:read`.

Arguments:

- `status`: open (default) or resolved

### `list_bucket_rules`: Bucket rules

The person's bucket rules, in the order they apply (the first match wins): spending whose merchant or description contains the text (optionally on one account, in one category, within an amount range) is charged to the bucket automatically, back to the bucket's start and on every sync. chargedCount is how many entries each has made. Use before create_bucket_rule to avoid a duplicate.

Scopes: `accounts:read`, `context:read`.

### `list_tasks`: The checklist

The person's checklist: dated to-dos from planning ("Mail the 83(b) by Dec 5", "Backdoor Roths by Apr 15"), each with its kind (task, or event: a dated thing that happens, done once its day has passed), its state against today (overdue, due_soon within two weeks, upcoming, someday without a date, done), its sum (what it costs or brings), the goal or bucket it serves, and spotlight (the one the Overview counts down to). status: open (default), done or all. Open tasks come by due date; done ones newest first. get_context already lists the open ones.

Scopes: `context:read`.

Arguments:

- `status`: 

### `list_documents`: List documents

Documents the person uploaded: paystubs, W-2s, 1099s, 1098s, tax returns, benefits and plan papers (a bonus withholding policy), statements, receipts. Each has its kind, tax year, the date on it, whose it is (entity), the income source a paystub is for, the account (or manual account, like the mortgage) a statement is of, and readable: text (read_document returns its text), image (read_document returns the picture), scan or unreadable (nothing to read; ask the person). q finds documents by words in their name, notes or text ("bonus withholding", "escrow"), each with the line it matched. Filter by kind or taxYear. Newest first by the date on it. get_context lists the latest few; get_tax_projection and list_accounts point at the ones behind their figures.

Scopes: `documents:read`.

Arguments:

- `q`: Words to find
- `kind`: 
- `taxYear`: 

### `read_document`: Read a document

One document's contents (an id from list_documents): a PDF's text page by page ("[Page 1]" …; Social Security and account numbers masked), up to 20,000 characters a call (pass nextOffset as offset for more), or an image document as the image itself. guidance says what the document is good for: a paystub's year-to-date figures can become its income source's tax inputs (upsert_income_source), but only after showing the person the numbers and hearing yes. Never repeat a full Social Security or account number.

Scopes: `documents:read`.

Arguments:

- `id` (required): 
- `offset`: Where to continue (nextOffset)

## Write tools

### `update_tax_settings`: Set the tax year's household figures

Change the household's figures for a tax year that the projection (get_tax_projection) can't find in the accounts: priorYearTax (last year's total tax, Form 1040 line 24) and priorYearAgi (for the 100%/110% safe harbor), otherPayments (estimated payments made from accounts Truenote can't see, this year's), priorYearPayments (of the IRS payments get_tax_projection found this year, the dollars that paid last year's return, a balance due or an extension payment, so they don't count toward this year), otherIncome (this year's interest, ordinary dividends, short-term gains and other ordinary income; negative for a net capital loss, up to 3000), capitalGains (this year's long-term capital gains and qualified dividends, taxed at 0/15/20%; both count toward the 3.8% net investment income tax), itemizedDeductions (used only when larger than the standard deduction), qualifyingChildren (children under 17 at year end; null: counted from the profile's household, a baby due by December 31 included) and notes. Only the fields you pass change; null clears. Per-job and per-business figures belong on the income source (upsert_income_source). Changes the person's data: say what you set.

Scopes: `context:write`.

Arguments:

- `year`: Default: this one
- `priorYearTax`: 
- `priorYearAgi`: 
- `otherPayments`: 
- `priorYearPayments`: 
- `otherIncome`: 
- `capitalGains`: 
- `itemizedDeductions`: 
- `qualifyingChildren`: 
- `notes`: 

### `upsert_goal`: Set a goal

Create or change a savings or payoff goal: by id, else by name (case-insensitive), else new (then kind and targetAmount are required). links are what counts toward it, each with the percent of it that counts: an account (accountId from list_accounts), a manual account (manualAccountId from list_accounts' manualAccounts: the house, an HSA) or a bucket (bucket: a name or id from list_buckets, for money kept in a savings bucket like an emergency fund); exactly one per link; giving links replaces them. Changes the person's data: say what you set.

Scopes: `context:write`.

Arguments:

- `id`: 
- `name` (required): 
- `kind`: 
- `targetAmount`: Dollars
- `targetDate`: 
- `priority`: 1 is the most important
- `notes`: 
- `archived`: 
- `links`: 

### `upsert_manual_account`: Add or update a manual account

Something no bank connection reports, kept by hand: the house (asset, type real_estate) and its mortgage (liability, type loan), a car loan, an HSA, IRA or pension held elsewhere (type retirement), private company stock or a startup stake (type equity), cash. By id, else by name (any case), else new: a new one needs kind and balance. balance is dollars, positive: what it's worth, or what's owed on a liability; it's recorded on balanceOn (default today, never a day still to come) and replaces that day's entry, so call it again with a new balance to update the value. These count in net worth and appear in list_accounts' manualAccounts; a goal can link them (upsert_goal links with manualAccountId). archived: true hides one that's gone (a sold car). What you leave out stays. Truenote's records only. Tell the person what you set.

Scopes: `context:write`.

Arguments:

- `id`: 
- `name` (required): 
- `kind`: 
- `type`: real_estate, vehicle, loan, retirement, equity, cash, crypto, other
- `entityId`: Household (null) or a business
- `notes`: 
- `archived`: 
- `balance`: 
- `balanceOn`: The day the balance is for (default today)

### `upsert_income_source`: Set an income source

Create or change an income source (a W-2 job, a 1099 client, a business, a bonus): by id, else by name, else new (then type and cadence are required). expectedAmount is take-home per payment (a paycheck's net pay). regular sources (salaries; the default for w2) are the spending plan's income; anything else (a bonus, 1099 work) is a windfall allocated when it lands. earner is who in the household earns it. taxSetAsidePct is the share of each payment to set aside for taxes (30 for 30%); payerMatch is text its deposits carry ("NORTHSTAR") so Truenote can find them. For the yearly tax projection (get_tax_projection), a W-2 job takes grossPay (this year's salary before deductions, bonus apart), retirement (401(k)/403(b) for the year), otherPretax (health, HSA, FSA through payroll for the year), withheldYtd with withheldAsOf (federal income tax withheld so far and the date of the paystub it's from, both or neither), withholdingPerPaycheck (federal tax withheld from each regular paycheck), bonus, bonusOn (paid or expected) and bonusWithholdingPct (default 22); a 1099 client or business takes receivedElsewhere (paid this year into accounts Truenote can't see), expectedRestOfYear (still expected this year; null: from expectedAmount) and expensesEstimate (deductible expenses for the year; null: its entity's spending). Fields you leave out keep their value; null clears. Changes the person's data: say what you set.

Scopes: `context:write`.

Arguments:

- `id`: 
- `name` (required): 
- `type`: 
- `cadence`: 
- `expectedAmount`: Dollars per payment
- `taxSetAsidePct`: 
- `payerMatch`: 
- `entityId`: 
- `earner`: A household member's name
- `regular`: Counts toward the spending plan's income (default: true for w2)
- `active`: 
- `notes`: 
- `grossPay`: W-2: this year's salary, bonus apart
- `retirement`: W-2: 401(k)/403(b) deferrals for the year
- `otherPretax`: W-2: health, HSA, FSA through payroll, per year
- `withheldYtd`: W-2: federal income tax withheld so far this year (from a paystub)
- `withheldAsOf`: The paystub's date (with withheldYtd)
- `withholdingPerPaycheck`: W-2: federal income tax withheld per regular paycheck
- `bonus`: W-2: this year's bonus
- `bonusOn`: When the bonus was or will be paid
- `bonusWithholdingPct`: Default 22
- `receivedElsewhere`: 1099/business: paid this year into accounts Truenote can't see
- `expectedRestOfYear`: 1099/business: still expected this year (null: from expectedAmount)
- `expensesEstimate`: 1099/business: deductible expenses for the year (null: the entity's spending)

### `update_profile`: Update the household profile

Change the profile every agent reads first: the person's name, household members (each with a relationship, and a birthDate or, for a baby on the way, a dueDate), state (postal code like TX), filing status, risk tolerance, the free-form "about us" and time zone. Only the fields you pass change. householdMembers replaces the whole list: read get_context first and send everyone, including the person themself (relationship self). Changes the person's data: say what you set.

Scopes: `context:write`.

Arguments:

- `name`: What to call the person
- `householdMembers`: 
- `state`: 
- `filingStatus`: 
- `riskTolerance`: 
- `about`: 
- `timeZone`: IANA zone, e.g. America/Chicago

### `upsert_entity`: Set an entity

Add or rename an entity money can belong to: the household (personal) or a business (an LLC, a side business). By id, else by name (case-insensitive), else new (then kind is required). Assign accounts and transactions to it with create_rule or categorize_transactions; each business's money is then reported on its own. Changes the person's data: say what you set.

Scopes: `context:write`.

Arguments:

- `id`: An existing entity to rename
- `name` (required): 
- `kind`: personal or business

### `upsert_plan_line`: Set a spending plan line

Add or change a line of the spending plan (read get_plan first): by id, else by name (case-insensitive), else new (then group and amount are required). group is a group's name or id; amount is dollars per payment, cadence how often (default monthly; a $139 yearly Amazon Prime is amount 139, cadence annually). endsOn is the last day it's paid (a car loan's final month); startsOn delays a line that hasn't begun (daycare from April). match is text its payment's bank description or merchant contains ("Valon" for the mortgage, "CoServ" for electricity): a line with match and no destination is a bill, paid when a payment out contains it (find the text with query_transactions or get_recurring). accountId (from list_accounts) is where saved money goes (a brokerage: its own deposits count); bucketId (from list_buckets) is the bucket it fills ("Vacation / Travel" → the Vacations bucket), which also sets the account. categoryId (from get_context) only breaks everyday spending down (Groceries, Dining). Anything you leave out stays as it is. To cancel something, delete_record with kind plan_line. Changes the person's data: say what you set.

Scopes: `context:write`.

Arguments:

- `id`: 
- `name` (required): 
- `group`: A group's name or id
- `amount`: Dollars per payment
- `cadence`: 
- `startsOn`: 
- `endsOn`: The last day it's paid
- `categoryId`: 
- `accountId`: 
- `bucketId`: A bucket it fills (from list_buckets); the line then goes to its account
- `match`: Text its payment's bank description or merchant contains; null clears it
- `notes`: 

### `upsert_plan_group`: Set a spending plan group

Add, rename or retarget a group of the spending plan: by id, else by name (case-insensitive), else new (then kind is required: spending for expenses and wants, saving for savings and investing). targetPct is the share of take-home it should hold (45 for 45%); the groups' targets usually add up to 100. Changes the person's data: say what you set.

Scopes: `context:write`.

Arguments:

- `id`: 
- `name` (required): 
- `kind`: 
- `targetPct`: 
- `position`: Order, 0 first

### `upsert_bucket`: Set a bucket

Create or change a bucket (a virtual part of a savings or checking account, see list_buckets): by id, else by name (case-insensitive; pass accountId when two accounts have a bucket with that name), else new (then accountId is required: a checking or savings account from list_accounts). target is the bucket's own goal in dollars and targetDate when it should be reached (both optional; null clears). startingBalance (new buckets only) is what it holds today; to correct an existing bucket's balance use record_bucket_entry with kind set_balance. overflow makes it the account's overflow bucket: what a deposit has left after filling what each bucket is due goes there (one per account; setting it moves it from another). archived hides a bucket once it's empty. This changes only Truenote's records, never the bank: no money moves. Say what you set.

Scopes: `context:write`, `accounts:read`.

Arguments:

- `id`: 
- `name` (required): 
- `accountId`: The account it splits (required for a new bucket)
- `target`: Dollars
- `targetDate`: 
- `notes`: 
- `overflow`: Extra from deposits goes here
- `archived`: 
- `startingBalance`: Dollars it holds today (new buckets only)

### `move_between_buckets`: Move money between buckets

Move an amount from one bucket to another bucket of the same account (by name or id from list_buckets), e.g. $500 from Emergencies to Vacations. Both buckets change in one step; the account's total and Unassigned stay the same (unless it takes the from bucket below zero: what it's short comes out of Unassigned). This is Truenote's bookkeeping only: no money moves at the bank. date defaults to today (it can't be in the future). Say what you moved.

Scopes: `context:write`, `accounts:read`.

Arguments:

- `from` (required): A bucket's name or id
- `to` (required): A bucket's name or id, in the same account
- `amount` (required): Dollars
- `date`: 
- `memo`: 

### `record_bucket_entry`: Record a bucket entry

Record money going into or out of a bucket (by name or id from list_buckets) in Truenote's ledger. kind: contribution (money put into the account for this bucket, e.g. a transfer to savings), withdrawal (money taken out of the account from this bucket), charge (spending paid from another account, like a vet bill on checking, that this bucket covers: it needs the transactionId, and the bucket drops now while the account's total drops when the money is moved back), or set_balance (a correction: the bucket holds exactly amount as of date). transactionId (from query_transactions) ties the entry to the bank transaction it accounts for. date defaults to today. This never moves money at the bank. When unsure which bucket something belongs to, ask the person rather than guess. Say what you recorded.

Scopes: `context:write`, `accounts:read`.

Arguments:

- `bucket` (required): A bucket's name or id
- `accountId`: When two accounts have a bucket with that name
- `kind` (required): 
- `amount` (required): Dollars (for set_balance: the balance it holds)
- `date`: 
- `memo`: 
- `transactionId`: The transaction it accounts for (needed for charge)

### `resolve_review_item`: Decide a review item

Decide an item from list_review_items for the person: decision approve does what its proposal says (or, with allocations, puts other amounts in other buckets: bucket names or ids, dollars; for a withdrawal, paysBack lists the charge entry ids it pays back instead of the proposal's), and createRule (a charge only, to one bucket) also saves the proposed bucket rule so the next match is automatic; decision dismiss leaves the transaction out of buckets for good (a deposit stays in Unassigned). Together the amounts can't be more than the transaction. Only decide what the person asked you to, or what's plainly right; otherwise ask. This is Truenote's bookkeeping: no money moves at the bank. Say what you decided.

Scopes: `context:write`, `accounts:read`, `transactions:read`.

Arguments:

- `id` (required): The item's id from list_review_items
- `decision` (required): 
- `allocations`: Instead of the proposal's buckets and amounts
- `paysBack`: A withdrawal: the charge entry ids it pays back, instead of the proposal's
- `createRule`: A charge: also save the proposed bucket rule

### `create_bucket_rule`: Create a bucket rule

A rule that charges matching spending to a bucket automatically ("Banfield" → Pets), for everything since the bucket's start and every sync after: textContains is matched against the merchant and the bank's description (any case); accountId (from list_accounts), categoryId (from get_context) and minAmount/maxAmount (dollars) narrow it. Money out only. The first matching rule wins; a transaction the person already decided (charged by hand, an entry deleted, a review item answered) is left alone, and nothing is ever charged twice. Returns how many it charged right away. Prefer a specific text (a merchant's name) over a broad one: a wrong automatic charge is worse than a review item. Truenote's bookkeeping only: no money moves.

Scopes: `context:write`, `accounts:read`.

Arguments:

- `bucket` (required): A bucket's name or id from list_buckets
- `bucketAccountId`: When two accounts have a bucket with that name
- `textContains` (required): 
- `accountId`: Only spending on this account
- `categoryId`: Only spending in this category
- `minAmount`: 
- `maxAmount`: 

### `add_note`: Remember a fact

Save a dated fact or decision for every agent to know later ("Lease ends 2027-06-30", "Decided to pay the Visa in full monthly"). Short tags (lowercase words) help find it. Use for durable context, not for chat history.

Scopes: `context:write`.

Arguments:

- `body` (required): 
- `occurredOn`: The day it's about, if any
- `tags`: 
- `pinned`: Always shown first in get_context

### `update_note`: Change a note

Change a note (an id from get_context): fix or rewrite its body when a fact or decision changes, re-date it, retag it, or pin or unpin it (pinned notes always come first in get_context). What you leave out stays. Prefer this over adding a second note that contradicts the first. Changes the person's data: say what you changed.

Scopes: `context:write`.

Arguments:

- `id` (required): 
- `body`: 
- `occurredOn`: The day it's about; null: none
- `tags`: Replaces the note's tags
- `pinned`: 

### `upsert_task`: Add or change a checklist task

Add a to-do to the person's checklist, or change one: by id, else by title (any case), else new. Use it for the dated actions a plan leaves behind ("Exercise options before the 409A", due 2026-11-06), one task per action, with a due date when there's a deadline. kind event is a dated thing that happens rather than something to do ("Brooke's due date", "JJ back to work", "Closing on the house"): it needs dueOn and has no checkbox. amount (dollars) is what it costs or brings when it's about money (the $15,000 a payment needs; it reads back as sum). done: true ticks it off, false opens it again. goalId (from get_context) or bucket (a name or id from list_buckets) say what it serves; null unlinks. spotlight: true makes it the Overview's countdown, at the top of the person's home page; there is only one, so this replaces the current one (list_tasks shows which). Spotlight the one dated event that matters most to the household's money in the coming months (a birth, a move, a wedding, a job change, a big payment being saved for), not routine to-dos; the person can change it. What you leave out stays. Truenote's records only: it never acts on the task. Tell the person what you added or changed.

Scopes: `context:write`.

Arguments:

- `id`: 
- `kind`: task (default) or event
- `title` (required): 
- `dueOn`: The day it's due (an event's day); null: no date
- `notes`: 
- `done`: 
- `amount`: Dollars; null clears it
- `spotlight`: The Overview's countdown; replaces the current one
- `goalId`: 
- `bucket`: A bucket's name or id
- `bucketAccountId`: When two accounts have a bucket with that name

### `save_plan`: Save a plan

Save a named scenario for the person to review: a markdown body and structured assumptions (numbers, dates, lists) such as a parental-leave budget or a tax plan. By id, else by name, else new (status draft). Saving again with the same name updates it.

Scopes: `context:write`.

Arguments:

- `id`: 
- `name` (required): 
- `summary`: 
- `body`: Markdown
- `assumptions`: 
- `status`: 

### `categorize_transactions`: Recategorize transactions

Set the category, entity (household or a business) or excluded flag of up to 200 transactions at once (ids from query_transactions, category and entity ids from get_context), and/or a note. A category, entity or exclusion set here wins over rules for those transactions. All of them change or none do. To fix a whole merchant going forward, use create_rule instead.

Scopes: `context:write`, `transactions:read`.

Arguments:

- `transactionIds` (required): 
- `categoryId`: null: back to the automatic category
- `entityId`: 
- `excluded`: true: leave out of spending and income
- `note`: 

### `create_rule`: Create a categorization rule

A rule that sets the category, entity or excluded flag of every matching transaction, past and future (except ones edited by hand), and/or a business share: businessShare splits each match, percent of it going to a business entity as a part of its own (the rest stays the household's), for a bill partly used for business (internet 60% to the LLC). Conditions all must hold: merchant or description contains text, an account, an amount range in dollars (by size), a direction (outflow is money out). Returns how many transactions it now decides. Prefer this over categorize_transactions or split_transaction for anything recurring.

Scopes: `context:write`, `transactions:read`.

Arguments:

- `name` (required): 
- `conditions` (required): 
- `setCategoryId`: 
- `setEntityId`: 
- `setExcluded`: 
- `businessShare`: 
- `priority`: Lower runs first

### `split_transaction`: Split a transaction

Split one transaction (an id from query_transactions; a part's id means its whole) into parts that add up to it exactly, each with its own category, entity and note: the business part of a mixed purchase, a bill shared with the LLC. amount is each part's size in dollars (the whole's direction is kept). The parts count in place of the whole everywhere (spending, the plan, each business's taxes), and query_transactions lists them instead (with splitOf). Replaces any split it had; rules leave it alone afterwards. unsplit: true puts it back together. For a recurring share, use create_rule's businessShare instead. Changes the person's records only: say what you split.

Scopes: `context:write`, `transactions:read`.

Arguments:

- `transactionId` (required): 
- `parts`: 
- `unsplit`: 

### `prepare_upload`: Prepare a document upload

Get a one-time link to keep one file (a paystub, W-2, 1099, 1098, tax return, statement, receipt; PDF or image, 10 MB at most) in the person's documents. Returns curl, a command that sends a local file straight to Truenote (replace FILE with the path; the file never passes through you), and uploadUrl, a page where the person drops the file themselves (for when you can't reach their files). Say what it is: kind, taxYear, documentOn, and the incomeSourceId a paystub is for (from get_context); name, kind and taxYear left out are guessed from the file's name. One call per file; the link lasts 15 minutes. Then read_document can read it.

Scopes: `documents:write`.

Arguments:

- `name`: Default: the file's name
- `kind`: 
- `taxYear`: 
- `documentOn`: The date on the document (a paystub's pay date)
- `entityId`: Whose it is (default: the household)
- `incomeSourceId`: The income source a paystub or W-2 is for
- `accountId`: The connected account a statement is of
- `manualAccountId`: The manual account (list_accounts) it's about: the mortgage, the HSA
- `notes`: 

### `update_document`: Edit a document

Change what a kept document is and whose (an id from list_documents): name, kind, taxYear, documentOn (the date on it, e.g. a statement's date), entityId, incomeSourceId (the job a paystub or W-2 is for), accountId (a connected account a statement is of), manualAccountId (a manual account it's about, like the mortgage), notes. Fields you leave out keep their value; null clears. The file itself never changes, and documents can't be deleted here. Changes the person's records: say what you changed.

Scopes: `documents:write`.

Arguments:

- `id` (required): 
- `name`: 
- `kind`: 
- `taxYear`: 
- `documentOn`: 
- `entityId`: 
- `incomeSourceId`: 
- `accountId`: 
- `manualAccountId`: 
- `notes`: 

### `delete_record`: Delete a record

Delete one of the person's records by kind and id: goal, income_source, entity (its accounts and transactions go back to the household; rules that set it go too), category (transactions in it fall back to Plaid's mapping; rules that set it go too), rule (what it decided goes back to the other rules), manual_account (with its balance history), plan, plan_group (only once it has no lines), plan_line (something canceled or entered by mistake; for one that ends later, set its endsOn with upsert_plan_line so the plan shows what frees up), task (to finish one, upsert_task with done: true instead), note (when a decision changes, add the new note, then delete the old one so agents don't read both), bucket (its money goes back to Unassigned; no money moves), bucket_rule, bucket_entry (undoes one ledger entry: a move's both sides; an automatic one isn't redone; an archived bucket's entries stay; needs accounts:read). Ids come from get_context, get_plan, list_tasks, list_accounts, list_buckets and list_bucket_rules. Documents use delete_document. It can't be undone: confirm with the person first (a note or entry you made in this conversation excepted), then say what you deleted.

Scopes: `context:write`.

Arguments:

- `kind` (required): 
- `id` (required): 

### `delete_document`: Delete a document

Permanently delete an uploaded document (an id from list_documents): the file and its text. Use when the person asks, or for a duplicate or wrong upload. It can't be undone: confirm with the person first.

Scopes: `documents:write`.

Arguments:

- `id` (required): 

### `upsert_category`: Add or change a category

Add a spending category, or rename one, change its kind (expense, income, transfer: transfers don't count as spending) or nest it under a parent (parentId, null: top level): by id, else by name (any case), else new (then kind is required). Which of the bank's categories land in it stays the person's to set in Truenote. Then categorize_transactions or create_rule to fill it. Say what you changed.

Scopes: `context:write`.

Arguments:

- `id`: 
- `name` (required): 
- `kind`: 
- `parentId`: 

### `update_rule`: Change a categorization rule

Change a rule (an id from get_context): its name, conditions (given conditions replace them all; amounts in dollars by size), what it sets (category, entity, excluded; null clears), its businessShare (null removes it), priority (lower runs first) or active (false pauses it). What you leave out stays. Saving re-decides every transaction nobody edited by hand. To remove a rule, delete_record with kind rule.

Scopes: `context:write`, `transactions:read`.

Arguments:

- `id` (required): 
- `name`: 
- `conditions`: 
- `setCategoryId`: 
- `setEntityId`: 
- `setExcluded`: 
- `businessShare`: 
- `priority`: 
- `active`: 

### `update_account`: Change a bank account's settings

Change how Truenote treats a connected account (an id from list_accounts): nickname (null: the bank's name again), hidden (true drops it out of totals, net worth and this connection; only the person can show it again unless this connection sees hidden accounts) or entityId (the business it belongs to; null: the household). Never touches the bank. Say what you changed.

Scopes: `context:write`, `accounts:read`.

Arguments:

- `accountId` (required): 
- `nickname`: 
- `hidden`: 
- `entityId`: 

### `reset_transactions`: Undo transaction edits

Undo hand edits on transactions (ids from query_transactions): their category, entity, exclusion and any hand split go back to what the rules decide. Notes stay. Use when an earlier categorize_transactions or split_transaction was wrong.

Scopes: `context:write`, `transactions:read`.

Arguments:

- `transactionIds` (required): 

### `refresh_bank`: Refresh a bank connection

Ask the bank for what's new on the connection holding an account (an id from list_accounts): balances and transactions, in the background (a minute or two). Use when the person says something posted that Truenote doesn't show yet. A connection that needs the person to sign in again can't be refreshed: tell them to reconnect it in Truenote.

Scopes: `context:write`, `accounts:read`.

Arguments:

- `accountId` (required): 

### `disconnect_bank`: Disconnect a bank

Remove the bank connection holding an account (an id from list_accounts): Truenote stops syncing it, and every account on that connection and its history are deleted from Truenote. Truenote is read-only to banks: nothing changes at the bank itself. Connecting it again means the person signs in to the bank in Truenote. It can't be undone: confirm with the person first, naming every account it removes.

Scopes: `context:write`, `accounts:read`.

Arguments:

- `accountId` (required):
