What it does
Overspending shows up in the P&L a month after it happens. Halfway through the month you can still act on it, if you know that software is up a third or that travel tripled.
This skill compares like with like: the first 16 days of this month against the first 16 days of last month, category by category, using the expense accounts your bookkeeper already keeps. With semimonthly payroll the paydays line up as well, so payroll doesn't distort the comparison.
How it works
1Pull month to date
Call
GET /v3/company/{realmId}/reports/ProfitAndLossfrom the 1st of this month to today withaccounting_method=Accrual, and keep the rows in theCOGSandExpensessections.2Pull the same days last month
Run the same report from the 1st of last month to the same day number (or the last day, if last month was shorter), so 16 days are compared with 16 days.
- 3
3Group into categories
Use the top-level expense accounts as categories and roll sub-accounts into their parent, following the report's section headers. Keep
Uncategorized Expenseas its own line. 4Flag what is running hot
Mark categories up 25% or more and by at least $500, and any category new this month. Name the largest transactions behind each flag from
ProfitAndLossDetailfor the same dates.- 5
5Write the report
Month-to-date total and its change against the same days last month, a bar per category, the flagged categories with their reasons, and the uncategorized amount if there is one.
Post it to the board
With
BRIEFKIN_TOKENset, the agent sends the result as one card that updates in place every run. Without it, you get the report in the chat.
What you get
- Expenses month to date and the change against the same days last month.
- By category: this month, last month, change.
- Categories up 25% or more, with the transactions behind them.
- Money sitting in Uncategorized Expense, if any.
Install and run it
Pick your agent, where the data comes from and how to schedule it; the commands below follow.
Install the skill
One command. It puts the SKILL.md in ~/.claude/skills and in ~/.agents/skills, which Codex, Cursor, Gemini CLI, Copilot CLI and OpenCode read too.
shell
curl -fsSL https://briefkin.dev/skills/quickbooks-expenses-by-category/install | shRun it
Ask Claude Code:
prompt
Run the quickbooks-expenses-by-category skillOr paste the prompt instead of installing:
prompt
From QuickBooks Online (read only), pull ProfitAndLoss from the 1st of this month to today and from the 1st of last month to the same day number last month, accrual basis. Group the COGS and Expenses rows into top-level expense categories, rolling sub-accounts into their parent. Give me the month-to-date total and its change against the same days last month, then each category with both amounts and the change. Flag categories up 25% or more and by at least $500, and anything new this month, and name the largest transactions behind each flag. Tell me if there is money in Uncategorized Expense.Put it on a schedule
Weekdays at 7:30, from cron on any machine where Claude Code is signed in:
crontab
30 7 * * 1-5 claude -p "Run the quickbooks-expenses-by-category skill"Add it with
crontab -e. A laptop asleep at that time runs it when it wakes if you use launchd or Task Scheduler instead; GitHub Actions works for the API route.Send it to your board
Connect Briefkin once with
curl -fsSL https://briefkin.dev/install | shand every run lands on your board as a stat tile. How setup works
View the SKILL.mdRaw file
SKILL.md---
name: quickbooks-expenses-by-category
description: "Every weekday: month-to-date spend by expense category from QuickBooks, against the same days of last month, with the categories running hot. Use when the user asks for this, or when it runs on a schedule."
---
# QuickBooks expenses by category
Every weekday: month-to-date spend by expense category from QuickBooks, against the same days of last month, with the categories running hot.
Overspending shows up in the P&L a month after it happens. Halfway through the month you can still act on it, if you know that software is up a third or that travel tripled.
This skill compares like with like: the first 16 days of this month against the first 16 days of last month, category by category, using the expense accounts your bookkeeper already keeps. With semimonthly payroll the paydays line up as well, so payroll doesn't distort the comparison.
## Two ways to get the data
Use the API or MCP route when you have an MCP server, a CLI or an API token for the app. Otherwise, if you can drive a browser the user is signed in to (Claude in Chrome, a Playwright or Chrome DevTools MCP server), use the browser route. Say which one you used.
## Route A: API or MCP server
### What you need
- A QuickBooks Online connection that can run reports (a connector, an MCP server, or an Intuit app with `com.intuit.quickbooks.accounting`), pointed at the right company.
If something is missing, say what and stop; do not invent numbers.
### Steps
1. **Pull month to date** (QuickBooks): Call `GET /v3/company/{realmId}/reports/ProfitAndLoss` from the 1st of this month to today with `accounting_method=Accrual`, and keep the rows in the `COGS` and `Expenses` sections.
2. **Pull the same days last month** (QuickBooks): Run the same report from the 1st of last month to the same day number (or the last day, if last month was shorter), so 16 days are compared with 16 days.
3. **Group into categories**: Use the top-level expense accounts as categories and roll sub-accounts into their parent, following the report's section headers. Keep `Uncategorized Expense` as its own line.
4. **Flag what is running hot** (QuickBooks): Mark categories up 25% or more and by at least $500, and any category new this month. Name the largest transactions behind each flag from `ProfitAndLossDetail` for the same dates.
5. **Write the report**: Month-to-date total and its change against the same days last month, a bar per category, the flagged categories with their reasons, and the uncategorized amount if there is one.
## Route B: the browser
### What you need
- Signed in to QuickBooks Online with access to reports, with the right company open.
If something is missing, say what and stop; do not invent numbers.
### Steps
Start at https://app.qbo.intuit.com/app/reports. The user is signed in already; never type passwords or codes, and ask if a sign-in page appears.
1. **Run month to date**: Open `https://app.qbo.intuit.com/app/reports`, open **Profit and Loss** under **Standard reports**, set **Report period** to a custom range from the 1st of this month to today and **Accounting method** to **Accrual**, and run it. Click **Collapse** so sub-accounts roll into their parent, then read every row in **Cost of Goods Sold** and **Expenses**.
2. **Run the same days last month**: Change the range to the 1st of last month through the same day number (or its last day, if last month was shorter) and run again, so 16 days are compared with 16 days. The previous-period comparison does not do this for a partial month, which is why it takes two runs.
3. **Flag what is running hot**: For each category compute the change. Mark categories up 25% or more and by at least $500, and any category that has spend this month and none last month.
4. **Name the transactions behind each flag**: Click the month-to-date amount of each flagged category to open its **Transaction Report** and note the largest transactions with their vendors and dates.
5. **Write the report**: Month-to-date total and its change against the same days last month, each category with both amounts and the change, the flagged categories with their reasons, and the **Uncategorized Expense** amount if there is one.
Note: Transactions still sitting in the bank feed's For review tab are not in the report, so a low total may mean the feed has not been worked through. Control names differ slightly between the classic and the newer report view.
## The report
- **Expenses month to date** and the change against the same days last month.
- **By category**: this month, last month, change.
- Categories up 25% or more, with the transactions behind them.
- Money sitting in Uncategorized Expense, if any.
## Post it to Briefkin
When `BRIEFKIN_TOKEN` is set, or `~/.config/briefkin/env` exists (the installer from https://briefkin.dev/docs writes it), also send the result to the user's Briefkin board as one card. Keep the `item_key` the same on every run so the card updates in place, use a new `event_id` per run, and put today's real numbers in place of the example ones. If the request fails, say so once and carry on.
```bash
[ -n "${BRIEFKIN_TOKEN:-}" ] || . ~/.config/briefkin/env
curl -sS -X POST "${BRIEFKIN_URL:-https://briefkin.dev}/v1/events" \
-H "authorization: Bearer $BRIEFKIN_TOKEN" \
-H "content-type: application/json" \
-d @- <<'JSON'
{
"v": 1,
"event_id": "quickbooks-expenses-by-category/<date of this run, e.g. 2026-10-16>",
"item_key": "quickbooks-expenses-by-category",
"project": "Acme",
"source": "QuickBooks expenses by category skill",
"kind": "metric",
"title": "October spend $44,620, 5% above September",
"metric": {
"label": "Expenses month to date",
"value": 44620,
"prefix": "$",
"better": "lower",
"period_start": "<start of the period, ISO 8601>",
"period_end": "<end of the period, ISO 8601>"
},
"glance": [
{
"type": "Grid",
"props": {
"columns": 2
},
"children": [
{
"type": "Stat",
"props": {
"label": "Same days in September",
"value": 42500,
"prefix": "$"
}
},
{
"type": "Stat",
"props": {
"label": "Difference",
"value": "+$2,120",
"delta": 5,
"better": "lower"
}
}
]
},
{
"type": "Bars",
"props": {
"unit": "USD",
"items": [
{
"label": "Payroll",
"value": 18300
},
{
"label": "Rent",
"value": 6500
},
{
"label": "Software",
"value": 5840
},
{
"label": "Contractors",
"value": 4900
},
{
"label": "Advertising",
"value": 4250
},
{
"label": "Travel",
"value": 2180
}
]
}
}
],
"widget": [
{
"type": "Table",
"props": {
"columns": [
"Category",
"Oct 1-16",
"Sep 1-16",
"Change"
],
"align": [
"left",
"right",
"right",
"right"
],
"rows": [
[
"Payroll",
"$18,300",
"$18,300",
"0%"
],
[
"Rent",
"$6,500",
"$6,500",
"0%"
],
[
"Software",
"$5,840",
"$4,230",
"+38%"
],
[
"Contractors",
"$4,900",
"$6,400",
"-23%"
],
[
"Advertising",
"$4,250",
"$3,900",
"+9%"
],
[
"Travel",
"$2,180",
"$640",
"+241%"
],
[
"Office",
"$1,120",
"$1,050",
"+7%"
],
[
"Other",
"$1,530",
"$1,480",
"+3%"
],
[
"Total",
"$44,620",
"$42,500",
"+5%"
]
]
}
},
{
"type": "Callout",
"props": {
"text": "Travel is up $1,540, mostly flights booked on Oct 7 for the November offsite. Software is up $1,610 on two annual renewals.",
"tone": "warn"
}
}
],
"size": "md"
}
JSON
```
Widgets come from the Briefkin catalog (https://briefkin.dev/v1/catalog). Without a token, just give the user the report.
Set `period_start` and `period_end` to the window the number covers: the tile names it from them ("Last 7 days", "Today", "This month"). For a count right now (open items, a balance), send `"period_label": ""` so no period shows; for another name, send it as `period_label` (at most 24 characters).
## Run it on a schedule
Suggested: Weekdays at 7:30 (`30 7 * * 1-5`). From cron, with the agent signed in on that machine:
```bash
30 7 * * 1-5 claude -p "Run the quickbooks-expenses-by-category skill"
# Codex: codex exec, Gemini CLI: gemini -p, Copilot CLI: copilot -p, OpenCode: opencode run
```
Or use the agent's own scheduler (Claude Code routines, Codex automations, Claude or ChatGPT scheduled tasks): https://briefkin.dev/skills/quickbooks-expenses-by-category#schedule
Source: https://briefkin.dev/skills/quickbooks-expenses-by-category
What your agent needs
A QuickBooks Online connection that can run reports (a connector, an MCP server, or an Intuit app with
com.intuit.quickbooks.accounting), pointed at the right company.
Connecting QuickBooks
- QuickBooks connector in Claude. Intuit and Anthropic partnered in 2026 to bring QuickBooks into Claude; where your plan offers the connector, connect it with your Intuit sign-in.
- QuickBooks Online MCP server, Intuit's open-source local server (source). It runs over stdio and reads
QUICKBOOKS_CLIENT_ID,QUICKBOOKS_CLIENT_SECRET,QUICKBOOKS_REFRESH_TOKEN,QUICKBOOKS_REALM_IDandQUICKBOOKS_ENVIRONMENT. - Accounting API with OAuth 2.0. Register an app in the Intuit Developer Portal, authorize the company once with the
com.intuit.quickbooks.accountingscope, and store the same five values. Access tokens last an hour and the refresh token can change on each refresh, so the skill must save the newest one.
The accounting scope has no read-only version; with Intuit's MCP server, set QUICKBOOKS_DISABLE_WRITE, QUICKBOOKS_DISABLE_UPDATE and QUICKBOOKS_DISABLE_DELETE to true so the agent gets only read, search and report tools.
Questions
Why does the total jump in the middle of the month?
It is a running month-to-date total, so it climbs every day and steps up on payday. The comparison that matters is against the same days of last month, which the card shows under the number.
Are transactions still waiting in the bank feed counted?
No. The API only sees transactions that have been added to the books; anything still in the bank feed's For review tab is invisible to it. If the card looks low, check whether the feed has been worked through this week.
Do I need Briefkin to use the QuickBooks expenses by category skill?
No. The skill runs with your own agent and gives you the report in the chat. With a Briefkin token set, each run also posts it to your board as a stat tile, so you can glance at it instead of asking again.
Which agents can run it?
Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot CLI, OpenCode, Windsurf and Amp all read SKILL.md files. The install command puts it in ~/.claude/skills and ~/.agents/skills, where they look. ChatGPT, the Claude app and Grok take the prompt instead. Pick your agent under "Install and run it" and the commands change to match.
Can it work without an API or MCP server, from my browser?
Yes. Switch the data source to "Your browser" and the steps change to the QuickBooks pages themselves: the agent opens app.qbo.intuit.com/app/reports in a browser you are signed in to and reads the numbers off the page. Claude Code, Codex, Cursor, Claude app and ChatGPT can drive a browser out of the box; Gemini CLI, Copilot CLI and OpenCode need a Playwright or Chrome DevTools MCP server first. It is slower than the API and needs you signed in, so it suits a report you run by hand or from a scheduler on your own computer.