Generic, open framework on Microsoft Agent Framework (MAF): multi-agent cost-saving proposals gated by a mandatory deterministic validator, with HITL learning.
Find a file
Kjell Tore Guttormsen c0d3ba4459 docs(s53): README two-mode CLI matrix + honesty-scoped learning-loop claims + CHANGELOG catch-up
README: the stale one-line CLI mention replaced by the two-mode flag matrix (single-project vs
--portfolio), runnable 'uv run python -m portfolio_optimiser.run ...' examples, the --outbox-dir
!= --verdict-dir self-contamination warning (documented, not enforced), and the --decision/
--rationale inert-in-portfolio note. Honesty scoping: the prior-verdict fold (the learning step)
is stated to happen ONLY on the --bundle-dir path; a --docs-dir-only run is single-shot (no fold).
CHANGELOG [Unreleased]/Added: S5.3 CLI-parity entry (six flags + portfolio mode + load_dimension +
recipe doc) plus catch-up for the shipped-but-undocumented S4.1 (preflight), S4.2 (--live-dry-run),
S5.1 (hitl CLI), S5.2 (notify); stale test count 237 -> 431. extending.md verified accurate (B11
notifier note stands verbatim — main() auto-wires no notifier; no CLI section to sync), left
unchanged.

SC4 honesty grep clean (each hit in bundle-path context, none on a fold-less path):
  grep -rniE 'learning loop|learns from|self-improv' README.md docs/extending.md CHANGELOG.md
  README:11 (system-level) :56 (wiki substrate) :67 (8-step bundle loop);
  CHANGELOG:13 (gated ExpeL fold) :17 (offline simulation). Full suite 431 passed (no code touched).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KNNiJRk1sSwxgVLS5AobT1
2026-07-23 21:51:00 +02:00
.claude/projects docs(i7): trekbrief + trekplan for program-avslutning — execute parked (fresh session) 2026-07-04 20:41:02 +02:00
docs refactor(ingest): adopt shared llm-ingestion-okf v0.3.1 behind a thin adapter 2026-07-20 07:47:55 +02:00
examples test(ingest): http golden extraction, byte-deterministic (I6) 2026-07-04 17:12:34 +02:00
shared chore(shared): subtree pull commons — ingest-spec.md (I1) 2026-07-03 14:04:11 +02:00
spikes fix(fase1): spike B fan-out measures real conversation bleed, not a counter 2026-06-24 11:09:55 +02:00
src/portfolio_optimiser feat(s53): CLI mode-exclusivity refusals (portfolio vs single-project partition) 2026-07-23 21:44:23 +02:00
tests test(s53): main()-level --verdict-dir coverage (already-wired flags confirmed, not re-wired) 2026-07-23 21:46:01 +02:00
.gitignore docs(truth): S1 truth maintenance — CHANGELOG, stack line, MCP claim, conflict semantics, 90% cut-list 2026-07-03 00:34:56 +02:00
.python-version feat: initial scaffold (Python framework on Microsoft Agent Framework) 2026-06-23 22:01:22 +02:00
CHANGELOG.md docs(s53): README two-mode CLI matrix + honesty-scoped learning-loop claims + CHANGELOG catch-up 2026-07-23 21:51:00 +02:00
CLAUDE.md docs(claude-md): S4 — record commons subtree relation + pull-only sync rule 2026-07-03 05:44:29 +02:00
CODE_OF_CONDUCT.md chore(release): MIT license + CONTRIBUTING/SECURITY/CODE_OF_CONDUCT + README badges (S12) 2026-07-05 08:10:09 +02:00
CONTRIBUTING.md chore(release): MIT license + CONTRIBUTING/SECURITY/CODE_OF_CONDUCT + README badges (S12) 2026-07-05 08:10:09 +02:00
env.template docs(fase2): add env.template documenting both profiles + no-egress notes 2026-06-26 00:43:26 +02:00
LICENSE chore(release): MIT license + CONTRIBUTING/SECURITY/CODE_OF_CONDUCT + README badges (S12) 2026-07-05 08:10:09 +02:00
pyproject.toml refactor(ingest): adopt shared llm-ingestion-okf v0.3.1 behind a thin adapter 2026-07-20 07:47:55 +02:00
README.md docs(s53): README two-mode CLI matrix + honesty-scoped learning-loop claims + CHANGELOG catch-up 2026-07-23 21:51:00 +02:00
SECURITY.md chore(release): MIT license + CONTRIBUTING/SECURITY/CODE_OF_CONDUCT + README badges (S12) 2026-07-05 08:10:09 +02:00
uv.lock refactor(ingest): adopt shared llm-ingestion-okf v0.3.1 behind a thin adapter 2026-07-20 07:47:55 +02:00

