CommunityResearch & Data Analysisgithub.com

jasveerai88/gst-hst-tracker

Track GST/HST for Canadian freelancers and sole proprietors from a JSON/CSV ledger — per-calendar-quarter GST/HST collected, ITCs, and net tax owing (collected − ITCs) with a T2125-style prep section, the small-supplier alarm (rolling last-4-calendar-quarters taxable income vs the $30,000 registration threshold with exact headroom), and a per-province view (tax system, collected, ITCs, net per province; recorded QST memo figures; PST/RST exposure estimates). Use when preparing GST/HST figures, checking ITCs, monitoring the registration threshold, or seeing place-of-supply exposure province by province. A tracking aid, NOT tax advice and NOT a CRA filing; rates are Nov-2026 defaults, overridable — never present them as live fact.

What is gst-hst-tracker?

gst-hst-tracker is a Claude Code agent skill that track GST/HST for Canadian freelancers and sole proprietors from a JSON/CSV ledger — per-calendar-quarter GST/HST collected, ITCs, and net tax owing (collected − ITCs) with a T2125-style prep section, the small-supplier alarm (rolling last-4-calendar-quarters taxable income vs the $30,000 registration threshold with exact headroom), and a per-province view (tax system, collected, ITCs, net per province; recorded QST memo figures; PST/RST exposure estimates). Use when preparing GST/HST figures, checking ITCs, monitoring the registration threshold, or seeing place-of-supply exposure province by province. A tracking aid, NOT tax advice and NOT a CRA filing; rates are Nov-2026 defaults, overridable — never present them as live fact.

Works with~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/jasveerai88/gst-hst-tracker/tree/HEAD

Installed? Explore more Research & Data Analysis skills: affaan-m/uspto-database, affaan-m/scholar-evaluation, affaan-m/literature-review · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

gst-hst-tracker — agent skill

Purpose

Canadian freelancers and sole proprietors track GST/HST in spreadsheets and discover CRA's $30,000 small-supplier threshold after crossing it. This tool reads a dated transaction ledger and produces (a) per-quarter GST/HST collected, ITCs and net tax owing with a T2125-style income/expense prep section, (b) the threshold test: rolling last-4-calendar-quarters taxable income against the $30,000 limit, with headroom or a crossed alarm, and (c) a per-province view of the same ledger: tax system, collected, ITCs and net per province, with the provincial component shown only as far as the data supports it (recorded QST as memo figures plus an estimate on unrecorded QC sales; PST/RST as rate×sales exposure estimates). Pure Python standard library; local only; reads one ledger file, writes nothing.

The honesty core of this tool: it is a tracking and calculation aid, not tax advice and not a CRA filing. Every report carries that disclaimer, and so must anything you write from its output. It never computes penalties or interest.

When to use / not use

Use when:

  • Preparing a quarter's GST/HST figures from a transaction ledger: collected, ITCs, net owing.
  • Checking how close a freelancer is to the $30,000 registration threshold, or whether they crossed it.
  • Organizing income and expense categories into a T2125-style prep view for filing season.
  • An agent needs Canadian GST/HST numbers it can trust in JSON.

Do NOT use when:

  • The user needs tax advice, a filing, or a ruling on their obligations — this tool cannot give one. Point them at the CRA or a qualified accountant.
  • The question involves penalties or interest — never computed.
  • The books are Quebec QST books: QST is memo-only here (see Limits). BC PST / SK PST / MB RST appear only as exposure estimates in the provinces view — never as taxes owed or credits.
  • The ledger is stale: the threshold window is anchored to the latest transaction, so a stale ledger gives a stale window. Say so if the dates look old.

Install

pipx install git+https://github.com/jasveerai88/gst-hst-tracker
# or: pip install git+https://github.com/jasveerai88/gst-hst-tracker

(Not on PyPI — the git+ form is the install.) From a source checkout, python3 src/gst_hst_tracker.py ... is equivalent.

Commands

# Quarterly report (JSON or CSV input; exit 0 on success)
gst-hst-tracker report LEDGER.json
gst-hst-tracker report LEDGER.csv --json

# One calendar quarter or one year only
gst-hst-tracker report LEDGER.json --period 2026-Q1
gst-hst-tracker report LEDGER.json --period 2026

# The small-supplier alarm (exit 1 when crossed, 0 otherwise)
gst-hst-tracker threshold LEDGER.json [--limit 30000]

# The provincial view (exit 0 on success)
gst-hst-tracker provinces LEDGER.json
gst-hst-tracker provinces LEDGER.json --period 2026-Q1 --json

# Also display INR equivalents (rate per 1 CAD)
gst-hst-tracker report LEDGER.json --cad-to-inr 67.97

# Override a province rate when it changes
gst-hst-tracker report LEDGER.json --rate NS=15

Input rows (JSON list, {"transactions": [...]} object, or CSV with the same headers): date (YYYY-MM-DD, required), kind (income|expense, required), description (required), amount (pre-tax CAD, required, ≥ 0), province (two-letter code, required); optional tax (GST/HST charged/paid — omit to compute from the province rate; 0 means zero-rated and is respected), qst (QC rows only; tracked separately, never in the net), category (expenses only; T2125-style grouping).

