Skip to content

p0ss/CourgetteRules

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

13 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Courgette Codifier

Plain English rules that compile to code – making legislation executable

Overview

Courgette rules are a way of writing eligibility rules and calculations which are very close to plain language that can be automatically compiled to code.

Why Courgette?

  • Readable by everyone: Policy makers, lawyers, and citizens can understand the rules
  • Executable by computers: Automatically generates working OpenFisca code
  • Testable and verifiable: Rules can be validated against real scenarios
  • Maintainable: Changes to policy can be directly reflected in the rules

Simple Example Corgette Rules

Scenario: Youth Allowance
  When age between 16 and 24
  And is_student
  And parental_income is less than $60,000
  Then youth_allowance is eligible
  And payment is $350.50 per fortnight

Easy to read right?

This compiles to complete OpenFisca Python code that can calculate eligibility and payment amounts.

from openfisca_core.model_api import *
from openfisca_core.periods import MONTH, YEAR, ETERNITY


class youth_allowance_eligible(Variable):
    value_type = bool
    entity = Person
    definition_period = MONTH
    label = "Youth Allowance eligibility"
    
    def formula(person, period, parameters):
        age = person('age', period)
        is_student = person('is_student', period)
        parental_income = person('parental_income', period)
        payment = person('payment', period)

        eligible = (
            (age >= 16 and person('youth_allowance_eligible', period) <= 24)
            and (is person('youth_allowance_eligible', period) student == True)
            and (parental person('youth_allowance_eligible', period) income < 60000)
            and (payment is $350.50 per fortnight)
        )

        return eligible

How it works

Courgette is an expanded version of Cucumber/Gherkin, using Lark free text parser to add custom syntax to cover legislative rules. This is exposed in a Quill wysiwyg editor styled with AGDS, and includes a compiler so that Courgette is continually compiled into OpenFisca.

Installation

Try online

You can play around with it in a test environment https://courgette-codifier.netlify.app/

Try locally

Firefox: Download the all files and open index.html in Firefox.

Other Browsers: Download all the files, run server.py and enter http://localhost:8000/index.html in your browser

Web Editor

The editor includes:

  • Syntax highlighting and validation
  • Real-time OpenFisca code generation
  • Example scenarios

Courgette Syntax

Basic Structure

A Courgette file consists of three types of blocks:

  1. Definitions - Reusable terms and calculations
  2. Schedules - Payment rates and thresholds
  3. Scenarios - Eligibility rules and outcomes

Definitions

Define terms that can be referenced throughout your rules:

Definition: assessable_income
  The total of employment income, investment income, and deemed income

Definition: secondary_earner_income  
  The lower of partner A income and partner B income

Schedules

Define payment rates, thresholds, or other values that vary by condition:

Schedule: Age Pension Rates
  When single: $1,096.70 per fortnight
  When couple combined: $1,650.40 per fortnight
  When couple separated by illness: $2,193.40 per fortnight

Scenarios

Define eligibility rules and calculate payments:

Scenario: [Benefit Name]
  When [condition]
  And [condition]
  Then [outcome]
  And [outcome]

Conditions

Natural Language Comparisons

When age is at least 67                    # >= 67
And income is less than $20,000            # < 20000
And assets are no more than $500,000       # <= 500000
And hours is greater than 15               # > 15
And age is not equal to 16                 # != 16

Code-Style Operators (Still Supported)

When age >= 67                    # Greater than or equal
And income < 20000                # Less than
And status == "unemployed"        # Equals
And has_partner != true           # Not equals
And hours <= 15                   # Less than or equal
And assets > 10000                # Greater than

Range Conditions

When age between 16 and 24       # Inclusive range
And income between 0 and 50000   # Any numeric range

Boolean Conditions

When is_student                     # Implicit true
And not working_full_time           # Negation
And has_dependent_children          # Natural readable form

Or be explicit if preferred:

When is_student is true
And is_australian_resident is yes
And youth_allowance is eligible

Logical Operators

All conditions must be true (AND)

When age >= 16
And is_australian_resident == true
And income < 50000

Any condition must be true (OR)

When age >= 67
Or has_disability == true
Or is_carer == true

Grouped Conditions

When age >= 16
And any of these are true:
  - is_student == true
  - is_apprentice == true  
  - employment_status == "job_seeker"
And income < 30000
When all of these are true:
  - age >= 67
  - residence_years >= 10
And none of these are true:
  - receiving_other_payment == true
  - assets > 500000

Outcomes

Eligibility

Then youth_allowance is eligible
Then age_pension is yes
Then family_tax_benefit_part_a is true

Fixed Payments

Then payment is $512.50 per fortnight
Then payment is $1,096.70 per fortnight

Schedule-based Payments

Then rate is determined by Age Pension Rates
Then rate is determined by Youth Allowance Base Rates

Payment Reductions

Then payment reduces by 50 cents per dollar over $204
Then payment reduces by 20 cents per dollar over $5,767

Multiple Outcomes

Then family_tax_benefit_part_a = true
And rate is determined by FTB Part A Maximum Rates
And payment reduces by 20 cents per dollar over $58,108
And payment reduces by 30 cents per dollar over $103,368

Complete Examples

Simple Eligibility

Scenario: Senior Card
  When age is at least 60
  And working_hours is at most 20
  And is_australian_resident
  Then senior_card is eligible

Complex Payment Calculation

Definition: assessable_income
  Total of employment, investment, and deemed income

