Skip to content

Command line (gspio)

You have written a model. Now you want to run it over a portfolio, trace a single life that disagrees with your spreadsheet, check a data file before you trust it, or look up the accessor or the regulation you need while you work — without writing a runner script each time.

gspio is the command installed with gaspatchio. It does all of the above from the shell:

gspio --help
 Model Execution
   run-model           Execute an actuarial model from a file
   run-single-policy   Execute an actuarial model for a single policy
   calc-graph          Generate a calculation graph from a model run
 Data Inspection
   describe            Describe the structure of a data file
 Knowledge Discovery
   docs                Search Gaspatchio framework documentation
   knowledge           Search the actuarial knowledge base
 Tutorial
   tutorial            List, initialize, and verify gaspatchio tutorials

Two inputs every run takes

Every model run takes two files:

  • a model file — a .py with a main(af) function that takes an ActuarialFrame and returns it with your results assigned;
  • a model-points file — a .parquet, one row per policy.

The fastest way to get both is to copy a worked model out of the box. gspio tutorial init level-1 writes the Hello World term-life model used throughout this page; pair it with a small portfolio of three policies:

import polars as pl

pl.DataFrame(
    {
        "policy_id":      ["POL001", "POL002", "POL003"],
        "age":            [30, 45, 60],
        "sex":            ["M", "F", "M"],
        "sum_assured":    [500_000, 250_000, 100_000],
        "annual_premium": [450, 1_200, 2_800],
        "mortality_rate": [0.001, 0.004, 0.015],  # annual qx
        "expense_rate":   [0.10, 0.10, 0.10],     # share of premium
    }
).write_parquet("model_points.parquet")

The model.py you initialised computes expected claims, expenses, net premium, profit, and a loss ratio for each policy. Everything below runs against these two files. For a full production model that ships its own assumptions and model points, gspio tutorial init level-4 writes a lifelib book reconciled to the reference cashflows.


Run a model over the portfolio — run-model

Project every policy and read the portfolio result in one command:

gspio run-model model.py model_points.parquet
Result (Columns filtered by -f/-l):
shape: (3, 13)
┌───────────┬─────┬─────┬─────────────┬────────────────┬────────────────┬──────────────┬─────────────────┬──────────┬─────────────┬────────┬────────────┬───────────────┐
│ policy_id ┆ age ┆ sex ┆ sum_assured ┆ annual_premium ┆ mortality_rate ┆ expense_rate ┆ expected_claims ┆ expenses ┆ net_premium ┆ profit ┆ loss_ratio ┆ is_profitable │
│ str       ┆ i64 ┆ str ┆ i64         ┆ i64            ┆ f64            ┆ f64          ┆ f64             ┆ f64      ┆ f64         ┆ f64    ┆ f64        ┆ str           │
╞═══════════╪═════╪═════╪═════════════╪════════════════╪════════════════╪══════════════╪═════════════════╪══════════╪═════════════╪════════╪════════════╪═══════════════╡
│ POL001    ┆ 30  ┆ M   ┆ 500000      ┆ 450            ┆ 0.001          ┆ 0.1          ┆ 500.0           ┆ 45.0     ┆ 405.0       ┆ -95.0  ┆ 1.1111     ┆ No            │
│ POL002    ┆ 45  ┆ F   ┆ 250000      ┆ 1200           ┆ 0.004          ┆ 0.1          ┆ 1000.0          ┆ 120.0    ┆ 1080.0      ┆ 80.0   ┆ 0.8333     ┆ Yes           │
│ POL003    ┆ 60  ┆ M   ┆ 100000      ┆ 2800           ┆ 0.015          ┆ 0.1          ┆ 1500.0          ┆ 280.0    ┆ 2520.0      ┆ 1020.0 ┆ 0.5357     ┆ Yes           │
└───────────┴─────┴─────┴─────────────┴────────────────┴────────────────┴──────────────┴─────────────────┴──────────┴─────────────┴────────┴────────────┴───────────────┘

The result is the model points plus every column your model computed. A wide result is shown as a window — the first and last columns, with the middle elided — so the table fits your terminal.

Option Effect
--mode, -m debug (default) records each step so you can inspect the calculation; optimize skips the bookkeeping for the fastest run.
--first-n, -f Number of leading columns to show (default 5).
--last-n, -l Number of trailing columns to show (default 10).
--start-at, -s Column index to start the window at (default 0).
--rows, -r Number of rows to show (default 15).
--output-file, -o Write the full result to a parquet file instead of printing.

To keep the full result rather than a printed window, write it out:

gspio run-model model.py model_points.parquet --mode optimize --output-file results.parquet

Trace a single policy — run-single-policy

When one life disagrees with your existing model, run that policy on its own and read its result back column by column:

gspio run-single-policy model.py model_points.parquet POL001 --policy-id-column policy_id
Transposed Result (Columns filtered by -f/-l):
shape: (1, 13)
┌───────────┬─────┬─────┬─────────────┬───┬─────────────┬────────┬────────────┬───────────────┐
│ policy_id ┆ age ┆ sex ┆ sum_assured ┆ … ┆ net_premium ┆ profit ┆ loss_ratio ┆ is_profitable │
│ str       ┆ i64 ┆ str ┆ i64         ┆   ┆ f64         ┆ f64    ┆ f64        ┆ str           │
╞═══════════╪═════╪═════╪═════════════╪═══╪═════════════╪════════╪════════════╪═══════════════╡
│ POL001    ┆ 30  ┆ M   ┆ 500000      ┆ … ┆ 405.0       ┆ -95.0  ┆ 1.1111     ┆ No            │
└───────────┴─────┴─────┴─────────────┴───┴─────────────┴────────┴────────────┴───────────────┘

