
Pt Irs Runbook
- 65 installs
- 191 repo stars
- Updated July 24, 2026
- pproenca/dot-skills
pt-irs-runbook is a Claude Code skill for ai & agent building.
About
pt-irs-runbook is a Claude Code skill for ai & agent building. It helps solo builders move faster with AI-assisted coding.
- pt-irs-runbook
- AI & Agent Building
- AI-coding skill
Pt Irs Runbook by the numbers
- 65 all-time installs (skills.sh)
- +7 installs in the week ending Aug 4, 2026 (Skillselion tracking)
- Ranked #6,043 of 16,546 AI & Agent Building skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/pproenca/dot-skills --skill pt-irs-runbookAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 65 |
|---|---|
| repo stars | ★ 191 |
| Last updated | July 24, 2026 |
| Repository | pproenca/dot-skills ↗ |
How do I helps with ai & agent building tasks during AI-assisted development.?
Helps with ai & agent building tasks during AI-assisted development.
Who is it for?
Best when you're working on ai & agent building and need structured help with pt irs runbook.
Skip if: Teams with no ai & agent building needs, or anyone wanting a generic chat assistant without this specific workflow.
When should I use this skill?
When you need to helps with ai & agent building tasks during AI-assisted development., or when pt-irs-runbook is a claude code skill for ai & agent building.
What you get
Structured output aligned to pt-irs-runbook: pt-irs-runbook, AI & Agent Building.
Files
Portugal IRS Filing Runbook
A diagnostic runbook for Portuguese personal income tax (IRS). Each symptom is a filing situation; each decision tree routes from the situation to the correct annex, autonomous rate, and deadline, then terminates in a concrete filing action or a clear "escalate to a contabilista certificado for {reason}".
Not tax advice. This skill encodes the CIRS and Portal das Finanças rules as
verified on the cited dates. Tax rates and thresholds change with each Orçamento
do Estado. Always confirm figures against the live Art. 68/72 text and the
official Modelo 3 / IRS automático screens before submitting, and involve a
contabilista certificado for anything non-routine. Default income year is
2025 (return filed 1 Apr – 30 Jun 2026) unless stated otherwise.
When to Apply
- The user asks how to file a Modelo 3 (PT annual income tax return) or which
annexes apply to their income.
- The user needs to know whether they are a PT tax resident or non-resident,
and what that changes.
- The user receives Portuguese-source income — rent, a property/share sale,
salary, pension, or self-employment fees — and must declare it.
- The user is a non-resident landlord (or has foreign income as a resident)
and needs the right rate plus double-taxation relief.
- The user asks about a specific PT regime: **IRS automático, IRS Jovem, IFICI
(the post-NHR regime), englobamento, mais-valias reinvestment**.
This skill is Portugal-specific. For UK/other-country filing it is out of scope (though it covers the PT side of a cross-border situation, e.g. PT rental income that also appears on a UK SA106).
How to Use
1. Always start at residency. Read residency-tree. Residency status (Art. 16) determines the entire regime — worldwide vs PT-source-only income, progressive vs flat rates, deductions vs none. 2. Then check whether a return is even required and which annexes: filing-obligation-tree. 3. Open the tree for each income type the user has. A taxpayer often needs several annexes at once. 4. Look up every rate/threshold in one place: rates-and-deductions.md is the single source of truth; the trees link to it rather than restating numbers. 5. Estimate figures deterministically with the calculators in references/queries/ (day-count, rental tax, capital gain), then verify on Portal das Finanças. 6. Summarise the outcome with assets/templates/report.md.
Common Symptoms
| # | Symptom / Question | Entry tree | Priority |
|---|---|---|---|
| 1 | "Am I resident or non-resident — and what changes?" | residency-tree | P1 (gateway) |
| 2 | "Do I have to file? Can I accept IRS automático? Which annexes?" | filing-obligation-tree | P1 (router) |
| 3 | "I receive rent from a PT property" (Categoria F) | rental-income-tree | P1 |
| 4 | "I sold a property or shares" (Categoria G / mais-valias) | capital-gains-tree | P1 |
| 5 | "I have salary or a pension" (Categoria A / H) | employment-pension-tree | P2 |
| 6 | "I'm self-employed / recibos verdes" (Categoria B) | self-employment-tree | P2 |
| 7 | "I have foreign income / risk of double taxation" (Anexo J) | foreign-income-tree | P2 |
Usual suspects — the mistakes a default answer makes
| Wrong default | Reality | Where |
|---|---|---|
| "Rental income is taxed at the progressive scale" | Cat F has its own autonomous rate (25% base, lower for long leases); englobamento is optional | rental-income-tree |
| "A 2-year lease gets a reduced rental rate" | The Art. 72 reductions start at 5-year permanent-housing contracts; under 5 years = 25% | rates-and-deductions.md |
| "Non-residents pay 28% on the whole property gain" | Since 2023 non-residents get the 50% inclusion + progressive rates, like residents | capital-gains-tree |
| "Just sign up for NHR" | NHR is closed to new arrivals; the current regime is IFICI with much narrower eligibility | foreign-income-tree |
| "A non-resident must appoint a fiscal representative" | Optional if you adhere to electronic notifications; always optional for EU/EEA residents | filing-obligation-tree |
Setup
On first use, populate config.json with the taxpayer's situation (residence country, fiscal representative status, applicable tax treaty, NIF). If a required field is empty, ask the user, then save it. Never store passwords — login to Portal das Finanças is interactive.
Gotchas
Diagnostic dead-ends and portal quirks accumulate in gotchas.md. Read it before a non-trivial filing.
Related Skills
- A UK Self Assessment / SA106 runbook would complement this for the cross-border
(PT rental → UK FTCR) case — not part of this skill.
IRS Filing Summary: {taxpayer} — income year {year}
Date prepared: {date} Prepared by: {agent/user} Filing window: 1 Apr – 30 Jun {year+1} Status: Draft / Ready to submit / Submitted ({submission date})
Summary
{1–2 sentences: residency status, the annex set, and the headline tax/refund estimate.}
Taxpayer status
- Residency (Art. 16): {resident | non-resident | partial-year — period dates}
- Residence country / treaty: {country} / {applicable DTT}
- Fiscal representative: {required+appointed | optional via e-notifications | n/a}
- IRS automático eligible: {yes/no — reason}
Income by category
| Category | Annex | Gross | Deductions/base | Rate basis | Est. tax |
|---|---|---|---|---|---|
| {A – employment} | A | {EUR} | {EUR} | {progressive / Jovem} | {EUR} |
| {F – rental} | F | {EUR} | {expenses} | {Art. 72 X%} | {EUR} |
| {G – capital gains} | G/G1 | {EUR} | {50% base} | {progressive} | {EUR} |
| {B – self-employment} | B/SS | {EUR} | {coefficient} | {progressive} | {EUR} |
| {J – foreign income} | J | {EUR} | {credit Art. 81} | {progressive} | {EUR} |
Annexes to submit
- [ ] Rosto (always; quadro 8-C if partial-year)
- [ ] Anexo {…}
- [ ] Anexo {…}
Decisions taken
- {e.g. "Cat F: kept 25% autonomous rate; englobamento not elected — marginal rate
higher than 25%."}
- {e.g. "Cat G: applied 50% inclusion; reinvestment exemption {claimed/not}."}
Estimated outcome
- Estimated tax due / refund: {EUR} (estimate — confirm in the official
simulator before submitting)
- Payment deadline if due: 31 Aug {year+1}
Open items / escalations
- [ ] {Item needing a contabilista certificado, with the specific reason}
- [ ] {Document to gather — e.g. inflation coefficient Portaria, foreign tax
certificate, recibos de renda}
Verification
- [ ] Figures cross-checked against rates-and-deductions.md
- [ ] Pre-filled values reviewed on Portal das Finanças
- [ ] Submitted and confirmation reference saved: {ref}
{
"income_year": "2025",
"residence_status": "",
"residence_country": "",
"has_fiscal_representative": "",
"adheres_to_electronic_notifications": "",
"applicable_tax_treaty": "",
"nif_last_digits": "",
"portal_modelo3_url": "https://www.portaldasfinancas.gov.pt/at/html/index.html",
"portal_efatura_url": "https://faturas.portaldasfinancas.gov.pt/",
"cirs_index_url": "https://info.portaldasfinancas.gov.pt/pt/informacao_fiscal/codigos_tributarios/cirs_rep/Pages/codigo-do-irs-indice.aspx",
"_setup_instructions": {
"income_year": "Tax year being filed (income earned). 2025 income is filed between 1 Apr and 30 Jun 2026.",
"residence_status": "resident | non-resident | partial-year — determined via references/residency-tree.md (Art. 16 CIRS).",
"residence_country": "Country of tax residence (ISO name). Drives the applicable double-taxation treaty and the EU/EEA option to be taxed as a resident (Art. 17-A).",
"has_fiscal_representative": "true|false — whether a representante fiscal is appointed in PT (Art. 19 LGT). Optional if electronic notifications are active, or for EU/EEA residents.",
"adheres_to_electronic_notifications": "true|false — adhesion to the public electronic notification service / ViaCTT, which exempts the fiscal-representative requirement.",
"applicable_tax_treaty": "Name of the relevant Convenção para Evitar a Dupla Tributação (e.g., 'Portugal-United Kingdom DTT'). Used by foreign-income-tree.md.",
"nif_last_digits": "Last 3 digits of the NIF for disambiguation only — never store the full NIF or any password here."
}
}
Gotchas — PT IRS filing
Diagnostic dead-ends and Portal das Finanças quirks. Append-only, with dates.
Tenant with a Portuguese NIF → set country = Portugal, not their nationality
When declaring a tenant (or any counterparty) on Portal das Finanças, the country field follows the NIF's country, not the person's passport. A Spanish or Italian tenant who holds a PT NIF is entered as Portugal. Foreign country + passport number is only for counterparties with no PT NIF. Picking the nationality instead silently rejects or mis-files the record. Added: 2026-05-24
The rental rate ladder has no 2–5 year tier
A common wrong assumption is that any multi-year lease earns a reduced Cat F rate. Under Art. 72 the reductions only begin at permanent-housing contracts ≥5 years (−10pp → 15%). Contracts under 5 years are taxed at the 25% base, whether the finalidade is H_PERM or H_NPER — the H_PERM/H_NPER choice makes no rate difference at a 2-year term. The "−2pp" some sources mention is a renewal bonus inside the 5–10 year tier, not a sub-5-year rate. Added: 2026-05-24
OE2026's 10% rate is for income year 2026, not the 2025 return being filed now
The OE2026 moderate-rent 10% rate (rent ≤ ~€2,300/mo, permanent housing) applies to income earned after the law's entry into force — i.e. the return filed in 2027. Do not apply it to the 2025-income Modelo 3 due 30 Jun 2026. Added: 2026-05-24
Cat F expenses exclude mortgage interest and furniture
Deductible Cat F expenses (Art. 41) are conservation/maintenance, condomínio, IMI, and insurance. Since 2015 mortgage interest, capital repayment, and furniture are NOT deductible against rental income — a frequent over-claim. Added: 2026-05-24
Non-residents: rental income has no withholding, so a return is mandatory
Individual tenants do not withhold (sem retenção, Art. 101). Because the PT-source rental income is therefore not taxed by final withholding, a non-resident landlord must file a Modelo 3 with Anexo F — they are not covered by the "only income subject to final withholding → no return" exemption. Added: 2026-05-24
{
"version": "0.1.0",
"organization": "dot-skills",
"technology": "Portugal Personal Income Tax (IRS / CIRS) and Modelo 3 filing",
"discipline": "investigation",
"type": "runbook",
"date": "May 2026",
"abstract": "A diagnostic runbook for filing the Portuguese IRS (Modelo 3). Maps filing situations — residency status, rental income (Cat F), capital gains (Cat G), employment/pensions (Cat A/H), self-employment (Cat B), and foreign income (Anexo J) — to decision trees that resolve the correct annex, the current Art. 72 autonomous rate, deductions, and Portal das Finanças deadlines. Covers residents and non-residents, including non-resident landlords and double-taxation relief. Verified against the CIRS and OE2025/OE2026 as of May 2026.",
"references": [
"https://info.portaldasfinancas.gov.pt/pt/informacao_fiscal/codigos_tributarios/cirs_rep/Pages/codigo-do-irs-indice.aspx",
"https://info.portaldasfinancas.gov.pt/pt/informacao_fiscal/codigos_tributarios/cirs_rep/Pages/irs72.aspx",
"https://info.portaldasfinancas.gov.pt/pt/informacao_fiscal/codigos_tributarios/cirs_rep/Pages/irs68.aspx",
"https://info.portaldasfinancas.gov.pt/pt/apoio_ao_contribuinte/Cidadaos/Rendimentos/Declaracao/Modelo_3/Paginas/default.aspx",
"https://info.portaldasfinancas.gov.pt/pt/apoio_ao_contribuinte/Cidadaos/Rendimentos/Declaracao/IRS_automatico/Paginas/default.aspx",
"https://info.portaldasfinancas.gov.pt/pt/apoio_contribuinte/Folhetos_informativos/Documents/Folheto_IRS_jovem_2025.pdf"
]
}
Decision Tree: Capital gains — Categoria G (Anexo G / G1)
For disposals of real estate and securities by an individual. Base computation and rates: rates-and-deductions.md §2, §4. Property-gain estimator: queries/property-capital-gain.py.
START: an asset was disposed of (sold, exchanged, or contributed) in the year.
│
├── Q1. What was disposed?
│ │
│ ├── Real estate (or rights over it) ──► Q2.
│ ├── Shares / securities / units ──────► Q6.
│ └── Other (crypto held <365 days, IP, etc.) ──► ESCALATE: rules vary by asset
│ and holding period; confirm the specific Art. 10 category.
│
├── Q2. Acquisition date of the property?
│ │
│ ├── Before 1 Jan 1989 ──► EXEMPT (pre-CIRS). Terminal: report on **Anexo G1**
│ │ (exempt gains) for the record; no tax on the gain.
│ └── 1989 or later ──► Q3.
│
├── Q3. Compute the GAIN. Run property-capital-gain.py with:
│ realisation value, acquisition value × inflation coefficient (current
│ Portaria), acquisition + disposal costs, and improvement costs (last 12 yrs).
│ │ Expected output: the gross gain and the taxable 50%.
│ │
│ └──► Q4.
│
├── Q4. Was the property the taxpayer's OWN PERMANENT HOME and are proceeds being
│ reinvested in another own permanent home (PT/EU/EEA)?
│ │ Window: 24 months before to 36 months after the sale; declare the intent.
│ │
│ ├── Fully reinvested ──► EXEMPT on the reinvested portion. Terminal: report the
│ │ sale and the reinvestment intent/amount on Anexo G so the exemption is
│ │ applied; any non-reinvested portion stays taxable (continue Q5 on it).
│ ├── Partially reinvested ──► taxable on the non-reinvested proportion. Q5.
│ ├── Not a permanent home, or no reinvestment ──► fully taxable. Q5.
│ └── Reinvestment spans multiple years / mortgage-discharge variant ──► ESCALATE.
│
├── Q5. Tax the taxable gain (real estate): **50% inclusion + progressive scale**.
│ │ Applies to BOTH residents and non-residents (post-2023). The 50% is
│ │ englobado at Art. 68; a non-resident declares worldwide income to set the
│ │ rate band only.
│ │
│ └── Terminal ACTION: submit **Anexo G** with the acquisition/realisation values,
│ costs, improvements, and (if any) reinvestment. Expect tax on 50% of the gain
│ at the average Art. 68 rate. Record with assets/templates/report.md.
│
└── Q6. Securities / shares.
│
├── Net result is a LOSS ──► report on Anexo G; losses may offset/ carry forward
│ (5 years) only if englobamento is elected. Terminal: file Anexo G.
├── Net GAIN, default ──► 28% flat (Art. 72). Terminal: file Anexo G; tax = 28%
│ of the net gain.
└── Held < 365 days AND taxpayer's taxable income reaches the top Art. 68 bracket
──► MANDATORY englobamento of the short-term gain (anti-speculation rule).
Terminal: file Anexo G with englobamento; gain taxed at the progressive
scale. If unsure whether the threshold is met ──► ESCALATE.Usual suspects (most frequent first)
1. Applying 28% to a non-resident's property gain. Since 2023 it is 50% inclusion + progressive — usually lower than the old 28%-on-100%. 2. Forgetting the inflation coefficient on the acquisition value — it materially reduces the gain for older properties. 3. Missing the permanent-home reinvestment exemption or its declaration of intent. 4. Omitting improvement costs / acquisition & disposal costs (IMT, notary, agent commission) that reduce the gain.
Decision Tree: Employment & pensions — Categoria A / H (Anexo A)
Salary (Cat A) and pensions (Cat H) both report on Anexo A and share the €4,104 specific deduction. Rates and IRS Jovem terms: rates-and-deductions.md §3, §6, §7.
START: the taxpayer received salary, wages, or a pension in the year.
│
├── Q1. Resident with ONLY Cat A/H PT income and standard deductions?
│ │
│ ├── Yes ──► IRS automático almost certainly applies. Go to
│ │ filing-obligation-tree.md Q4 to review and accept the pre-filled return.
│ └── No (also has F/G/B/J, or wants a benefit not pre-filled) ──► Q2.
│
├── Q2. Is the taxpayer eligible for IRS Jovem (age ≤ 35, within the 10-year
│ window, Cat A/B income)?
│ │
│ ├── Yes ──► apply the year-based exemption (100% / 75% / 50% / 25%) up to the
│ │ 55-IAS cap. Terminal: on Anexo A, flag the IRS-Jovem year so the
│ │ exemption is applied; keep proof of first-income year. If the year
│ │ sequence is unclear (gaps, prior partial use) ──► ESCALATE.
│ └── No ──► Q3.
│
├── Q3. Any severance / contract-termination compensation, or stock-based pay?
│ │
│ ├── Yes ──► ESCALATE: the exempt portion of severance (Art. 2 §4) and the
│ │ valuation of equity comp need case-specific treatment.
│ └── No ──► Q4.
│
└── Q4. Non-resident with PT employment income?
│
├── Taxed by final withholding at source and nothing else due ──► NO RETURN
│ (confirm via filing-obligation-tree.md). Terminal.
└── Otherwise ──► Terminal ACTION: submit **Anexo A** with the income and PT
withholding already deducted at source; the €4,104 specific deduction
applies. Combine with any other annexes from the assembly step. Record with
assets/templates/report.md.Usual suspects
1. Accepting IRS automático when other income exists. It only covers a clean Cat A/H situation — rental or gains make it wrong. 2. Missing IRS Jovem for a young worker, or mis-sequencing the exemption year. 3. Pensions filed in the wrong place. Cat H goes on Anexo A, not a separate pension annex.
Decision Tree: Do I file, IRS automático, and which annexes?
Run this after residency-tree.md. It decides whether a return is required at all, whether the pre-filled IRS automático can be accepted, and which annexes the Modelo 3 needs. Deadlines and the calendar: rates-and-deductions.md §8.
START: residency known (resident / non-resident / partial-year)?
│
├── NON-RESIDENT branch
│ │
│ ├── Q1. Is ALL PT-source income taxed by final withholding
│ │ (retenção a título definitivo)? e.g. some dividends/interest taxed at
│ │ source with no further obligation.
│ │ │
│ │ ├── Yes, and nothing else ─────► NO RETURN DUE. Terminal: confirm nothing
│ │ │ else is PT-source; advise no Modelo 3 is required.
│ │ │
│ │ └── No — there is PT-source income NOT finally withheld
│ │ (rent is the classic case: individual tenants don't withhold,
│ │ Art. 101) ──► MUST FILE Modelo 3. Go to Q3 (annex assembly).
│ │
│ └── Q2. Fiscal representative (Art. 19 LGT) — needed?
│ │
│ ├── Resident in EU/Norway/Iceland/Liechtenstein ──► OPTIONAL. Terminal:
│ │ no representative required; electronic notifications optional.
│ ├── Adheres to electronic notifications (ViaCTT / public e-notification) ──►
│ │ OPTIONAL. Terminal: adhesion satisfies the duty; no representative.
│ ├── Non-EU/EEA, no e-notification adhesion ──► REQUIRED. Terminal: appoint a
│ │ representante fiscal before filing.
│ └── Non-resident with a VAT-liable self-employment activity in PT ──►
│ REQUIRED and the representative must be a PT-resident VAT taxpayer;
│ e-notification does NOT waive it. Escalate to a contabilista.
│
├── RESIDENT branch
│ │
│ ├── Q3. Below the dispensa thresholds (Art. 58)? — only income subject to final
│ │ withholding, or total income under the legal minimum, no other duties.
│ │ │
│ │ ├── Yes ──► NO RETURN DUE. Terminal: confirm no Cat F/G/B income and no
│ │ │ obligation triggers; advise no Modelo 3 required.
│ │ │
│ │ └── No ──► a return is due. Go to Q4.
│ │
│ ├── Q4. IRS automático offered AND the situation is fully covered by it?
│ │ Covered: residents with only Cat A/H (and certain simple Cat B
│ │ simplified) income, PT-source, standard deductions, no excluded items.
│ │ NOT covered: rental (F), capital gains (G), foreign income (J),
│ │ organized accounting, some benefits/regimes.
│ │ │
│ │ ├── Fully covered ──► REVIEW & ACCEPT IRS automático. Terminal: verify the
│ │ │ pre-filled income, household and withholding, then confirm. It
│ │ │ becomes final automatically if not rejected in the window.
│ │ │
│ │ └── Not covered, or taxpayer prefers manual ──► File full Modelo 3. Go to Q5.
│
└── Q5. ANNEX ASSEMBLY (resident: worldwide; non-resident: PT-source only).
Add every annex whose income/condition is present. Each links to its tree.
Rosto (always) — identification, household, quadro 8-C for partial-year.
├── Salary / pension present? → Anexo A (employment-pension-tree.md)
├── Self-employment / recibos verdes? → Anexo B (self-employment-tree.md)
│ (organized accounting → Anexo C → escalate)
├── Investment income (dividends/interest) to declare/aggregate? → Anexo E
├── Rental income? → Anexo F (rental-income-tree.md)
├── Capital gain (property/shares)? → Anexo G / G1 (capital-gains-tree.md)
├── Foreign income (resident)? → Anexo J (foreign-income-tree.md)
├── Deductions/benefits to claim? → Anexo H (rates-and-deductions.md §6)
└── Self-employment Social Security? → Anexo SS
Terminal: submit the Modelo 3 with exactly this annex set within the
1 Apr – 30 Jun window. Use assets/templates/report.md to record the outcome.Usual suspects
1. Non-resident landlord assuming no return. Rent is not finally withheld → filing is mandatory (Q1 "No" branch). 2. Accepting IRS automático with rental or gains. Those situations are outside automático; accepting it would omit Anexo F/G. Always run Q4's coverage check. 3. Over-appointing a representative. EU/EEA residence or e-notification adhesion already satisfies Art. 19 — don't pay for a representative you don't need.
Decision Tree: Foreign income & double taxation (Anexo J, Art. 81)
For a resident with income earned abroad (residents are taxed on worldwide income), and for the post-NHR IFICI regime. Treaty credit and IFICI terms: rates-and-deductions.md §1, §7. The applicable treaty is in config.json (applicable_tax_treaty).
START: resident received income from outside Portugal in the year.
│
├── Q1. Is the taxpayer under the IFICI regime (the post-NHR incentive)?
│ │
│ ├── Yes ──► foreign-source income is largely EXEMPT (with progression) and
│ │ eligible PT Cat A/B is taxed at 20%. Terminal: declare foreign income on
│ │ Anexo J and the IFICI annex; apply the exemption-with-progression method.
│ │ Registration deadline: 15 Jan of the year after becoming resident
│ │ (rates-and-deductions.md §7). If eligibility/registration is unconfirmed
│ │ ──► ESCALATE.
│ ├── Asking to "sign up for NHR" ──► NHR is CLOSED to new arrivals. Terminal:
│ │ test IFICI eligibility instead (narrow: research/innovation/listed
│ │ activities); if not eligible, normal worldwide taxation applies → Q2.
│ └── No / not applicable ──► Q2.
│
├── Q2. Classify each foreign income stream and place it on **Anexo J** by type
│ (employment, pensions, capital, rental, capital gains). Then resolve double
│ taxation per the treaty in config.json.
│ │
│ ├── Immovable property income/gains abroad ──► the source state taxes first
│ │ (OECD model Art. 6/13). PT gives a credit (Q3). For the mirror case —
│ │ PT-source rent declared by a non-resident — PT taxes first and the
│ │ residence state grants relief (e.g. UK FTCR on a UK SA106); the PT side
│ │ is rental-income-tree.md, not this tree.
│ └── Other income types ──► Q3.
│
├── Q3. Apply the foreign-tax credit (Art. 81 — crédito de imposto por dupla
│ tributação internacional).
│ │ Credit = the LESSER of (a) foreign tax actually paid, capped at the treaty
│ │ rate, and (b) the PT tax attributable to that foreign income.
│ │
│ ├── A treaty exists (config.applicable_tax_treaty set) ──► cap the creditable
│ │ foreign tax at the treaty rate; enter foreign income and foreign tax on
│ │ Anexo J. Terminal ACTION: file Anexo J with the Art. 81 credit.
│ ├── No treaty with the source country ──► unilateral relief still applies under
│ │ Art. 81; credit = lesser of foreign tax and PT tax on that income.
│ │ Terminal: file Anexo J with unilateral credit.
│ └── Foreign tax exceeds the treaty rate (over-withheld abroad) ──► claim the
│ excess back from the SOURCE country, not from PT. PT credits only up to
│ the treaty rate. If the source refund process is unclear ──► ESCALATE.
│
└── Q4. Consistency check before filing.
│ Foreign income on Anexo J also raises the average rate applied to PT income
│ (worldwide income sets the band). Confirm currency conversion uses the
│ official annual exchange rate.
│
└── Terminal ACTION: submit **Anexo J** alongside the PT-income annexes, with the
Art. 81 credit. Record with assets/templates/report.md.Usual suspects
1. Recommending NHR. It is closed to new arrivals; the live regime is IFICI, with much narrower eligibility. 2. Crediting more foreign tax than the treaty allows. PT caps the credit at the treaty rate; the excess is recovered from the source country. 3. Omitting foreign income because it was taxed abroad. Residents declare worldwide income on Anexo J even when a credit fully offsets the PT tax. 4. Forgetting that foreign income raises the rate band on PT income.
#!/usr/bin/env python3
"""Estimate the taxable real-estate capital gain (Categoria G, Art. 10/43/50 CIRS).
Purpose
Compute the gain on a property disposal and the taxable base. For income year
2025 the taxable portion is 50% of the gain for BOTH residents and
non-residents (the pre-2023 100%-at-28% non-resident rule is gone). The taxable
50% is then englobado at the progressive Art. 68 scale -- this script does NOT
apply the progressive rate (use the official simulator for that).
Usage
python3 property-capital-gain.py --sale 300000 --acquisition 165000 \
--coefficient 1.33 --acq-costs 9000 --sale-costs 12000 \
--improvements 25000 [--reinvested-fraction 0.0] [--year 2025]
Parameters
--sale Realisation (sale) value, EUR.
--acquisition Original acquisition value, EUR.
--coefficient Inflation coefficient for the acquisition year (current
Portaria). Default: 1.0 (no correction).
--acq-costs Acquisition costs (IMT, stamp duty, notary), EUR.
--sale-costs Disposal costs (agent commission, energy cert), EUR.
--improvements Capital improvements in the last 12 years, EUR.
--reinvested-fraction Fraction (0..1) of an own-permanent-home gain exempt via
reinvestment (Art. 10 s.5). Default: 0.0.
--year Income year. Default: 2025.
Expected output
The gross gain, the reinvestment-exempt portion, and the taxable base (50% of
the non-exempt gain). Estimate only -- the taxable base is taxed at the
progressive scale; verify on Portal das Financas.
"""
import argparse
INCLUSION = 0.50 # taxable portion of a real-estate gain (residents and non-residents)
def main():
parser = argparse.ArgumentParser(description="Real-estate capital gain estimate (Cat G)")
parser.add_argument("--sale", type=float, required=True, help="Realisation value, EUR")
parser.add_argument("--acquisition", type=float, required=True, help="Acquisition value, EUR")
parser.add_argument("--coefficient", type=float, default=1.0, help="Inflation coefficient")
parser.add_argument("--acq-costs", type=float, default=0.0, help="Acquisition costs, EUR")
parser.add_argument("--sale-costs", type=float, default=0.0, help="Disposal costs, EUR")
parser.add_argument("--improvements", type=float, default=0.0, help="Improvements (12y), EUR")
parser.add_argument("--reinvested-fraction", type=float, default=0.0,
help="Exempt fraction via reinvestment, 0..1")
parser.add_argument("--year", default="2025")
args = parser.parse_args()
fraction = min(max(args.reinvested_fraction, 0.0), 1.0)
corrected_acquisition = args.acquisition * args.coefficient
gain = (args.sale - args.sale_costs) - corrected_acquisition - args.acq_costs - args.improvements
exempt = max(gain, 0.0) * fraction if gain > 0 else 0.0
net_gain = gain - exempt
taxable_base = net_gain * INCLUSION if net_gain > 0 else net_gain # losses pass through fully
print(f"Real-estate capital gain estimate -- income year {args.year}")
print(f" corrected acquisition (x{args.coefficient}): EUR {corrected_acquisition:,.2f}")
print(f" gross gain: EUR {gain:,.2f}")
if fraction > 0:
print(f" reinvestment-exempt: EUR {exempt:,.2f} ({fraction*100:.0f}%)")
print(f" taxable base (50% incl.): EUR {taxable_base:,.2f}")
if gain <= 0:
print(" note: no gain -> loss may offset other Cat G results / carry forward")
print(" NOTE: taxable base is taxed at the PROGRESSIVE Art. 68 scale (englobamento), "
"not a flat rate. Estimate only; verify on Portal das Financas.")
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Estimate Categoria F (rental) net income and autonomous IRS (Art. 72 CIRS).
Purpose
Compute net rental income (gross minus deductible expenses, Art. 41) and the
autonomous tax using the verified Art. 72 rate ladder for income year 2025.
Rates are quoted verbatim from Art. 72 as of May 2026.
Usage
python3 rental-tax-estimate.py --gross 13200 --expenses 1800 \
--use residential --term-years 2 [--permanent-housing] \
[--rent-cut-5pct] [--year 2025]
Parameters
--gross Gross annual rent received, EUR.
--expenses Documented deductible expenses (conservation, condominio,
IMI, insurance), EUR. NOT mortgage interest or furniture.
--use residential | non-residential. Default: residential.
--term-years Signed contract term in years. Default: 0.
--permanent-housing Flag: lease is for habitacao permanente (required for the
duration reductions). Default: not set.
--rent-cut-5pct Flag: new contract rent is >=5% below the previous one
(extra -5pp, Art. 72 s.24). Default: not set.
--year Income year. Default: 2025. (For 2026+, the OE2026 10%
moderate-rent rate may apply -- not modelled here.)
Expected output
Net income, the selected autonomous rate with the reason, and the estimated
tax. Estimate only -- englobamento (progressive scale) may be cheaper for low
total income; verify on Portal das Financas.
"""
import argparse
BASE_RESIDENTIAL = 25.0
NON_RESIDENTIAL = 28.0
def autonomous_rate(use, term_years, permanent_housing, rent_cut_5pct):
"""Return (rate_percent, reason) per Art. 72 for income year 2025."""
if use == "non-residential":
return NON_RESIDENTIAL, "non-residential lease (Art. 72): no reductions"
rate = BASE_RESIDENTIAL
reason = "residential base 25% (term < 5 years or not permanent housing)"
if permanent_housing:
if 5 <= term_years < 10:
rate, reason = 15.0, "permanent housing 5-<10 years: -10pp"
elif 10 <= term_years < 20:
rate, reason = 10.0, "permanent housing 10-<20 years: -15pp"
elif term_years >= 20:
rate, reason = 5.0, "permanent housing >=20 years: -20pp"
if rent_cut_5pct and rate < BASE_RESIDENTIAL:
reduced = rate - 5.0
if reduced < 5.0:
# The combined reductions reach below the deepest published tier (5%).
# The statute's floor interaction here is an edge case (e.g. a >=20yr
# contract plus a rent cut); clamp to 5% and tell the user to verify.
rate = 5.0
reason += "; new rent >=5% below previous: extra -5pp (clamped at 5% floor -- verify)"
else:
rate = reduced
reason += "; new rent >=5% below previous: extra -5pp"
return rate, reason
def main():
parser = argparse.ArgumentParser(description="Categoria F autonomous tax estimate (Art. 72)")
parser.add_argument("--gross", type=float, required=True, help="Gross annual rent, EUR")
parser.add_argument("--expenses", type=float, default=0.0, help="Documented deductible expenses, EUR")
parser.add_argument("--use", choices=["residential", "non-residential"], default="residential")
parser.add_argument("--term-years", type=float, default=0.0, help="Signed contract term, years")
parser.add_argument("--permanent-housing", action="store_true")
parser.add_argument("--rent-cut-5pct", action="store_true")
parser.add_argument("--year", default="2025")
args = parser.parse_args()
net = max(args.gross - args.expenses, 0.0)
rate, reason = autonomous_rate(args.use, args.term_years,
args.permanent_housing, args.rent_cut_5pct)
tax = net * rate / 100.0
print(f"Categoria F estimate -- income year {args.year}")
print(f" gross rent: EUR {args.gross:,.2f}")
print(f" deductible exp.: EUR {args.expenses:,.2f}")
print(f" net income: EUR {net:,.2f}")
print(f" autonomous rate: {rate:.0f}% ({reason})")
print(f" estimated tax: EUR {tax:,.2f}")
if args.gross - args.expenses < 0:
print(" note: expenses exceed rent -> reportable loss, carry forward 6 years")
print(" NOTE: estimate only. Compare with englobamento (Art. 68) for low "
"income; verify on Portal das Financas.")
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""Portuguese tax-residency day test (Art. 16 CIRS).
Purpose
Determine whether the >183-day presence test is met. Art. 16 counts days of
physical presence in Portugal in ANY rolling 12-month period that begins or
ends in the income year -- not just the calendar year. This script counts the
maximum presence in any 365-day window across the supplied intervals.
Usage
python3 residency-days.py --interval 2025-01-10:2025-04-20 \
--interval 2025-06-01:2025-09-15 \
[--dwelling-on-dec31] [--year 2025]
Parameters
--interval START:END A presence interval, inclusive, ISO dates (YYYY-MM-DD).
Repeatable. Overlapping intervals are de-duplicated.
--dwelling-on-dec31 Flag: taxpayer held a home in PT on 31 Dec suggesting
habitual residence (Art. 16(1)(b)). Default: not set.
--year Income year for the report label. Default: 2025.
Expected output
Total distinct days present, the maximum days in any rolling 12-month window,
and a verdict: RESIDENT (day test), RESIDENT (habitual residence), or
NON-RESIDENT (by these tests). Estimate only -- confirm status and any treaty
tie-breaker on Portal das Financcas.
"""
import argparse
from datetime import date, timedelta
def parse_interval(text):
start_str, end_str = text.split(":")
start = date.fromisoformat(start_str)
end = date.fromisoformat(end_str)
if end < start:
raise ValueError(f"interval end {end} precedes start {start}")
return start, end
def present_days(intervals):
"""Return the sorted set of distinct dates covered by the intervals."""
days = set()
for start, end in intervals:
current = start
while current <= end:
days.add(current)
current += timedelta(days=1)
return sorted(days)
def max_rolling_window(days, window_days=365):
"""Max count of present days within any window_days-length window."""
if not days:
return 0
best = 0
for i, anchor in enumerate(days):
horizon = anchor + timedelta(days=window_days - 1)
count = 0
for d in days[i:]:
if d > horizon:
break
count += 1
best = max(best, count)
return best
def main():
parser = argparse.ArgumentParser(description="PT tax residency day test (Art. 16 CIRS)")
parser.add_argument("--interval", action="append", default=[], metavar="START:END",
help="Presence interval START:END (YYYY-MM-DD), repeatable")
parser.add_argument("--dwelling-on-dec31", action="store_true",
help="Held a home in PT on 31 Dec (habitual residence test)")
parser.add_argument("--year", default="2025", help="Income year label")
args = parser.parse_args()
intervals = [parse_interval(t) for t in args.interval]
days = present_days(intervals)
total = len(days)
rolling = max_rolling_window(days)
print(f"PT tax-residency day test -- income year {args.year}")
print(f" distinct days present: {total}")
print(f" max days in any 12-month window: {rolling}")
if rolling > 183:
verdict = "RESIDENT (day test met: >183 days in a 12-month window)"
elif args.dwelling_on_dec31:
verdict = "RESIDENT (habitual residence: home held on 31 Dec)"
else:
verdict = "NON-RESIDENT (neither day test nor habitual-residence test met)"
print(f" verdict: {verdict}")
print(" NOTE: estimate only. Dual residence -> apply the treaty tie-breaker; "
"confirm on Portal das Financas.")
if __name__ == "__main__":
main()
Rates & Deductions — single source of truth
All numeric values used by the decision trees. Default income year: 2025 (return filed 1 Apr – 30 Jun 2026). Where OE2026 changes a value for income year 2026 (filed 2027), it is marked [2026→]. When a new Orçamento do Estado lands, update only this file.
Verify before filing. Brackets and indexed caps are re-set by each annual budget.
The autonomous rates below are quoted verbatim from Art. 72 CIRS as of May 2026;
progressive brackets must be read off the live Art. 68 table for the income year.
1. Residency regime (sets everything)
| Resident | Non-resident | |
|---|---|---|
| Taxed on | Worldwide income | PT-source income only |
| Rate basis | Progressive (Art. 68) by englobamento | Special/flat rates (Art. 72) per category |
| Family quotient | Yes | No |
| Deduções à coleta | Yes | No (limited exceptions) |
| EU/EEA option | — | May elect to be taxed under resident rules (Art. 17-A), declaring worldwide income to set the rate |
Source: CIRS Art. 15, 16, 17-A.
2. Art. 72 autonomous / special rates
Rental income — Categoria F (verbatim from Art. 72, May 2026)
| Situation | Rate | Note |
|---|---|---|
| Residential letting, base | 25% | §2. Applies to any residential lease under 5 years |
| Permanent-housing contract ≥5 and <10 years | 15% | §3: −10pp; +2pp per renewal of equal length, renewal reductions capped at 10pp |
| Permanent-housing contract ≥10 and <20 years | 10% | §4: −15pp |
| Permanent-housing contract ≥20 years (and direito real de habitação duradoura) | 5% | §5: −20pp |
| New contract with rent ≥5% below previous contract | extra −5pp | §24, on top of the duration reduction |
| Non-residential (commercial, industrial, rural) | 28% | No duration reductions |
- There is no 2–5 year reduction tier. A 2-year lease is taxed at the 25% base
regardless of H_PERM vs H_NPER finalidade.
- Reductions do not apply to contracts signed after 1 Jan 2024 whose monthly
rent exceeds the municipal price limits by more than 50%.
- [2026→] OE2026 adds a 10% rate for moderate-rent permanent-housing leases
(rent ≤ ~€2,300/month, registered, property classified residential), plus a "zero-IRS" track for rents ≤80% of the INE median with a ≥3-year term. These apply to 2026 income (filed 2027), not the 2025 return.
- Englobamento (option to be taxed at the progressive scale instead) is available;
worthwhile only if the marginal rate is below the autonomous rate.
Source: CIRS Art. 72 §2–§5, §24; Lei 56/2023 (Mais Habitação); OE2026.
Capital gains & investment income — Art. 72
| Item | Rate |
|---|---|
| Net gains on securities/shares (Cat G) | 28% flat, or option to aggregate |
| Investment income not subject to withholding (Cat E) | 28% |
| Income/gains from blacklisted (favourable-regime) jurisdictions | 35% |
| Non-resident with PT permanent establishment | 25% |
Real-estate gains are not a flat Art. 72 rate — see §4 below (50% inclusion + progressive). Source: CIRS Art. 72 §1, §18.
3. Art. 68 progressive brackets (residents, and englobamento)
For income year 2025 there are 9 escalões with marginal rates ranging from roughly 13% to 48% (redação da Lei n.º 55-A/2025). Exact threshold euros are re-indexed annually — read them off the official Art. 68 table for the income year rather than hardcoding.
- Add the taxa adicional de solidariedade: +2.5% on taxable income above
€80,000 and +5% above €250,000 (Art. 68-A).
- The progressive scale applies to the resident's total englobado income and to
englobado capital gains; it sets the average rate used for the non-resident's real-estate gain too.
Source: CIRS Art. 68, 68-A; Portal das Finanças escalões table (income year 2025).
4. Real-estate capital gains base (Cat G)
Gain = realisation value − (acquisition value × inflation coefficient) − acquisition/disposal costs − improvement costs (last 12 years), per Art. 10, 50.
- Taxable portion = 50% of the gain for both residents and non-residents
(the pre-2023 "100% at 28%" rule for non-residents is gone).
- The taxable 50% is englobado at the progressive scale (Art. 43 §2). A
non-resident declares worldwide income on the return only to fix the rate band.
- Reinvestment exemption (Art. 10 §5): gain on an own permanent home is exempt
to the extent proceeds are reinvested in another own permanent home in PT/EU/EEA, within 24 months before or 36 months after the sale (with declaration of intent).
- Inflation coefficients are published yearly by Portaria — pass the current one to
queries/property-capital-gain.py.
5. Categoria B — simplified regime coefficients (Art. 31)
Taxable income = coefficient × gross receipts (regime applies up to €200,000 turnover):
| Coefficient | Applies to |
|---|---|
| 0.15 | Sale of goods, hotel/restaurant/beverage |
| 0.75 | Professional services in the Art. 151 table |
| 0.35 | Other services |
| 0.95 | Intellectual property assigned by third parties, capital, positive balance of gains |
| 0.30 | Subsidies not for operations |
| 0.10 | Operating subsidies |
- The 0.75/0.35 service coefficients carry a 15% expense-justification rule:
part of the deemed deduction must be backed by documented business expenses.
- First-year −50% and second-year −25% reductions on the coefficient apply
to a newly opened activity.
- Social Security is reported separately via Anexo SS.
- Above €200,000 turnover, or by option, organized accounting (Anexo C) →
escalate to a contabilista certificado.
Source: CIRS Art. 28, 31.
6. Deductions (residents only)
Dedução específica (subtracted before the scale):
- Categoria A (employment) and H (pensions): €4,104 per holder (or higher
mandatory social-contribution amount).
Deduções à coleta (subtracted from the tax) — income year 2025, confirm caps on the Anexo H / despesas screen:
| Deduction | Rate / cap |
|---|---|
| General family expenses (despesas gerais familiares) | 35% of expenses, cap €250/holder (45% / €335.66 for single-parent) |
| Health | 15%, cap €1,000 |
| Education | 30%, cap €800 |
| Property — rent paid for own home | 15%, cap €600 (raised for some moderate-rent cases) |
| Homes/elder care (lares) | 25%, cap €403.75 |
| Invoice-requirement deduction (IVA em faturas) | 15% of VAT in eligible sectors, cap €250 |
| Descendants/ascendants, PPR, donations | per Art. 78-A..78-F |
Source: CIRS Art. 25, 78–78-G. Caps are indexed — verify for the income year.
7. Special regimes
- IRS Jovem (2025 model): ages up to 35, max 10 years of Cat A/B income.
Exemption schedule on eligible income: 100% year 1; 75% years 2–4; 50% years 5–7; 25% years 8–10. Cap 55 × IAS = €28,737.50 (IAS 2025 = €522.50). Source: Folheto IRS Jovem 2025 (Portal das Finanças).
- IFICI (the post-NHR regime, a.k.a. NHR 2.0): 20% flat IRS on Cat A/B from
eligible highly-qualified activities, plus exemption of most foreign-source income. Narrow eligibility (research/innovation/listed activities). The old NHR is closed to new arrivals — registrations ended in the 2024/early-2025 transition. Anyone "just signing up for NHR" must instead test IFICI eligibility.
- IFICI registration deadline: apply by 15 January of the year following
the year you become a PT tax resident (Portaria 352/2024/1) — e.g. resident in 2025 → register by 15 Jan 2026. Registration is via the AT / the relevant certifying body for the activity (IAPMEI, FCT, AICEP, Startup Portugal, etc.). Transitional: those who became resident in 2024 had until 15 Mar 2025. Verify the channel for the specific activity.
8. Calendar (income year 2025)
| Date | Event |
|---|---|
| Until ~Feb 2026 | Validate e-fatura invoices (deduction classification) |
| 15–31 Mar 2026 | Confirm household/dependents; complaint window on pre-filled deductions |
| 1 Apr – 30 Jun 2026 | Modelo 3 submission window (all taxpayers, electronic) |
| 31 Jul 2026 | Assessment / refund target for on-time returns |
| 31 Aug 2026 | Payment deadline if tax is due |
Non-residents file in the same window if they have PT-source income not taxed by final withholding. Source: Portal das Finanças "IRS – Principais prazos 2026".
Decision Tree: Rental income — Categoria F (Anexo F)
For PT-source rent received by an individual (residents and non-residents). Rates: rates-and-deductions.md §2. Estimator: queries/rental-tax-estimate.py.
START: rent received from a PT property during the income year.
│
├── Q1. Is the property let under a business activity in organized accounting, or
│ is it a Cat B activity (e.g. alojamento local as a business)?
│ │
│ ├── Alojamento local / Cat B ──► WRONG TREE. Go to self-employment-tree.md
│ │ (AL is Categoria B, not F).
│ ├── Organized accounting ──────► ESCALATE to a contabilista certificado.
│ └── Ordinary lease (Cat F) ────► continue to Q2.
│
├── Q2. Compute NET income: gross rents − deductible expenses (Art. 41).
│ │ Deductible: conservation/maintenance, condomínio, IMI, landlord insurance,
│ │ and (first year) the stamp duty on the lease.
│ │ NOT deductible: mortgage interest, capital repayment, furniture/appliances.
│ │ Expected: net ≥ 0; carry forward losses for 6 years if expenses > rents.
│ │
│ ├── Any expense undocumented (no invoice/receipt)? ──► drop it; only documented
│ │ expenses count. If most expenses are undocumented ──► ESCALATE.
│ └── Net computed ──► Q3.
│
├── Q3. Determine the AUTONOMOUS RATE (Art. 72). Use rental-tax-estimate.py.
│ │ Criteria are the SIGNED CONTRACT TERM and use:
│ │
│ ├── Non-residential (commercial/industrial/rural) ───────────► 28%.
│ ├── Residential, term < 5 years ─────────────────────────────► 25% (base).
│ ├── Residential, permanent housing, ≥5 and <10 years ────────► 15% (−10pp).
│ ├── Residential, permanent housing, ≥10 and <20 years ───────► 10% (−15pp).
│ ├── Residential, permanent housing, ≥20 years ───────────────► 5% (−20pp).
│ └── New contract with rent ≥5% below the previous one ───────► additionally −5pp
│ (on top of a duration reduction; the combined rate does not go below the 5%
│ statutory floor — a ≥20yr contract plus a rent cut is an edge case to verify).
│ (Expected check: post-2024 contracts lose reductions if rent exceeds the
│ municipal limit by >50% — if so, fall back to 25%.)
│ NOTE [2026→]: from 2026 income, a 10% moderate-rent rate may apply instead
│ (rent ≤ ~€2,300/mo). Do NOT use it on the 2025 return.
│
├── Q4. Englobamento — should it be elected instead of the autonomous rate?
│ │ Compare the autonomous rate to the taxpayer's marginal Art. 68 rate on the
│ │ net rent (residents; or EU/EEA non-residents under Art. 17-A).
│ │
│ ├── Marginal progressive rate < autonomous rate ──► ELECT englobamento on Anexo F
│ │ (tick the option). Terminal: rent is taxed at the progressive scale.
│ └── Otherwise ──► keep the autonomous rate (no englobamento).
│
└── Q5. Compliance checks, then file.
│
├── Recibos de renda eletrónicos issued for each payment (or exemption claimed)?
│ If not issued and not exempt ──► issue/regularise first.
└── Terminal ACTION: submit **Anexo F** — list the property (matrix article,
conservatória), gross rent, documented expenses, contract term/finalidade
so the system applies the right rate, and the englobamento choice from Q4.
Record figures with assets/templates/report.md. Non-resident: confirm the
fiscal-representative status from filing-obligation-tree.md.Usual suspects (most frequent first)
1. Expecting a reduced rate on a short lease. Under 5 years = 25%; reductions begin only at 5-year permanent-housing contracts. 2. Deducting mortgage interest or furniture. Neither is allowed against Cat F. 3. Forgetting englobamento can be cheaper for low total income — always run the Q4 comparison. 4. Treating alojamento local as Cat F. AL run as a business is Cat B.
Decision Tree: Tax residency (Art. 16 CIRS)
Why this is the gateway: residency decides whether the taxpayer is taxed on worldwide income at the progressive scale (resident) or only on PT-source income at the special Art. 72 rates (non-resident), and whether deductions and the family quotient apply. Decide this before opening any income-type tree.
Rates and regime differences: rates-and-deductions.md §1. Day-count tool: queries/residency-days.py.
START: For the income year, was the person present in Portugal?
│
├── Q1. Days physically present in PT during ANY rolling 12-month window
│ beginning or ending in the year — run queries/residency-days.py.
│ │ Expected output: max days in any 12-month window, and a pass/fail on 183.
│ │
│ ├── > 183 days ──────────────────────────────► RESIDENT (day test met). Go to Q4.
│ │
│ └── ≤ 183 days ──► Q2.
│
├── Q2. On 31 Dec of the year, did they hold a dwelling in PT in conditions
│ suggesting intention to keep and occupy it as habitual residence?
│ │ (Owned or rented home kept available year-round, family living there, etc.)
│ │
│ ├── Yes ─────────────────────────────────────► RESIDENT (habitual-residence test). Go to Q4.
│ │
│ └── No ──► Q3.
│
├── Q3. Special-status check: crew of PT-flagged ships/aircraft, or serving the
│ Portuguese State abroad, or member of a household whose other members are
│ PT-resident (Art. 16 §2)?
│ │
│ ├── Yes ─────────────────────────────────────► RESIDENT by attribution. Go to Q4.
│ │
│ └── No ──────────────────────────────────────► NON-RESIDENT. Go to Q5.
│
├── Q4. RESIDENT — did residency start or end PART-WAY through the year?
│ │ (Arrived in / left PT during the year — Art. 16 §3, §4: residency is counted
│ │ from the day of first presence / to the day of last presence.)
│ │
│ ├── Yes ──► PARTIAL-YEAR RESIDENT.
│ │ ACTION: file ONE Modelo 3 per status period, each marking the period
│ │ in quadro 8-C (Rosto). Resident period = worldwide income at the
│ │ progressive scale; non-resident period = PT-source only at Art. 72.
│ │ Then open the income-type trees for each period's income.
│ │
│ └── No ───► FULL-YEAR RESIDENT.
│ ACTION: declare WORLDWIDE income. Open filing-obligation-tree.md,
│ then each income-type tree. Foreign income → foreign-income-tree.md.
│
└── Q5. NON-RESIDENT — is the person tax-resident in the EU, Norway, Iceland or
Liechtenstein, AND would the progressive scale beat the flat Art. 72 rate?
│ (EU/EEA residents may elect resident-equivalent taxation — Art. 17-A —
│ declaring worldwide income only to set the rate band.)
│
├── Yes, and it lowers tax ──► NON-RESIDENT, opt for Art. 17-A treatment.
│ ACTION: file Modelo 3 marking the EU/EEA option; expect to report
│ worldwide income for rate purposes. Then open the income-type trees.
│
├── No / not EU/EEA ─────────► NON-RESIDENT, standard.
│ ACTION: declare only PT-source income at Art. 72 rates. Check the
│ fiscal-representative question in filing-obligation-tree.md, then open
│ the relevant income-type trees.
│
└── Both PT and another country claim residency (dual-residence) ──►
ESCALATE to a contabilista certificado: apply the tie-breaker article
of the relevant double-taxation treaty (permanent home → centre of vital
interests → habitual abode → nationality). Treaty residence overrides
the domestic test and changes the whole return.Usual suspects
1. Counting only calendar-year days. The 183-day test uses any rolling 12-month window that begins or ends in the year — residency-days.py handles this; a naïve Jan–Dec count under-detects residency. 2. Assuming non-resident = no PT return. A non-resident with PT-source income not taxed by final withholding (typically rent) still files — see filing-obligation-tree.md. 3. Ignoring partial-year split. People who moved in/out mid-year owe two declarations, not one blended return.
Decision Tree: Self-employment — Categoria B (Anexo B / C)
For recibos verdes / independent activity, including alojamento local run as a business. Coefficients and reductions: rates-and-deductions.md §5.
START: the taxpayer earned independent/business income in the year.
│
├── Q1. Accounting regime?
│ │
│ ├── Turnover > €200,000, or organized accounting elected ──► Anexo C.
│ │ ESCALATE to a contabilista certificado.
│ └── Simplified regime (turnover ≤ €200,000) ──► Q2.
│
├── Q2. Determine the COEFFICIENT for the activity (Art. 31):
│ │ 0.15 goods/hospitality · 0.75 Art. 151 professional services ·
│ │ 0.35 other services · 0.95 IP/capital · 0.30/0.10 subsidies.
│ │ Taxable income = coefficient × gross receipts.
│ │
│ ├── Newly opened activity? ──► apply −50% (year 1) / −25% (year 2) to the
│ │ coefficient.
│ └──► Q3.
│
├── Q3. Does the 0.75 / 0.35 service coefficient apply?
│ │ Those carry the 15% expense-justification rule: part of the deemed deduction
│ │ must be backed by documented business expenses, or taxable income is
│ │ increased by the unjustified shortfall.
│ │
│ ├── Yes, and expenses documented ──► fine; keep records.
│ ├── Yes, but expenses not documented ──► taxable income rises; warn the taxpayer.
│ └── No (e.g. 0.15 goods) ──► continue.
│
├── Q4. Social Security position?
│ │
│ ├── Liable (not exempt as employee/pensioner) ──► add **Anexo SS**.
│ └── Exempt this year ──► no Anexo SS.
│
└── Q5. Other flags.
│
├── VAT-liable activity AND taxpayer is non-resident ──► fiscal representative
│ must be a PT-resident VAT taxpayer (see filing-obligation-tree.md Q2);
│ ESCALATE.
├── IRS Jovem eligible (≤35, within window) ──► apply the exemption to the Cat B
│ income (see rates-and-deductions.md §7); flag the year on the return,
│ then proceed to the Terminal ACTION below.
└── Terminal ACTION: submit **Anexo B** (simplified) with gross receipts by
coefficient class, plus Anexo SS if liable. The progressive scale applies to
the computed taxable income (englobamento is the default for Cat B). Record
with assets/templates/report.md.Usual suspects
1. Declaring gross receipts as taxable income. Under the simplified regime only the coefficient share is taxed. 2. Ignoring the 15% expense-justification rule on service income. 3. Filing alojamento local as Cat F. Run as a business it is Cat B. 4. Forgetting the first/second-year coefficient reductions for a new activity.
Symptom Catalog — PT IRS filing
Each symptom is a filing situation. Start at residency (it sets the regime), then filing obligation (do you even file, and which annexes), then open the tree for each income type the taxpayer has. A return often needs several annexes at once. Every tree terminates in a concrete filing action or an escalation to a contabilista certificado with a stated reason.
| # | Symptom / Question | Entry point | Priority | Terminal states |
|---|---|---|---|---|
| 1 | "Am I resident or non-resident — and what changes?" | residency-tree.md | P1 (gateway) | Resident / Non-resident / Partial-year (two periods) / Escalate (tie-breaker treaty case) |
| 2 | "Do I have to file? IRS automático? Which annexes?" | filing-obligation-tree.md | P1 (router) | No return due / Accept IRS automático / File Modelo 3 with annexes {list} |
| 3 | "I receive rent from a PT property" (Categoria F) | rental-income-tree.md | P1 | Submit Anexo F at rate X% / Escalate (organized accounting, sublease, undocumented expenses) |
| 4 | "I sold a property or shares" (Categoria G) | capital-gains-tree.md | P1 | Submit Anexo G (taxable base Y) / Anexo G1 (exempt) / Escalate (reinvestment, inheritance basis) |
| 5 | "I have salary or a pension" (Categoria A / H) | employment-pension-tree.md | P2 | Accept IRS automático / Submit Anexo A / Escalate (IRS Jovem proof, severance) |
| 6 | "I'm self-employed / recibos verdes" (Categoria B) | self-employment-tree.md | P2 | Submit Anexo B simplified / Escalate (organized accounting, VAT, Anexo SS) |
| 7 | "I have foreign income / double-taxation risk" (Anexo J) | foreign-income-tree.md | P2 | Submit Anexo J + credit (Art. 81) / IFICI path / Escalate (treaty residence conflict) |
How priority maps to urgency
- P1 changes the rest of the return: get residency and the annex set right
first, and rental/gains have hard rate consequences if misclassified.
- P2 is income-type detail that slots into the annex set decided in P1/P2 #2.
Rates and thresholds live in one place
Do not restate rates inside a tree. All numeric values — Art. 68 brackets, Art. 72 autonomous rates, Cat B coefficients, deduction caps, IRS Jovem and IFICI terms, deadlines — are in rates-and-deductions.md, with the income year they apply to. Update that one file when a budget changes.
Calculators
Deterministic estimates (verify the result on Portal das Finanças afterwards):
| Tool | Computes | Used by |
|---|---|---|
| queries/residency-days.py | 183-day presence test over any rolling 12-month window (Art. 16) | residency-tree |
| queries/rental-tax-estimate.py | Net Cat F income and autonomous tax by contract tier | rental-income-tree |
| queries/property-capital-gain.py | Taxable real-estate gain with 50% inclusion and inflation coefficient | capital-gains-tree |
Related skills
FAQ
What does pt-irs-runbook do?
pt-irs-runbook is a Claude Code skill for ai & agent building.
When should I use pt-irs-runbook?
When you need to helps with ai & agent building tasks during AI-assisted development., or when pt-irs-runbook is a claude code skill for ai & agent building.
What are the main capabilities?
pt-irs-runbook; AI & Agent Building; AI-coding skill.