Skip to content
Back to skills

Add New Country

ASecurity

Create YAML tax configurations for new countries in the universal salary calculator. Use when: (1) Adding a new country to the calculator, (2) Adding a new tax year for existing country, (3) Creating variant configs (expat regimes, special tax rules), (4) Writing test vectors for configs. Triggers: "add country", "create config for", "new tax year", "add variant", "30% ruling config", etc. IMPORTANT: This skill includes automated test validation. All configs MUST pass `npm run test:configs` ...

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 27, 2026
code-qualitygobashnodedebuggingsecurity

Security analysis

A100/100

Pro scans all 2 files and shows the line behind each finding

Scanned September 27, 2026

npx -y skills add David-Li0406/meta-skill-evloving --skill add-new-country --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Add New Country?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Add New Country
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/david-li0406-add-new-country/badge)](https://www.skillsdirectory.com/skills/david-li0406-add-new-country)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: add-new-country
description: |
  Create YAML tax configurations for new countries in the universal salary calculator.
  Use when: (1) Adding a new country to the calculator, (2) Adding a new tax year for existing country,
  (3) Creating variant configs (expat regimes, special tax rules), (4) Writing test vectors for configs.
  Triggers: "add country", "create config for", "new tax year", "add variant", "30% ruling config", etc.

  IMPORTANT: This skill includes automated test validation. All configs MUST pass `npm run test:configs`
  before completion. The skill guides you through research, implementation, test creation, validation,
  and debugging until all tests pass.
---

# Add New Country Configuration

## Workflow

1. **Research** - Gather official tax rates, brackets, contributions, credits. See references/country-tax-research.md for guidance.
2. **Plan** - Identify complexity level and required nodes
3. **Implement** - Create base.yaml with all calculations
4. **Write Tests** - Create test vectors with expected values
5. **Validate** - Run test suite, debug failures until all tests pass
6. **Document** - Add sources and notices
7. **Add research to guides** - Add the research to the guides/countries/<country>.md file.

## Quick Reference

File structure:
```
configs/<country>/<year>/
  base.yaml
  variants/<name>.yaml
  tests/<name>.json
```

Reference syntax:
- `@input_name` - User inputs (e.g., `@gross_annual`, `@filing_status`)
- `$node_or_param` - Parameters or calculated nodes

Essential node types:
- `bracket_tax` - Progressive tax brackets
- `percent_of` - Flat percentage
- `credit` - Tax credits (with optional `phaseout`)
- `sum`, `sub`, `min`, `max` - Arithmetic
- `switch`, `lookup` - Conditionals
- `function` - Escape hatch for complex logic (DE, FR, US)

## Process

### Step 1: Research

Gather from official government sources:
- Income tax brackets and rates
- Social security / national insurance rates and caps
- Standard deductions and credits
- Filing status options
- Regional variations (if any)

Record all source URLs with retrieval dates.

If the country already has a year in it, consider searching for the same / similar sources to update for the new year requested. Chances are not much changed.


### Step 2: Assess Complexity

| Level    | Characteristics                                       | Approach                 |
| -------- | ----------------------------------------------------- | ------------------------ |
| Simple   | No income tax or flat tax (UAE, SG, HK)               | Pure YAML, minimal nodes |
| Moderate | Progressive brackets + contributions (NL, AU, IE, UK) | Pure YAML                |
| High     | Multi-level regions or special calculations (CH, US)  | YAML + lookups           |
| Complex  | Income splitting, family quotient (DE, FR)            | Use `function` node      |

### Step 3: Create base.yaml

Minimal template:
```yaml
meta:
  country: "xx"
  year: 2024
  currency: "XXX"
  version: "1.0.0"
  sources:
    - url: "https://..."
      description: "Official tax rates"
      retrieved_at: "2024-01-01"
  updated_at: "2024-01-01"

notices:
  - id: "salary_input"
    title: "Annual Gross"
    body: "Enter total annual salary before deductions."
    severity: "info"

inputs:
  gross_annual:
    type: number
    required: true
  filing_status:
    type: enum
    required: true
    default: "single"
    options:
      single:
        label: "Single"
        description: "Unmarried individual"

parameters:
  tax_brackets:
    - { threshold: 0, rate: 0.20 }
    - { threshold: 50000, rate: 0.40 }

calculations:
  - id: income_tax
    type: bracket_tax
    base: "@gross_annual"
    brackets: "$tax_brackets"
    category: income_tax
    label: "Income Tax"

  - id: net_annual
    type: sub
    values: ["@gross_annual", "$income_tax"]

outputs:
  gross: "@gross_annual"
  net: "$net_annual"
  effective_rate:
    type: div
    values:
      - type: sub
        values: ["@gross_annual", "$net_annual"]
      - "@gross_annual"
  breakdown:
    taxes:
      - "$income_tax"
```

### Step 4: Write Test Vectors

Create `tests/<name>.json` covering:
- Low income (below first bracket)
- Median income (~50-80k)
- High income (top bracket)
- Each filing status
- Regional variations if applicable

**IMPORTANT**: Use official government calculators or tax tables to get accurate expected values. Don't estimate!

Test vector format:
```json
{
  "name": "Single at median income",
  "description": "Verified against official calculator at ...",
  "inputs": {
    "gross_annual": 60000,
    "filing_status": "single"
  },
  "expected": {
    "net": 45000,
    "effective_rate": 0.25,
    "breakdown": {
      "income_tax": 12000,
      "social_security": 3000
    }
  },
  "tolerance": 50,
  "sources": [{
    "description": "Official tax calculator result",
    "url": "https://...",
    "retrieved_at": "2024-01-01"
  }]
}
```

**Tips**:
- Include `breakdown` expectations for major tax items to catch calculation errors early
- Set reasonable `tolerance` (e.g., 50 for rounding differences, 0.0001 for rates)
- Document source URLs so test vectors can be verified independently

### Step 5: Run Test Suite & Debug

**CRITICAL**: All tests MUST pass before the config is considered complete.

Run the test suite:
```bash
# Run all config tests
npm run test:configs

# Or run tests for specific country
npx vitest run packages/engine/__tests__/config-tests.test.ts -t "xx/2024"
```

#### Common Test Failures & Fixes

**Reference Errors** (`Reference not found: xyz`):
- Check that all `@` inputs are defined in `inputs:` section
- Check that all `$` references point to valid `parameters:` or `calculations:` nodes
- Ensure node IDs match exactly (case-sensitive)

**Calculation Mismatches** (Expected X, got Y):
- Verify bracket thresholds and rates from official sources
- Check for off-by-one errors in bracket calculations
- Ensure correct order of operations in compound calculations
- Validate phaseout calculations (start, end, rate)
- Check rounding modes and precision

**Type Errors** (`is not a number`):
- Ensure switch cases return the correct type for downstream nodes
- Check that conditionals return numeric values when used in arithmetic
- Verify lookup tables have numeric values where expected

**Breakdown Errors** (`Breakdown item not found`):
- Ensure all breakdown nodes have `category` and `label`
- Check that output section references match node IDs

#### Debugging Process

1. **Read the error message** - identifies which test and what failed
2. **Check test vector** - verify expected values are correct
3. **Trace calculation** - follow the node DAG from inputs to outputs
4. **Fix config** - adjust brackets, rates, or logic
5. **Re-run tests** - repeat until all pass

#### Validation Checklist

Once tests pass, verify:
- [ ] All `@` and `$` references resolve
- [ ] Every breakdown node has `category` and `label`
- [ ] Sources documented with URLs and dates
- [ ] Test vectors verified against official calculators
- [ ] Notices guide users on country-specific conventions
- [ ] **All tests pass: `npm run test:configs` shows 100% passing**

### Step 6: Document

Final touches:
- Add helpful notices explaining country-specific conventions
- Document any assumptions or limitations
- Add `description` to all enum options
- Review all source URLs are accessible and dated

## Creating Variants

For special regimes (expat rules, alternative tax treatments):

```yaml
meta:
  variant: "special-regime"
  label: "Special Regime Name"
  description: "Who qualifies and what it does"
  base: "../base.yaml"

parameters:
  # Override or add parameters

calculations:
  # Override nodes by matching id
  - id: taxable_income
    type: mul
    values: ["@gross_annual", 0.70]
```

**Don't forget**: Variants need their own test vectors too! Run `npm run test:configs` to ensure variant tests pass.

## Detailed Specification

See [references/DATA_SPEC.md](references/DATA_SPEC.md) for:
- Complete node type reference
- All input types and options
- Bracket table formats
- Overlay merge rules
- Validation requirements

Files in this skill

  • SKILL.md8 KB
  • references/DATA_SPEC.md17.8 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…