portfolio-optimiser

License: MIT Python Built on Microsoft Agent Framework

A generic, open framework — built on Microsoft Agent Framework (MAF) — that finds cost savings inside each project of a portfolio of independent projects. A swarm of agents generates candidate measures; a mandatory deterministic validator (solver + Monte Carlo) decides the numbers; domain experts judge the outcomes (human-in-the-loop); and the system learns from their verdicts across runs.

Status: the full 8-step agentic loop is wired and proven with load-bearing tests, and the end-to-end proof is an offline simulation with a scripted stand-in client — no live-model run yet. The ingest layer (real data sources) is implemented — file/CSV and SQL on both stacks with bit-identical golden extractions from the shared spec, plus HTTP as a MAF-only demonstrated extension point against a local mock — but exercised only against committed fixtures: no bundle has yet been materialized from a live source. A sibling implementation of the same method on the Claude Agents SDK is built in parallel from the same shared spec.

Disclaimer — technical framework only. Deploying organizations own their processing purposes and assessments (DPIA, risk/ROS, security review). The framework ships the technical prerequisites — local-only mode, provenance, no silent data egress — but makes no compliance guarantees.

Built on an LLM wiki: Karpathy's idea, Google's format

The knowledge architecture is the heart of the project, and it is deliberately not ours:

  • The idea is Andrej Karpathy's "LLM wiki": instead of pointing a model at documents written for people, you curate a small, versioned body of knowledge written for the model to read — concept files, explicit structure, explicit links.
  • The format is Google Cloud's Open Knowledge Format (OKF) (open spec, v0.1), which formalizes that pattern: a knowledge bundle is a directory of markdown files with YAML frontmatter (one required field, type), a reserved index.md entry point, and intra-bundle cross-links forming an emergent graph. Custom frontmatter fields are allowed and must be preserved — which is exactly where this project's own layers (expert verdicts, ingest provenance) live.

Because OKF is open and vendor-neutral, the same bundles are consumed unchanged by both reference implementations (MAF and the Claude Agents SDK sibling) — the knowledge outlives any particular agent stack.

Not RAG. Agents read a bundle by navigating it — index.md first, then its cross-links, with progressive disclosure — never by keyword retrieval or stuffing the whole bundle into a prompt. Query-time retrieval against the bundle is explicitly forbidden by the method spec: it would leak the verdict layer around the learning gate.

AI-first, humans on top

A traditional wiki is built for people — optimized for humans finding and reading information, with machine access bolted on afterwards. This project inverts that order, and is a concrete example of what that looks like:

  • The wiki (the OKF bundle) is written for the model: it is the agent's working memory and the substrate the learning loop reads from and promotes into.
  • The human affordances are layers on top: experts judge outcomes by dropping a plain JSON verdict file in an inbox folder; an explicit, fail-closed promotion gate is the only path by which an approved verdict becomes wiki knowledge; reports and reviews are rendered from the machine-readable layers.

Humans stay decisive — nothing enters the wiki without an approval — but the primary reader of every file is the model, not a person browsing.

How it works