The policy id is the third argument. --policy-id-column names the column that holds it — it defaults to Policy number, so set it to match your data (policy_id here). For a projection model with a time dimension, this returns one row per period: the full trace for that life, which is what you reconcile against your spreadsheet step by step. The same --mode and display options as run-model apply.


Export the calculation graph — calc-graph

To audit what feeds what — which inputs and which intermediate columns each result depends on — export the calculation graph:

gspio calc-graph model.py model_points.parquet --policy-id-column policy_id -o graph.json
✓ Calculation graph saved to: graph.json
  Nodes: 13 (7 inputs, 6 computed)
  Edges: 11

graph.json holds nodes (the input columns and the computed ones, each with its dtype, formula, dependencies, and a sample value) and edges (the dependency from each column to the ones it is built from):

{
  "id": "expected_claims",
  "type": "computed",
  "label": "expected_claims = [(col(\"sum_assured\")) * (col(\"mortality_rate\"))]",
  "data": {
    "dtype": "float",
    "dependencies": ["mortality_rate", "sum_assured"],
    "formula": "[(col(\"sum_assured\")) * (col(\"mortality_rate\"))]",
    "value_sample": 500.0,
    ...
  }
}

The graph is captured for models written as traced column expressions (af.expected_claims = af.sum_assured * af.mortality_rate), which is what the debug run records. Narrow it to one life with --policy-id/-p, and supply sample values from a chosen period with a Polars filter, --filter "col('year') == 1".


Inspect a data file — describe

Before you trust a model-points or assumptions file, read its shape — columns, dtypes, and a sample:

gspio describe model_points.parquet
File Analysis: model_points.parquet
Format: LONG
Rows: 3
Columns: 7

Sample Data (first 5 rows):
shape: (3, 7)
┌───────────┬─────┬─────┬─────────────┬────────────────┬────────────────┬──────────────┐
│ policy_id ┆ age ┆ sex ┆ sum_assured ┆ annual_premium ┆ mortality_rate ┆ expense_rate │
│ str       ┆ i64 ┆ str ┆ i64         ┆ i64            ┆ f64            ┆ f64          │
╞═══════════╪═════╪═════╪═════════════╪════════════════╪════════════════╪══════════════╡
│ POL001    ┆ 30  ┆ M   ┆ 500000      ┆ 450            ┆ 0.001          ┆ 0.1          │
│ POL002    ┆ 45  ┆ F   ┆ 250000      ┆ 1200           ┆ 0.004          ┆ 0.1          │
│ POL003    ┆ 60  ┆ M   ┆ 100000      ┆ 2800           ┆ 0.015          ┆ 0.1          │
└───────────┴─────┴─────┴─────────────┴────────────────┴────────────────┴──────────────┘

describe reads .parquet, .csv, and .xlsx, detects whether the file is shaped as an assumption table, and names the likely value and key columns. --value-column overrides the detected value column; --json emits the structure as JSON for a tool to consume.


Start from a worked model — tutorial

The tutorials are runnable models you copy into your own directory and run with the commands above:

gspio tutorial list
 Level    Description
 level-1  Hello World — term life portfolio, column arithmetic, when/then
 level-2  Assumptions — mortality/lapse table lookups, multi-dimension tables
 level-3  Mini Variable Annuity — account values, guarantees, dynamic lapse
 level-4  Reconciled Lifelib — production model reconciled to 0.0000% vs lifelib
 level-5  Scenarios — parameter shocks, sensitivity analysis, stress testing

gspio tutorial init level-3 --dest ./va-model copies a level into ./va-model (--force overwrites an existing one), and gspio tutorial verify level-3 runs it and checks the output against the expected result. The Tutorials page walks each level end to end.


Look up the docs or an actuarial concept — docs and knowledge

While building a model you reach for two things: how a gaspatchio feature works, and what a regulation or actuarial concept requires. Search both from the shell — and so can an LLM working alongside you:

gspio docs "cumulative survival probability"
gspio knowledge "IFRS 17 risk adjustment" --jurisdiction EU

Each returns the ranked excerpts as JSON — several sources you can weigh against the model in front of you, rather than a single answer:

{
  "results": [
    {
      "text": "Tests for cumulative_survival() method.",
      "score": 0.775,
      "content_type": "overview",
      "object_path": "test_projection.TestCumulativeSurvival",
      "has_code": false
    },
    ...
  ],
  "query": "cumulative survival probability"
}
Option Effect
--limit, -n Number of results to return.
--search-type, -s hybrid (default), semantic for concepts, or keyword for exact names.
--content-type, -t (docs) restrict to code_example, overview, when_to_use, or parameters.
--tag/--jurisdiction/--doc-type (knowledge) filter by tag (IFRS17, SolvencyII, …), jurisdiction, or document type.
--answer, -a Summarise the sources into one answer. Use sparingly — the ranked excerpts let you judge each source yourself.

The Knowledge Store page covers both stores, what they hold, and how to keep them current.


Version and shell completion

gspio --version            # the installed package and core versions
gspio --install-completion  # add tab-completion to your shell