From revolut-pit-tax
Calculate Polish capital gains tax (PIT-38) from a Revolut consolidated statement and NBP average exchange rate table. Use this skill whenever the user uploads a Revolut brokerage statement (PDF) and/or an NBP exchange rate file (CSV) and wants to determine tax obligations for Polish PIT-38 filing. Also trigger when the user mentions: Revolut tax, PIT-38 from Revolut, Polish tax on foreign stocks, rozliczenie Revolut, podatek od zysków kapitałowych Revolut, dywidendy Revolut PIT, or any combination of Revolut + Polish tax filing. This skill covers both capital gains from stock sales and dividend income from foreign securities held via Revolut.
How this skill is triggered — by the user, by Claude, or both
Slash command
/revolut-pit-tax:calculateThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
This skill processes a Revolut consolidated brokerage statement (PDF) and an NBP average exchange
This skill processes a Revolut consolidated brokerage statement (PDF) and an NBP average exchange rate table (CSV) to produce tax-ready figures for Polish PIT-38 filing, including the PIT/ZG attachment for foreign-sourced income.
Revolut, as a foreign broker (Revolut Securities Europe UAB, Lithuania), does not issue a PIT-8C. The taxpayer must manually calculate all amounts in PLN and file them. This skill automates that calculation.
Revolut Consolidated Statement (PDF) — downloaded from the Revolut app under Invest → More → Documents. Contains sells summary, dividend details, cost basis (FIFO), and exchange rates used by Revolut (which are NOT the rates to use for tax purposes). If input is missing — DO NOT perform any actions; request the user to provide it.
NBP Average Exchange Rate Table (CSV) — already bundled with this skill at
./resources/kursy.csv (relative to this SKILL.md file). Always use this file directly —
do NOT ask the user to provide an NBP rate table. The file covers the full tax year 2025
and contains columns: date, USD rate, EUR rate.
Before starting, read resources/pit38-rules.md for the complete set of Polish tax rules
that govern this calculation. The critical points are:
Read resources/revolut-statement-format.md for the exact structure of Revolut's PDF and
how to extract data from it.
Revolut PDF: Extract two transaction tables:
The PDF already contains PLN equivalents and Revolut's exchange rates — ignore these. Extract only the USD (or EUR) amounts and recalculate PLN values yourself.
NBP CSV: Always load from ./resources/kursy.csv (path relative to this SKILL.md).
Parse into a date→rate lookup dictionary. Handle Polish number formatting (comma as decimal
separator). The CSV has header and footer rows to skip (non-date rows).
Important: If the Revolut statement contains transactions with purchase dates from a
prior year, ./resources/kursy.csv will not contain rates for those dates. In this case:
For each transaction, determine the correct NBP rate:
def get_nbp_rate_before(date, rates_dict):
"""Get NBP average rate from the last business day BEFORE the given date."""
d = date - timedelta(days=1)
while d not in rates_dict:
d -= timedelta(days=1)
if (date - d).days > 10:
raise ValueError(f"No NBP rate found within 10 days before {date}")
return rates_dict[d], d
For stock sales:
For dividends:
Group results for PIT-38 sections:
| PIT-38 Section | Content |
|---|---|
| Section C/E | Capital gains from stock sales (przychód, koszty, dochód) |
| Section F | Dividend income (przychód brutto, podatek zagraniczny, podatek do zapłaty) |
Group results for PIT/ZG attachments — one per country:
Capital gains (Section C/E):
podatek = ROUND(dochód × 0.19, 0) # rounded to full PLN
Dividends (Section F):
podatek_PL = ROUND(przychód_brutto × 0.19, 0)
odliczenie = min(podatek_zagraniczny, podatek_PL) # cannot exceed PL tax
do_zapłaty = podatek_PL − odliczenie
After extracting data from the Revolut PDF, write two JSON files and run the calculation script:
sells.json — array of stock sale records:
[
{
"name": "Fox Corporation (FOXA)",
"country": "US",
"currency": "USD",
"purchase_date": "2024-07-08",
"sale_date": "2025-03-10",
"qty": "2",
"cost_usd": "69.46",
"proceeds_usd": "109.47",
"fees_usd": "1.05",
"cost_rate_override": "3.941"
}
]
cost_rate_override is optional — only include when purchase_date falls outside the NBP CSV
date range. Use the Revolut-stated rate as fallback and flag it prominently in the output.
dividends.json — array of dividend records:
[
{
"date": "2025-03-27",
"name": "Fox Corporation",
"symbol": "FOXA",
"country": "US",
"currency": "USD",
"gross_usd": "0.77",
"tax_usd": "0.12"
}
]
All numeric amounts must be strings (not JSON numbers) to preserve decimal precision.
Dates must be ISO 8601: "YYYY-MM-DD". For empty sections (no sells or no dividends), pass [].
Run:
python scripts/calculate_pit.py \
--nbp resources/kursy.csv \
--sells sells.json \
--dividends dividends.json
The script outputs a single JSON object to stdout. Capture and parse it — all further output (XLSX, PDF) is generated from this structured data.
Generate two deliverables (use the xlsx and pdf skills as appropriate):
XLSX workbook with three sheets:
PDF report — print-ready version with the same three sections, formatted with tables and highlighted summary boxes showing amounts to enter in PIT-38.
Both outputs should include:
| File | When to Read |
|---|---|
resources/pit38-rules.md | Always — contains Polish tax law specifics |
resources/revolut-statement-format.md | When parsing the Revolut PDF |
./resources/kursy.csv | NBP mean exchange rates — bundled, always use this directly |
scripts/pit_lib.py | Reference for calculation logic (NBP lookup, PLN conversion, tax math) |
scripts/calculate_pit.py | CLI runner — call this with sells.json + dividends.json to get JSON results |
npx claudepluginhub budzikt/revolut-pit-taxImports Wise (TransferWise) CSV transaction exports into accounting systems, handling multi-currency transfers, conversion fees, deduplication by ID, and categorization.
Manages German tax reports including VAT (Umsatzsteuer), income tax prepayments, and Finanzamt submissions via ELSTER. Lists statuses, previews filings, submits on confirmation. For tax queries.
Guides users through a complete German personal income tax return intake for ELSTER (tax years 2024+), including questionnaire, tax estimate, and form-by-form field mapping.