Skip to main content

explain-my-variance

Tell me why a P&L line moved. I compare actuals against budget (if you have one), prior period, and same period prior year, decompose every material swing into price / volume / mix / one-time drivers tied to specific journal entries and vendors, and write a 3–5 paragraph narrative on the biggest movers. Materiality threshold defaults to 5% and $1k and is configurable per run. Unexplained residuals are surfaced, never quietly absorbed. Drafts only — I never re-classify or post to clean up a variance.

Jump to install

Source facts

Repository
gethouston/houston
Last source activity
September 16, 2026 at 16:49
Detected SKILL.md language
English
Stars
112
Forks
66

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
explain-my-variance
description
Tell me why a P&L line moved. I compare actuals against budget (if you have one), prior period, and same period prior year, decompose every material swing into price / volume / mix / one-time drivers tied to specific journal entries and vendors, and write a 3–5 paragraph narrative on the biggest movers. Materiality threshold defaults to 5% and $1k and is configurable per run. Unexplained residuals are surfaced, never quietly absorbed. Drafts only — I never re-classify or post to clean up a variance.
version
1
category
Bookkeeping
featured
no
image
ledger
x_houston
{"created_by":"houston","skill_schema":1}
# Explain My Variance Actuals vs. budget vs. prior period vs. same-period prior year. I decompose every material line into price / volume / mix / one-time drivers, each one tied to specific journal entry ids or transaction sets. The narrative focuses on the 3–5 biggest movers so you read a story, not a spreadsheet. Anything I can't explain, I label as residual rather than make up a cause. ## When to use - "why was operating expenses up in March" / "what drove revenue miss". - "compare actuals to budget for {period}". - "run variance analysis on {period}". - Called by `close-my-month` after `prepare-my-financials statement=pnl` wrote current-period P&L. ## Connections I need I run external work through Composio. Before this skill runs I check that the categories below are linked. Missing → I name the category, ask you to connect it from the Integrations tab, stop. - **No external connections required.** I work entirely from your existing journal entries, P&Ls, and budget file. This skill never blocks on a missing connection. ## Information I need I read your bookkeeping context first. For every required field that's missing I ask ONE plain-language question (best modality: connected app > file drop > URL > paste) and wait. - **The period to analyze** — Required. Why: defines the actuals window and which prior periods to compare against. If missing I ask: "Which period are we running variance on, e.g. March 2025 or Q1 2025?" - **A finished P&L for the period** — Required. Why: variance compares this period's P&L lines against baselines. If missing I ask: "Have we closed and generated the P&L for that period yet? If not, let's run that first." - **A chart of accounts** — Required. Why: I group variances by account code line and statement section from your chart of accounts. If missing I ask: "Do we have a chart of accounts yet? If not, let's draft one first." - **A current budget** — Optional. Why: lets me run actuals vs. budget alongside actuals vs. prior period. If you don't have one I keep going and note "no budget on file" in the report. - **At least one prior P&L (last month or same month last year)** — Optional but strongly preferred. Why: gives me a baseline to compare against. If you don't have one I report actuals only and flag that there's nothing to compare to yet. ## Steps <!-- houston-workflow:v1 --> 1. **Read context.** Load `context/bookkeeping-context.md`, `config/context-ledger.json` (for `domains.budget` - cadence + path), `config/chart-of-accounts.json`. Read `config/budget.json` if exists (`[{period, glCode, amount, note?}]`). 2. **Pick comparison baselines.** For requested `period` (`YYYY-MM` or `YYYY-QN`), assemble up to three baselines: - **Budget** - rows from `config/budget.json` for period. If absent, skip + note "no budget on file". - **Prior period** - `financials/{prior-YYYY-MM}/pnl.md` if present; else recompute on fly from `journal-entries.json`. - **Same period prior year** - `financials/{prior-YYYY-MM-12}/pnl.md` if present; else recompute. 3. **Load actuals for period.** Read period P&L from `financials/{YYYY-MM}/pnl.md` (generated by `prepare-my-financials`). If missing, recompute from `journal-entries.json` on fly + note canonical P&L not yet written. 4. **Compute variances per account code line.** For each account code line in any of: actuals, budget, prior period, prior year, compute: - `actual_minus_budget`, `pct_vs_budget` - `actual_minus_prior_period`, `pct_vs_prior_period` - `actual_minus_prior_year`, `pct_vs_prior_year` 5. **Apply materiality threshold.** Default: `abs(variance) > 5% AND abs(variance) > $1000`. Configurable per run via arg. Only material variances get driver decomposition. Non-material summarized in single table at bottom. 6. **Decompose each material variance into drivers.** Ground each driver in specific journal entries or transactions: - **Price** - same-quantity unit cost changed (e.g., SaaS vendor price increase). Cite journal entry ids where new price first appears. - **Volume** - more or fewer units at same unit price (e.g., more hosting spend because usage doubled). Cite transaction count vs. baseline + representative journal entry ids. - **Mix** - different blend of SKUs / vendors / categories. Cite entrant journal entries + exited vendors. - **One-time** - non-recurring (true-up, one-off refund, annual renewal booked in month). Cite journal entry id + memo. Each driver has: `{driver, amount, jeRefs: [id…], transactionRefs?: [ids…], narrative}`. `amount` must sum to total variance within $1.00. Unexplained residual logged explicitly - never silently absorbed. 7. **Write plain-English narrative on 3-5 biggest movers.** Narrative names each mover, dollar impact, primary driver, specific evidence (journal entry id or vendor or transaction set). No invented causes. Thin evidence → say so. "no obvious driver, recommend user review" acceptable. Speculation padding not. 8. **Write variance artifact.** Path: `variance-analyses/{YYYY-MM}.md`. Atomic write: `.tmp` → rename. Structure: - Header: period, baselines used, materiality threshold, accounting method. - **Headline** - 1-2 sentence summary (e.g., "Operating expenses +$45k (+12%) vs. budget, driven by hosting doubling and a one-time legal true-up"). - **Narrative** - 3-5 paragraphs on biggest movers, each citing journal entry ids / vendors / transaction counts. - **Material variances table** - one row per material account code line with actuals, each baseline, variance, driver decomposition. - **Non-material variances** - compact summary table. - **Unexplained residuals** - any driver decomposition not tied back within $1.00. - Footer: sources (P&L file path, budget file path, prior-period P&L paths, journal-entries.json hash). 9. **Append to `outputs.json`.** Read-merge-write. Row: `{id, type: "variance-analysis", title: "Variance - {YYYY-MM}", summary: "<the headline>", path: "variance-analyses/{YYYY-MM}.md", status: "draft", domain: "reporting"}`. 10. **Summarize to user.** One paragraph: headline + 3-5 biggest movers with dollar impact + primary driver, plus unexplained residuals needing review. Point at written file. ## Outputs - `variance-analyses/{YYYY-MM}.md` - `outputs.json` row: `type: "variance-analysis"`, `domain: "reporting"`, `status: "draft"` until user signs off.
View on GitHub