The model (state it when you report results)

  • Net tax owing per calendar quarter = GST/HST collected on income − ITCs (GST/HST paid on expenses). Negative net = ITCs exceed collections: a refund position, not cash in hand.
  • Threshold: taxable supplies (income rows only) over the last 4 calendar quarters ending at the latest transaction's quarter. CRA's test is exceeds $30,000 — exactly $30,000 is still a small supplier (status: "at", exit 0).
  • Rate defaults as of 2026-11: GST 5% (AB BC MB NT NU SK YT), HST 13% ON, HST 15% NB/NL/PE, HST 14% NS (lowered from 15% on 2025-04-01), QC = GST 5% federal part only.
  • QST (9.975%) is a separate Revenu Québec tax: supplied qst amounts appear as memo totals only and never enter the net.
  • Provincial view (provinces): the same federal math grouped by the row's province. Encoded provincial taxes, stamped "Encoded rates, checked 2026-11 — verify against CRA/provincial sources before filing": QST 9.975% (QC), PST 7% (BC), PST 6% (SK), RST 7% (MB); HST provinces have no separate provincial component. QC shows recorded QST totals plus an estimate on QC income rows with no recorded qst; BC/SK/MB show a rate×sales exposure estimate only, and no provincial ITC (PST/RST on inputs is generally a cost). Rounding: per-province figures are rounded to cents and the summary sums those rounded figures, so it always reconciles with the province blocks.

Output JSON schema (--json)

report: tool ("gst-hst-tracker"), version, command ("report"), file, currency ("CAD"), rates (per-province rate_pct + label, stamped as_of: "2026-11", plus the QST note), cad_to_inr (rate or null), period_filter (string or null), periods, totals, disclaimer.

Each period: period (e.g. "2026-Q1"), quarter ([2026, 1]), income_total, expense_total, gst_hst_collected, itcs, net_tax_owing, qst_collected, qst_paid, transactions, t2125 (gross_business_income, expenses_by_category, total_expenses). totals sums the same fields across the periods shown. With --cad-to-inr, money fields gain *_inr siblings.

threshold: the common fields plus latest_transaction, window_end_quarter, quarters (four {quarter, income} entries, oldest first), rolling_total, limit, headroom (0 when crossed), over_by (0 when not crossed), crossed (bool), status ("under" | "at" | "crossed"), rule, disclaimer.

provinces: the common fields plus provincial_rates (stamp, qst_rate_pct, taxes — per-province federal label and provincial_tax {name, rate_pct} or null), rounding_rule, provinces, totals, disclaimer. Each entry in provinces: province, tax_system (built from the effective rates, e.g. "GST 5% + PST 7%"), income_total, expense_total, gst_hst_collected, itcs, net_tax_owing, transactions, and provincial — null for GST-only and HST provinces; otherwise {name, rate_pct, recorded_collected, recorded_paid, recorded_net} (numbers for QC, null for BC/SK/MB — nothing is recorded for those), estimate_base, estimated_on_sales, note. totals adds qst_recorded_collected / qst_recorded_paid / qst_recorded_net and provincial_estimated_on_sales.

On error, stdout is a single object: {"error": "<message>"} (validation errors name the row: "row 2: ...") with exit code 2 — including argparse usage errors in --json mode. Never plain text, never a traceback.

Exit codes

  • report: 0 — report computed. 2 — error.
  • provinces: 0 — view computed. 2 — error. (No exit-1 state: the view is informational; the alarm lives in threshold.)
  • threshold: 0 — rolling total is under or exactly at the limit: still a small supplier on these figures. 1 — THRESHOLD CROSSED: the rolling total exceeds the limit and GST/HST registration is required. This is a finding, not a failure: surface it prominently. 2 — error: no numbers were produced; do not quote any.
  • Errors in either command exit 2 with a clean message (or the {"error": ...} object in --json mode).

Limits & honesty rules the agent must respect

  • Not tax advice, not a filing. Never present this tool's output as advice or as a filed return. The disclaimer in every output is load-bearing: keep it attached to any summary you write.
  • The rates are defaults as of 2026-11, not live facts. Cite them as "the tool's Nov-2026 defaults" and note they are overridable. Nova Scotia is 14% (it was 15% until 2025-03-31) — if a user's figures were computed at 15% for NS, that is worth flagging, not silently accepting.
  • Exactly at $30,000 is NOT crossed. CRA's test is "exceeds $30,000". If status is "at", report "still a small supplier, zero headroom" — never "must register".
  • Exit 1 from threshold is the tool working. It means the alarm fired. Report the rolling total, the amount over, and that registration is required — promptly, not buried.
  • QST never enters the net. If you summarize Quebec rows, keep QST as a separate memo figure. Do not add QST collected to net_tax_owing, and do not treat QST paid as an ITC.
  • Provincial estimates are estimates. The provinces view's PST/RST figures and the QST figure on unrecorded Quebec sales are rate×sales estimates from the encoded table — never present them as amounts collected, owed, or filed, and always carry the encoded-rates stamp ("checked 2026-11 — verify against CRA/provincial sources before filing") when you quote the rates. PST/RST paid on inputs is never an ITC in this tool.
  • A negative net is a refund position, not income. Do not describe it as money received.
  • Penalties and interest are never computed — if the user crossed in an earlier period, that is a CRA/accountant conversation; do not estimate an amount.
  • Local only: the tool reads the file you point it at and sends nothing anywhere.

Related Skills