# portfolio-optimiser-claude ## Kontekst Søsken-implementasjon (beslutning D7) av portfolio-optimiser-metoden på **Claude Agent SDK**: generisk, åpent Python-rammeverk som finner kostnadsbesparelser INNI hvert prosjekt i en portefølje. Bygges **fra metode-spec-en alene** (`shared/method-spec.md`) — aldri ved reverse-engineering av MAF-søskenet (`~/repos/portfolio-optimiser`). Program-planer (sesjonsplan S5–S12, sammenligningsprotokoll, frossent målbilde) bor i hovedrepoets `docs/plan/`. Løpende state: `STATE.md` (local-only). ## Stack Python ≥3.10. **Claude Agent SDK** (`claude-agent-sdk` ≥0.2, verifisert 0.2.110 per 2026-07-03: MIT-lisens, bundler Claude Code CLI — ingen separat installasjon; import og konstruksjon fungerer uten API-nøkkel, nøkkel trengs kun ved faktisk `query()`). Pakkehåndtering: `uv`. Pydantic for kontrakts-validering. ## Konvensjoner - Type hints overalt; `mypy --strict`. `ruff` for lint+format. `pytest` for test. - **Testsuiten kjører uten API-nøkkel og uten nettverk** (invariant fra S5; håndhevet ved at all kontrakts-/kontekst-logikk er ren config/fil-lag). - Modell-valg som konfig: `src/portfolio_optimiser_claude/data/model_map.json` (rolle→Claude-modell-id per backend-profil, hver profil krever `default`; validert av `contracts.py`). Modell-id-er verifiseres mot offisiell doc før endring. - SDK-primitiver (verifisert 2026-07-03): `query()`/`ClaudeSDKClient`, `ClaudeAgentOptions` (`max_turns`, `max_budget_usd` — førsteklasses USD-tak), `AgentDefinition` (subagenter; sub-felt er camelCase), `@tool` + `create_sdk_mcp_server` (in-process MCP), hooks (`PreToolUse` med `permissionDecision: "deny"` for deterministisk gating). MERK: `SessionStart`/`SessionEnd` finnes IKKE som Python-callback-hooks. - `shared/` er en **git subtree** av [`portfolio-optimiser-commons`](https://git.fromaitochitta.com/ktg/portfolio-optimiser-commons) (source of truth; remote `commons`). Synk er **PULL-ONLY**: endringer committes i commons og hentes med `git subtree pull --prefix=shared commons main --squash`. ALDRI `git subtree push` fra konsument — re-split lekker hele konsument-historikken inn i commons (observert + opprydd i MAF-repoet 2026-07-03). Se `shared/README.md`. ## Kommandoer - Sync: `uv sync` - Test: `uv run pytest` - Lint: `uv run ruff check .` + `uv run ruff format .` - Type: `uv run mypy src` ## Arbeidsflyt (invarianter) - **Rent teknisk rammeverk:** deployer eier DPIA/ROS/behandlingsformål — kun tekniske forutsetninger (lokal-only, provenance, ingen stille egress) + disclaimer. - **Metode-spec-en er normativ** (RFC 2119). Ærlighets-regelen (§1) er ufravikelig: ingen artefakt påstår mer enn implementasjonen gjør; skriptede stand-ins merkes som det. - **Deterministisk validator obligatorisk + blokkerende** (§3 steg 4); golden-suiten (`shared/examples/bygg-energi-mikro/golden.json`) er ENESTE fasit (§7). - **Load-bearing tester** (§11): hver søm bevises med en test som blir RØD når sømmen detaches — grønn-men-død er feilmoden regelen finnes for. - **Stoppkriterier + budsjett-tak påkrevd ved oppstart** (§8; `contracts.py` fail-fast). På kjørestien kommer USD-taket i tillegg via `ClaudeAgentOptions.max_budget_usd`. - **Kostnadsdisiplin (D6):** alt utvikles offline/deterministisk; den ENE ekte API-kjøringen i programmet er S10 (mikro-bundle, billigste egnede modell — per model_map Haiku 4.5 — harde tak, kost loggføres). - **STATE.md er local-only** (gitignored — repoet skal publiseres; STATE når aldri et offentlig speil). ## Communication patterns ### Linking to local files When pointing to local files in responses, always use markdown link syntax with a descriptive name: - Use `[Human-friendly name](file:///absolute/path)` — never bare `file:///...` URLs or autolinks ``. - Always use absolute paths. Never `~/` or relative paths. - For multiple files, render as a bullet list of named markdown links. Why: bare `file://` URLs only render the first as clickable across multiple lines. Named markdown links make each entry independently clickable and look cleaner.