Schedule: JobSeeker Base Rates
  When single no children: $693.10 per fortnight
  When single with children: $745.20 per fortnight
  When partnered: $631.20 per fortnight each

Scenario: JobSeeker Payment
  When age between 22 and age_pension_age
  And is_australian_resident
  And any of these are true:
    - employment_status is "unemployed"
    - employment_hours is less than 15
  And income is less than $1,356.99
  Then jobseeker_payment is eligible
  And rate is determined by JobSeeker Base Rates
  And payment reduces by 50 cents per dollar over $150
  And payment reduces by 60 cents per dollar over $256

Family Benefits with Multiple Parts

Definition: ftb_child
  A dependent child under 16, or 16-19 in full-time secondary study

Schedule: FTB Part A Rates
  When child under 13: $197.96 per fortnight
  When child 13 to 15: $257.46 per fortnight

Schedule: FTB Part B Rates  
  When youngest under 5: $161.55 per fortnight
  When youngest 5 to 18: $112.55 per fortnight

Scenario: Family Tax Benefit Part A
  When has_ftb_child == true
  And family_income < 80000
  Then family_tax_benefit_part_a = true
  And rate is determined by FTB Part A Rates

Scenario: Family Tax Benefit Part B
  When has_ftb_child == true
  And any of these are true:
    - is_single_parent == true
    - secondary_earner_income < 5767
  Then family_tax_benefit_part_b = true
  And rate is determined by FTB Part B Rates
  And payment reduces by 20 cents per dollar over $5,767

Style Guide

Proper English

Where possible courgette supports Australian spelling and terminology:

  • recognise not ❌ recognize
  • labour not ❌ labor
  • fortnight not ❌ two weeks

Naming Conventions

Variables: Use snake_case

is_australian_resident
has_dependent_children
taxable_income

Scenarios: Use Title Case

Scenario: Age Pension
Scenario: Youth Allowance Student
Scenario: Family Tax Benefit Part A

Schedules: Use descriptive names with "Rates", "Thresholds", etc.

Schedule: Age Pension Rates
Schedule: Income Test Thresholds
Schedule: Asset Test Limits

Amounts and Periods

Always specify the payment period:

$350.50 per fortnight
$175.25 per week
$4,563.00 per year

Use Australian number formatting:

$1,096.70    # Comma for thousands
$50,000      # Round numbers can omit cents

Comments

Use # for inline comments:

When age >= 67  # Age Pension qualifying age
And residence_years >= 10  # General residence requirement

Validation

The Courgette editor provides real-time validation:

  • Syntax errors: Missing operators, unmatched quotes
  • Reference errors: Undefined schedules or definitions
  • Style warnings: Non-Australian spelling, incorrect capitalisation
  • Structure errors: Missing outcomes, invalid block structure

Generated OpenFisca Code

Courgette generates complete OpenFisca implementations including:

Variables

class youth_allowance_eligible(Variable):
    value_type = bool
    entity = Person
    definition_period = MONTH
    label = "Youth Allowance eligibility"

Formulas

def formula(person, period, parameters):
    age = person('age', period)
    is_student = person('is_student', period)
    parental_income = person('parental_income', period)
    
    return (
        (age >= 16) and (age <= 24) and
        (is_student == True) and
        (parental_income < 60000)
    )

Parameters (YAML)

youth_allowance_base_rates:
  description: Youth Allowance Base Rates
  values:
    single_at_home:
      value: 350.50
    single_away_from_home:
      value: 512.50

Advanced Features

Nested Conditions

When is_couple == true
And all of these are true:
  - any of these are true:
    - partner_age >= 67
    - partner_has_disability == true
  - combined_income < 80000
  - combined_assets < 900000

Multiple Reductions

Then payment is $1,000 per fortnight
And payment reduces by 25 cents per dollar over $200
And payment reduces by 50 cents per dollar over $500
And payment cuts out at $1,200

Conditional Schedules

Schedule: Complex Rates
  When single and age < 21: $400
  When single and age >= 21: $500
  When couple and combined_income < 40000: $800
  When couple and combined_income >= 40000: $700

Best Practices

  1. Start simple: Write basic scenarios first, add complexity gradually
  2. Use definitions: Extract complex calculations into named definitions
  3. Be explicit: Write == true rather than relying on implicit booleans
  4. Comment edge cases: Document special rules and exceptions
  5. Group related rules: Keep scenarios for the same benefit together
  6. Test thoroughly: Validate against real-world examples

Roadmap

  • Implicit boolean conditions (When is_student without == true)
  • Date-based conditions (When date >= "2024-01-01")
  • Arithmetic in conditions (When income + assets < 100000)
  • OpenFisca to Courgette reverse compilation
  • Model Context Protocol tooling
  • Direct compilation to CUDA for GPU policy modelling
  • Multi-language support (te reo Māori)

Contributing

The Courgette Method is open source and welcomes contributions. Areas where help is needed:

  1. Additional Australian benefits: Implement more scenarios
  2. Validation rules: Improve error messages and hints
  3. Documentation: Add more examples and tutorials
  4. Testing: Create test suites for complex scenarios

License

MIT License - See LICENSE file for details

Acknowledgements

Built for the Australian Government Rules as Code community. Special thanks to:

  • The OpenFisca team for the underlying engine
  • The Australian Digital Transformation Agency
  • Policy makers who provided feedback on readability

Remember: The goal is legislation that's as easy to read as a recipe, but as precise as code.

About

Plain English rules that compile to code – making legislation both readable and executable

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published