# Recipe: building a knowledge base *(Norwegian title kept from the programme plan — «oppskrift» = recipe. Contents in English, like the rest of this repo's documentation.)* This is the documented **team process** for building the OKF bundles this framework reads. It is a recipe, not a wizard: there is deliberately no onboarding interview and no guided verdict command. Both were evaluated and rejected — a setup this consequential is done by people talking to each other, and a wizard would hide exactly the decisions that need deciding. **Honest expectation: 1–2 weeks of dedicated work** for a knowledge base worth running against. The quality of that investment decides the quality of everything downstream. A thin bundle produces confident nonsense; the deterministic validator will catch arithmetic, but it cannot catch a domain the base never described. **Honesty rule (method spec §1):** this document separates what this repo *does today* from what the process *will* look like once the bundle factory exists. Sections marked **NOT BUILT** describe a target arrangement, not a capability you can use. ## 1. The team Setup is always done by a small team, never by one person and never by a tool alone: | Role | Brings | Owns | |---|---|---| | Technical | the file formats, the ingest layer, the run entrance, the caps | the bundle's *shape* | | Domain expert(s) | what is actually true in this domain, and what the numbers hide | the bundle's *content* | The split matters because the two failure modes are different. A technically perfect bundle with no domain substance runs cleanly and tells you nothing. A domain-rich pile of documents that never navigates is invisible to the loop. ## 2. What a knowledge base is here One **OKF bundle** per project: a directory of plain markdown, plus the IR projection the deterministic validator consumes. From the shared micro example ([`shared/examples/bygg-energi-mikro/`](../shared/examples/bygg-energi-mikro/)): ``` bygg-energi-mikro/ index.md # REQUIRED entry point; links to everything else bygg-kontor-nord.md # type: project — the asset and its baseline tiltak-led-retrofit.md # type: hypothesis — the candidate measure + parameters metode-ipmvp-a.md # type: methodology — how savings are measured kilder-realiseringsgap.md # type: reference — sourced literature verdict-led-fro.md # type: verdict — an expert judgement (see §5) validator-input.json # the IR projection the validator consumes ``` Four rules the code actually enforces — verify against these, not against intent: 1. **`index.md` is the entry point.** A bundle without one fails fast (`navigate_bundle`). 2. **The index's cross-links define the bundle.** Navigation follows the links in `index.md`; a file nobody links to is a file the model never sees. Links containing a path separator are skipped (fail-closed boundary rule), so keep concept files flat and beside the index. 3. **Every non-index file needs a `type` in its frontmatter.** `project`, `hypothesis`, `methodology`, `reference`, `verdict` are the types in use. 4. **`type: verdict` files are excluded from the read-context.** A verdict reaches the next hypothesis only through the experience fold, never by leaking through context. This is a seam, not a preference — see the load-bearing tests. `validator-input.json` is separate and **required by the run entrance**: it is the candidate measure projected into the cost-IR (`project_id`, `measure`, `affected_items` with quantity and unit cost, `claimed_saving_nok`). Writing it is technical work, and it is where the domain expert's parameters become numbers the validator can refuse. ## 3. The process, week by week **Day 1–2 — scope and one skeleton.** Pick *one* project and *one* candidate measure. Build the bundle above end to end, however thin. Run it: ```bash uv run python -m portfolio_optimiser_claude.preflight uv run python -m portfolio_optimiser_claude.costsim --projects 1 uv run python -m portfolio_optimiser_claude.run --bundle --live-dry-run \ --outbox --run-id skeleton-1 ``` The drill builds everything a real run builds and stops before the first model call, so the rig is proven before anyone spends anything. Do not proceed to content until this is clean. **Day 3–7 — content, expert-led.** The domain experts fill in what the skeleton only named: the baseline the asset actually has, the method by which a saving is measured, and — the part that matters most — the *sourced* reference material describing where modelled numbers and realized numbers diverge. In the micro example this is `kilder-realiseringsgap.md`, and it is the reason the learning loop has anything to learn. **Day 8–10 — seed the judgement layer.** Add at least one `type: verdict` file encoding what the experts know that the model does not: the correction they would apply and *why*. Without this the first runs have no experience to fold, and the loop is a validator with extra steps. **Ongoing — sufficiency review.** Ask the base directly: *is this comprehensive enough to be useful, and what is missing?* The answer becomes the domain experts' work list. This review is human-run today; an automated evaluator is part of the factory (**NOT BUILT**, §7). ## 4. The domain expert's interface The expert is asked exactly three things: **what** to contribute, **how**, and **where**. They deliver files in their own formats — notes, spreadsheets, reports, memos — and are never asked to fill in a schema or hand-write JSON. **Today:** a technical team member transcribes those contributions into bundle files. This is the interim arrangement, and it is real work — budget for it in the 1–2 weeks. The AI translator that would do it is **NOT BUILT** (§7). **Tabular sources are the exception, and they are automated.** If the contribution is a CSV catalogue or a local SQL database, the ingest layer materializes an OKF bundle from it deterministically, with provenance frontmatter and a `generated: true` honesty marker. That path makes zero model calls and touches no network. See [`docs/extending.md`](extending.md). ## 5. Verdicts — the loop's fuel After a run, an expert judges the proposal. The verdict is a plain-JSON file dropped into an inbox folder; a later run merges it before the fold. The shape (§4.2) is deliberately small: an `id`, a `decision`, a `rationale`, and the proposal features the verdict is about. **Today:** the same transcription applies — the expert judges in their own words, a technical team member writes the verdict file. The decision is the human's in both arrangements; only the typing changes. **NOT BUILT — the target arrangement.** The expert delivers a free-format file and the factory AI-translates it into the strict verdict format, because at volume manual translation is unrealistic. Approval in practice then becomes **spot checks** in the generated bundle, which only works with one guard in place: *the structured verdict must always point back at the expert's original file*, so a spot check can compare what the expert wrote against what the system understood. **The verdict is the human's judgement; the AI is a translator.** Any implementation of this that drops the provenance pointer breaks the arrangement. ## 6. Reading and editing bundles Bundles are plain markdown with frontmatter, so **Obsidian or VS Code is the reading solution** — Obsidian in particular follows the cross-links the way the framework navigates them, which makes "what will the model actually see?" answerable by clicking. A dedicated reading view is a later building block in the toolkit repo, not a prerequisite. ## 7. What is not built Named here so the recipe cannot be mistaken for a description of shipped capability (§1): - **The bundle factory** — the tooling that would translate free-format expert contributions (and verdicts) into bundle files. It lives in a separate toolkit repo that **does not exist yet**. Everything above marked NOT BUILT depends on it. - **The demo path** — fresh clone → unzip a worked example into a bundle inbox → the factory builds it → the whole loop runs. Factory-dependent, and honest only once the factory is real: the point of that demo is that it shows the actual process with finished content. - **A dedicated reading view** for bundles (see §6). - **A dimension catalogue** — the formalized scoping of measure types and cost codes. Today the routing table treats a measure as a config string; the catalogue is gated on a pending amendment to the shared spec. ## 8. Checklist before the first real run - [ ] `index.md` exists and links every concept file that should be visible. - [ ] Every non-index file has a `type` in its frontmatter. - [ ] `validator-input.json` matches the hypothesis file's parameters. - [ ] At least one `type: verdict` file encodes real expert correction. - [ ] Reference material is sourced — a claim without a source is a claim the experts cannot defend when the model repeats it back. - [ ] `preflight` is clean and `costsim` gives a cost you have accepted. - [ ] `--live-dry-run` completes and its captured artifacts look right. - [ ] Stop criteria and a budget cap are set — the framework refuses to start without them.