Log, find, update, and delete expenses and income in the Simplify Budget Google Sheet, and answer read-only recurring schedule questions. NEVER use sessions_spawn or ACP — ONLY use the exec tool to run bash scripts. Expenses use live categories. Income uses name, account, source, and notes. For edits/deletes, find rows first, then mutate by transaction id. Amounts are always stored in the configured tracker currency. Just do it.
CRITICAL EXECUTION RULE: You MUST use the
exectool to run the bash scripts below. Do NOT callsessions_spawn. Do NOT create ACP sessions. These are standalone shell scripts. Resolve script paths relative to this skill directory and run the resulting absolute path withexec.
Required environment variables:
GOOGLE_SA_FILE — absolute path to the Google service account JSON fileSPREADSHEET_ID — the Simplify Budget spreadsheet IDTRACKER_CURRENCY — the base currency code for the tracker (for example EUR)Optional environment variables:
TRACKER_CURRENCY_SYMBOL — display symbol for the base currency (for example €)TRACKER_CURRENCY is the system of record for stored amounts.TRACKER_CURRENCY."50 MYR" or "12 USD".TRACKER_CURRENCY, and store the converted amount in the sheet.[auto-fx] audit line to notes with the original amount, converted amount, rate, and rate date.The Simplify Budget sheet has a fixed list of user-defined categories (e.g. "Dining Out 🍽️", "Groceries 🛒", "Transport 🚗"). You MUST:
=zategory{stableId} (e.g. =zategory4) — never use the fullName string as the write inputWhen the user provides an expense (amount + description, with optional date/account/notes):
Fetch the current active categories:
bash <skill_dir>/scripts/get_categories.sh
This returns lines of stableId<TAB>fullName. Show the fullNames to yourself for matching — do NOT show this raw output to the user.
Extract from the user's message:
amount — required. If the user mentions a foreign currency, preserve it in the amount string you pass to the script, for example "50 MYR" or "12 USD". If they give no currency, pass a plain number like 10.description — what they bought/paid for (required)category — match to the fetched category list; construct =zategory{stableId} (e.g. =zategory4 for Dining Out, =zategory2 for Transport)date — in YYYY-MM-DD format. Default to today if not specified.account — default to "Cash" if not specifiednotes — optional supporting context. Keep the main purchase title in description and extra detail in notesWrite the expense:
bash <skill_dir>/scripts/write_expense.sh "<amount_or_amount_with_currency>" "=zategory<stableId>" "<description>" "<YYYY-MM-DD>" "<account>" "<notes>"
If the user asks to add multiple expenses in one message, split them into separate write_expense.sh calls. Never try to pass multiple amounts into one command.
Examples:
add 3 test expenses with 1 2 and 3 euro1, 2, and 3test expense 1 euro, test expense 2 euro, test expense 3 euroConfirm to the user in a friendly, concise way: "✅ Logged [description] — [amount] under [actual resolved category] on [date]" Include notes only when present. Always name the category you actually used.
When the user uploads a receipt image or asks you to log a receipt:
description.Examples:
When the user wants to inspect, fix, or delete an expense, resolve it from the sheet first:
bash <skill_dir>/scripts/find_expenses.sh "<query>" 10
description and notes.When the user provides income (amount + name, with optional date/account/source/notes):
Extract from the user's message:
amount — required. If the user mentions a foreign currency, preserve it in the amount string you pass to the script, for example "500 USD" or "1000 MYR". If they give no currency, pass a plain number.name — required. This is the income title, e.g. Salary, BMW Sale, Etoro withdrawaldate — in YYYY-MM-DD format. Default to today if not specified.account — default to Other if not specified.source — default to Other if not specified. Use the user’s wording when it is clear, e.g. Salary, Capital Gains, Remittance, Crypto, MTS.notes — optional supporting context.Write the income:
bash <skill_dir>/scripts/write_income.sh "<amount_or_amount_with_currency>" "<name>" "<YYYY-MM-DD>" "<account>" "<source>" "<notes>"
Confirm to the user in a concise way: "✅ Logged income [name] — [amount] into [account] from [source] on [date]" Include notes only when present.
When the user wants to inspect, fix, or delete income, resolve it from the sheet first:
bash <skill_dir>/scripts/find_income.sh "<query>" 10
name, source, and notes.When the user asks summary questions such as:
what's my income this monthwhat did I spend this monthwhat are this month's totalshow much did I save this monthDo NOT rebuild these totals from ledger rows unless the user explicitly asks for line-item reconstruction.
Instead, read the monthly summary from Dontedit:
bash <skill_dir>/scripts/find_summary.sh --month 2026-03
Rules:
Dontedit is the source of truth for monthly totals.Expenses / Income only when the user asks for detailed entries, not when they ask for top-line monthly totals.When the user asks read-only recurring questions like:
what is due this monthwhen is capcut duewhat subscriptions are due nextUse the recurring query script. Do NOT write anything into Expenses or Income.
Examples:
bash <skill_dir>/scripts/find_recurring.sh --month 2026-03
bash <skill_dir>/scripts/find_recurring.sh --query "CapCut" --date 2026-03-28
bash <skill_dir>/scripts/find_recurring.sh --query "CapCut" --mode next --date 2026-03-28
Rules:
Recurring using the same recurrence rules as the existing Apps Script logic.when is X due, prefer --mode next.When the user wants to change or delete a recurring item in the Recurring tab:
find_recurring.sh.Recurring row itself. Never write anything into Expenses or Income for this task.__KEEP__ for unchanged fields and __CLEAR__ for optional end date / notes / source:
bash <skill_dir>/scripts/update_recurring.sh "<recurring_id>" "<YYYY-MM-DD_or___KEEP__>" "<name_or___KEEP__>" "<category_or___KEEP__>" "<expense_or_income_or___KEEP__>" "<Monthly_or_Quarterly_or_Yearly_or___KEEP__>" "<amount_or___KEEP__>" "<account_or___KEEP__>" "<YYYY-MM-DD_or___KEEP___or___CLEAR__>" "<notes_or___KEEP___or___CLEAR__>" "<source_or___KEEP___or___CLEAR__>"
bash <skill_dir>/scripts/delete_recurring.sh "<recurring_id>"
When the user wants to add a recurring expense or recurring income to the Recurring tab:
start_date in YYYY-MM-DDnamecategory must use the live active category list; never invent a categorytype as expense or incomefrequency as Monthly, Quarterly, or Yearlyamountaccount, end_date, notes, sourcebash <skill_dir>/scripts/write_recurring.sh "<YYYY-MM-DD>" "<name>" "<category>" "<expense_or_income>" "<Monthly_or_Quarterly_or_Yearly>" "<amount>" "<account>" "<YYYY-MM-DD_optional_end_date>" "<notes>" "<source>"
Recurring starting from row 6, matching the SB_LIVE hole-reuse behavior.=zategory<stableId> formula derived from the live category listIncome 💵When the user wants to change amount, name, date, account, source, or notes for an income row:
find_income.sh. Do NOT trust chat memory as the source of truth.__KEEP__ for unchanged fields and __CLEAR__ to blank notes:
bash <skill_dir>/scripts/update_income.sh "<transaction_id>" "<amount_or_amount_with_currency_or___KEEP__>" "<name_or___KEEP__>" "<YYYY-MM-DD_or___KEEP__>" "<account_or___KEEP__>" "<source_or___KEEP__>" "<notes_or___KEEP___or___CLEAR__>"
If the user asks to undo or delete an income entry:
find_income.sh.bash <skill_dir>/scripts/delete_income.sh "<transaction_id>"
When the user says things like "fix that", "that was wrong", "change the amount", "put that under X instead", "it was 4 not 5":
Resolve the target expense from the sheet using find_expenses.sh. Do NOT trust chat memory as the source of truth.
Ask for or infer the correction from their message (amount, category, description, date, account, or notes). If the new amount is in a foreign currency, preserve that currency in the amount argument you pass to the script.
For category corrections, fetch the category list again and match:
bash <skill_dir>/scripts/get_categories.sh
Run the update with the corrected values. Use __KEEP__ for unchanged fields and __CLEAR__ to blank notes:
bash <skill_dir>/scripts/update_expense.sh "<transaction_id>" "<amount_or_amount_with_currency_or___KEEP__>" "<=zategory<stableId>_or___KEEP__>" "<description_or___KEEP__>" "<YYYY-MM-DD_or___KEEP__>" "<account_or___KEEP__>" "<notes_or___KEEP___or___CLEAR__>"
Confirm: "✅ Updated — now [description] — [amount] under [actual resolved category]" Include notes only when present. Always name the category you actually used.
If the user asks to undo or delete an entry:
find_expenses.sh.bash <skill_dir>/scripts/delete_expense.sh "<transaction_id>"
name, account, source, and notes columns on the Income tab.TRACKER_CURRENCYTRACKER_CURRENCY