One run, one project, eight steps — with the learning loop closing across runs:

  1. Understand — navigate the project's OKF bundle; fold the candidate's prior expert verdicts into the hypothesis prompt (ExpeL-style, retrieved structurally, never by text).
  2. Hypothesise — one typed candidate measure (strict IR, fail-fast schema).
  3. Debate — a maker-checker pair argues the reasoning (round-capped).
  4. Validate — two falsifiers on the same candidate: the deterministic validator gates the numbers (blocking, never optional) and the checker gates the reasoning.
  5. Refine — a rejected attempt retries informed by the rejection reason, under hard attempt and token caps. Unbounded loops are forbidden everywhere.
  6. Propose or discard — a validated proposal with risk percentiles, or a typed rejection.
  7. Expert feedback — days later, an expert drops a verdict file in an inbox folder; a later run picks it up. Fully resumable; no live session assumed.
  8. Promote — an approved verdict is lifted into the wiki as a type: verdict concept file, navigable by the next run. The gate is fail-closed: raw agent output never self-promotes.

Every proposal carries provenance (citations into the bundle, model, validator decision, token usage). Every seam above is protected by a load-bearing test — a test designed to fail when the seam is detached, so the loop cannot silently degrade into theater.

How it is set up

  • One shared, framework-neutral core (shared/, a git subtree of portfolio-optimiser-commons): the business concept, the normative method spec and ingest spec, the expert-reviewer persona as an Agent Skill, and an example bundle with a golden suite as the only ground truth. Both stacks implement from the spec alone.

  • Per project: one OKF bundle — the bundled examples are hand-curated; the ingest layer that materializes a bundle from a source (file catalogues/CSV + SQL, HTTP as a MAF-only demonstrated extension point) via a deterministic, schema-validated manifest that runs before the loop is implemented and exercised against committed fixtures — no bundle has yet been materialized from a live source.

  • Run: the run.py CLI has two modes — a documented partition, since one invocation cannot exercise every flag:

    • Single-projectPROJECT_ID --docs-dir <dir>, plus optional --bundle-dir, --verdict-dir, --outbox-dir (which requires --run-id), --dimension-config, --decision/--rationale, and --live-dry-run.
    • Portfolio--portfolio, plus optional --goals, --ledger, --dimension-config; it stops early and prints a goal reached: … line when the accumulated ledger meets a goal.
    # Single-project, offline drill (builds contracts + clients, stops before the first model call):
    uv run python -m portfolio_optimiser.run FV42-GSV-E1 --docs-dir <docs> --bundle-dir <bundle> --live-dry-run
    # Portfolio run with a savings goal checked against an accumulated ledger:
    uv run python -m portfolio_optimiser.run --portfolio --goals goals.json --ledger ledger.json
    

    The prior-verdict fold — the learning step — happens only on the --bundle-dir path; a plain --docs-dir-only run is single-shot (no fold). --decision/--rationale apply to the single-project path only and are inert in portfolio mode. --outbox-dir must differ from --verdict-dir: writing the raw outbox into a folder later read as an inbox would re-ingest raw agent output past the promotion gate (self-contamination) — documented here, deliberately not CLI-enforced. Stop criteria and budget caps are required at startup. Try the offline end-to-end proof (no model, no network): uv run python -m portfolio_optimiser.simulation.

What this enables

The reference case is portfolio cost review (the example bundle is a building-energy measure), but the architecture is designed to generalize to any setting with the same shape — candidate measures inside independent projects, numbers a deterministic tool can check, and judgement only an expert has:

  • Portfolio reviews — cost savings, energy efficiency, maintenance and procurement measures, proposed per project and validated against the project's own data.
  • Compounding organizational memory — approved expert verdicts become navigable knowledge; the next run's hypotheses start from what experts actually decided, including realization gaps no solver can compute.
  • Auditable AI — an unbroken provenance chain from expert decision back through proposal, bundle file and text span, and (with ingest) to the source system, query, and timestamp.
  • Vendor-neutral knowledge — the same bundles drive two different agent stacks; switching frameworks does not orphan the organization's curated knowledge.

Docs

Stack & develop

Python ≥3.10 · MAF via the split GA packages (see pyproject.toml) · uv. Backend profiles: Azure/Foundry (full) + local (fallback).

uv sync
uv run pytest
uv run ruff check .