Month-end variance commentary
On the second of each month, Claude Code reads the two newest trial balance exports in your close folder, computes the changes with a script instead of mental math, and writes commentary for each account over your threshold. A second model checks every number against the table before you see it.
- Find exports Shell
- Analyze variances Claude Code · Sonnet
- Check the numbers Claude API · Opus 5
- Controller sign-off You
- Save report Shell
What each step does
Find exports
ShellLists the two newest CSV files in the folder: this period and the last one.
Analyze variances
Claude Code · SonnetJoins the two periods with a script, flags material changes and explains them from the files in the folder.
Check the numbers
Claude API · Opus 5A second model checks the arithmetic and that every claim is backed by the data.
Controller sign-off
YouShows you the report. Reject with a comment and it is rewritten with your notes.
Save report
ShellWrites the approved report to the reports folder, named after the month.
From copy to first run
- Copy the pipeline JSON with the button above.
- In Jimothy, open Pipelines → New pipeline, paste it under “Or import a pipeline JSON” and click Import.
- Under Workspace, choose the folder where you save each month’s trial balance exports.
- Fill in the variables below under Pipeline settings → Variables.
- Triggers → Add trigger → Schedule, cron 0 8 2 * * (08:00 on the 2nd of each month).
Export both periods as CSV with one row per account (number, name, balance or debit/credit columns). Any other files in the folder, such as GL detail or accrual schedules, are used to explain the swings.
What to fill in
The prompts and commands read these as {{vars.<name>}}. The examples are placeholders: replace them with your own.
| Variable | What to put in it | Example |
|---|---|---|
company | Your company name, used in the write-up. | Acme Inc. |
thresholdPercent | Flag an account when its change is at least this many percent… | 10 |
minAmount | …and at least this amount, in your reporting currency. | 5000 |
reportsFolder | Folder (inside the close folder) where approved reports are saved. | reports |
Show the pipeline JSON
{
"jimothyPipeline": 1,
"name": "Month-end variance commentary",
"description": "Compares the two newest trial balance exports, explains material variances, and saves the report after you approve.",
"icon": "workflow",
"color": "#22c55e",
"repo": {
"mode": "inplace",
"localPath": ""
},
"concurrency": 1,
"variables": {
"company": "Acme Inc.",
"thresholdPercent": "10",
"minAmount": "5000",
"reportsFolder": "reports"
},
"steps": [
{
"id": "find",
"name": "Find exports",
"type": "shell",
"description": "Lists the two newest CSV files in the folder: this period and the last one.",
"timeoutMinutes": 2,
"command": "files=$(ls -t -- *.csv 2>/dev/null | head -2); [ \"$(printf '%s\\n' \"$files\" | grep -c .)\" -eq 2 ] || { echo \"Put this month's and last month's trial balance exports (.csv) in $(pwd)\"; exit 1; }; printf '%s\\n' \"$files\""
},
{
"id": "analyze",
"name": "Analyze variances",
"type": "agent",
"description": "Joins the two periods with a script, flags material changes and explains them from the files in the folder.",
"harnessId": "claude-code",
"model": "sonnet",
"dependsOn": [
"find"
],
"timeoutMinutes": 30,
"prompt": "You are preparing month-end variance commentary for {{vars.company}}.\n\nThe two newest trial balance exports in the current folder are, newest first:\n{{steps.find.output}}\nThe first is the current period and the second is the prior period.\n\n1. Inspect both files to learn their columns. Write and run a small script (Python or awk) that joins the accounts by account number and computes, for each account: prior balance, current balance, change and % change. Never do arithmetic in your head; every number you report must come from the script's output.\n2. Check that debits equal credits in each file and report the totals.\n3. Flag accounts where the absolute change is at least {{vars.minAmount}} AND the absolute % change is at least {{vars.thresholdPercent}}%.\n4. For each flagged account, explain the change in one to three sentences. Use the other files in this folder (GL detail, accrual schedules, invoices, notes) as evidence and name the file you used. If nothing in the folder explains it, write \"Unexplained: ask the account owner\" instead of guessing.\n\nDo not modify or delete any existing file. Your final answer is a Markdown report with these sections and nothing else:\n# Variance commentary: <current period>\n## Summary (three bullets)\n## Flagged accounts (table: Account, Name, Prior, Current, Change, %)\n## Commentary (one sub-heading per flagged account)\n## Checks (debit and credit totals for each file)\n{{#if steps.review.output}}\n\nA reviewer checked your previous report. Fix every problem it lists:\n{{steps.review.output}}{{/if}}{{#if steps.approve.output}}\n\nYour previous draft was rejected with this feedback. Rewrite it:\n{{steps.approve.output}}{{/if}}"
},
{
"id": "review",
"name": "Check the numbers",
"type": "agent",
"description": "A second model checks the arithmetic and that every claim is backed by the data.",
"harnessId": "anthropic-api",
"model": "claude-opus-5",
"dependsOn": [
"analyze"
],
"timeoutMinutes": 10,
"passPattern": "VERDICT:\\s*APPROVE",
"loopBackTo": "analyze",
"maxLoops": 2,
"prompt": "Review this variance report before it goes to the controller.\n\n{{steps.analyze.output}}\n\nCheck that:\n- every Change equals Current minus Prior, and every % equals Change divided by the absolute Prior, to one decimal place;\n- every account in the table has commentary, and every account in the commentary is in the table;\n- the commentary only states causes it attributes to a named file, or says \"Unexplained\";\n- the debit and credit totals in Checks balance.\n\nList each problem you find with the account it affects. End with exactly one line: VERDICT: APPROVE if there are no problems, otherwise VERDICT: CHANGES_REQUESTED."
},
{
"id": "approve",
"name": "Controller sign-off",
"type": "approval",
"description": "Shows you the report. Reject with a comment and it is rewritten with your notes.",
"dependsOn": [
"review"
],
"loopBackTo": "analyze",
"maxLoops": 3,
"approvalMessage": "Save this variance report? Reject with a comment to have it rewritten.\n\n---\n\n{{steps.analyze.output}}"
},
{
"id": "save",
"name": "Save report",
"type": "shell",
"description": "Writes the approved report to the reports folder, named after the month.",
"dependsOn": [
"approve"
],
"timeoutMinutes": 2,
"command": "mkdir -p {{vars.reportsFolder}} && f={{vars.reportsFolder}}/variance-$(date +%Y-%m).md && printf '%s\\n' {{steps.analyze.output}} > \"$f\" && echo \"Saved $(pwd)/$f\""
}
]
}More for accounting & finance, and beyond
Expense policy check
Checks each submitted expense against your written policy. Clean ones go straight through; only the flagged ones wait for you.
Accounting & financeInvoice intake and GL coding
Reads each incoming vendor invoice, extracts the details, suggests GL codes from your chart of accounts, and sends it to your AP tool after you check it.
Accounting & financeOverdue invoice reminders
Reads your AR aging report every week, drafts a reminder for each overdue customer in the right tone for how late they are, and sends the ones you pick.