Scaffold a Model (Phase 1)
Overview
Turn a company's financials into a runnable pyfpa config. Read the business profile first (see fpa-learn-business), infer the chart-of-accounts → model-line mapping, and write a validated EntityConfig YAML following openfpa conventions. Output a runnable skeleton plus an explicit list of assumptions to confirm.
Core principle: Convention over invention. Map the real numbers onto the existing engine shape; don't design a new one.
When to use
- A trial balance / P&L (CSV, XLSX, or pasted) needs to become a forecast model
- Onboarding follow-on after
.fpa/business-profile.md exists
Workflow
- Ingest the financials:
pyfpa.read_pl_csv(path) (or a pyfpa.io.adapters source) → {account: amount}.
- Map accounts to model lines of the
EntityConfig schema:
- revenue accounts →
channels[] (one Channel per channel/segment, with annual_revenue, a 12-month seasonality weight list, growth_rate, cogs_pct)
- cost accounts →
opex[] as OpexLine(kind="fixed", monthly_amount=…) or kind="variable", pct_of_revenue=…
- debt →
debt[] (term_loan with monthly_principal, or interest-only loc)
- balance-sheet rhythm →
working_capital(dso_days, dpo_days, dio_days) and opening_balances
- Write the company model and config under
models/generated/. Validate
config with pyfpa.load_config(path), which raises on any bad field.
- Create a runnable command such as
python3 models/generated/run_forecast.py. Keep the runner thin and make its
output locations explicit.
- Run and validate it. Confirm the model executes, reconciles its inputs,
and writes the expected outputs.
- Register the tested command with
openfpa entrypoint-register, including
its inputs and outputs. Registration publishes the command for agent
discovery; it does not run it.
- Surface assumptions: list the 6-10 inferences a human must confirm
(seasonality shape, fixed vs variable splits, cogs_pct per channel, opening
balances). Do not bury them.
Conventions (match the engine)
- For a config-backed generated model, keep assumptions in validated YAML rather
than scattering company numbers through code.
- Set
opening_balances AR/AP/inventory to the first forecast month's DSO/DPO/DIO-implied balances - the engine diffs each month against the prior, seeding month 1 against opening, so use month-1 projected revenue/COGS, NOT the annual average. Get this wrong and month-1 cash swings on a one-time artifact (see fpa-cfo-judgment working-capital seam).
"total" is a reserved channel/opex name (the engine adds a total column).
A live-formula Excel edition of the model is available via fpa-excel-model.
Next
Runnable config confirmed → fpa-configure-actuals to wire live/real numbers, then the operate skills.
1---2name: fpa-scaffold-model3description: Use when building a new openfpa forecast model from a company's financials - a trial balance, a P&L export, or a pasted income statement - and you need a runnable config to exist before any forecasting or analysis.4---56# Scaffold a Model (Phase 1)78## Overview910Turn a company's financials into a runnable `pyfpa` config. Read the business profile first (see **fpa-learn-business**), infer the chart-of-accounts → model-line mapping, and write a validated `EntityConfig` YAML following openfpa conventions. Output a runnable skeleton plus an explicit list of assumptions to confirm.1112**Core principle:** Convention over invention. Map the real numbers onto the existing engine shape; don't design a new one.1314## When to use1516- A trial balance / P&L (CSV, XLSX, or pasted) needs to become a forecast model17- Onboarding follow-on after `.fpa/business-profile.md` exists1819## Workflow20211. **Ingest** the financials: `pyfpa.read_pl_csv(path)` (or a `pyfpa.io.adapters` source) → `{account: amount}`.222. **Map accounts to model lines** of the `EntityConfig` schema:23 - revenue accounts → `channels[]` (one `Channel` per channel/segment, with `annual_revenue`, a 12-month `seasonality` weight list, `growth_rate`, `cogs_pct`)24 - cost accounts → `opex[]` as `OpexLine(kind="fixed", monthly_amount=…)` or `kind="variable", pct_of_revenue=…`25 - debt → `debt[]` (`term_loan` with `monthly_principal`, or interest-only `loc`)26 - balance-sheet rhythm → `working_capital(dso_days, dpo_days, dio_days)` and `opening_balances`273. **Write** the company model and config under `models/generated/`. Validate28 config with `pyfpa.load_config(path)`, which raises on any bad field.294. **Create a runnable command** such as30 `python3 models/generated/run_forecast.py`. Keep the runner thin and make its31 output locations explicit.325. **Run and validate it.** Confirm the model executes, reconciles its inputs,33 and writes the expected outputs.346. **Register the tested command** with `openfpa entrypoint-register`, including35 its inputs and outputs. Registration publishes the command for agent36 discovery; it does not run it.377. **Surface assumptions**: list the 6-10 inferences a human must confirm38 (seasonality shape, fixed vs variable splits, cogs_pct per channel, opening39 balances). Do not bury them.4041## Conventions (match the engine)4243- For a config-backed generated model, keep assumptions in validated YAML rather44 than scattering company numbers through code.45- Set `opening_balances` AR/AP/inventory to the **first forecast month's** DSO/DPO/DIO-implied balances - the engine diffs each month against the prior, seeding month 1 against opening, so use month-1 projected revenue/COGS, NOT the annual average. Get this wrong and month-1 cash swings on a one-time artifact (see **fpa-cfo-judgment** working-capital seam).46- `"total"` is a reserved channel/opex name (the engine adds a `total` column).4748A live-formula Excel edition of the model is available via **fpa-excel-model**.4950## Next5152Runnable config confirmed → **fpa-configure-actuals** to wire live/real numbers, then the operate skills.