Template · Accounting & finance

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.

Download .json

Schedule0 8 2 * *Month-end variance commentary2nd · 08:00
Pipeline
  1. Find exports Shell
  2. Analyze variances Claude Code · Sonnet
  3. Check the numbers Claude API · Opus 5
  4. Controller sign-off You
  5. Save report Shell
Reportreports/variance-2026-09.md14 accounts over threshold, 2 need an owner’s explanationSaved
The pipeline

What each step does

  1. Find exports

    Shell

    Lists the two newest CSV files in the folder: this period and the last one.

  2. Analyze variances

    Claude Code · Sonnet

    Joins the two periods with a script, flags material changes and explains them from the files in the folder.

  3. Check the numbers

    Claude API · Opus 5

    A second model checks the arithmetic and that every claim is backed by the data.

    If it fails, goes back to Analyze variances, up to 2 times.

  4. Controller sign-off

    You

    Shows you the report. Reject with a comment and it is rewritten with your notes.

  5. Save report

    Shell

    Writes the approved report to the reports folder, named after the month.

Set it up

From copy to first run

  1. Copy the pipeline JSON with the button above.
  2. In Jimothy, open Pipelines → New pipeline, paste it under “Or import a pipeline JSON” and click Import.
  3. Under Workspace, choose the folder where you save each month’s trial balance exports.
  4. Fill in the variables below under Pipeline settings → Variables.
  5. 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.

Variables

What to fill in

The prompts and commands read these as {{vars.<name>}}. The examples are placeholders: replace them with your own.

VariableWhat to put in itExample
companyYour company name, used in the write-up.Acme Inc.
thresholdPercentFlag an account when its change is at least this many percent…10
minAmount…and at least this amount, in your reporting currency.5000
reportsFolderFolder (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\""
    }
  ]
}