# Project export: Folio

This document was generated by HackStack to give an AI agent context about a hackathon project. Sections are labeled with their provenance; content marked as truncated was cut to keep this document small.

## Project metadata

- Hackathon: OpenAI Build Week
- Tagline: Private finance help for contractors and small businesses, from messy transactions and cash-flow questions to clean records and ready-to-share documents.
- Devpost: https://devpost.com/software/folio-fawlrq
- GitHub: https://github.com/ImDanielGitHub/folio
- Video: https://www.youtube.com/embed/W7ISyfluO8c?enablejsapi=1&hl=en_US&rel=0&start=&version=3&wmode=transparent
- Team: 1 GitHub contributor(s) — Aneke, Daniel (Student) (18 commits)

## Devpost submission (written by the team)

### Inspiration

I work as an independent contractor, so the line between personal and business spending is not always as clean as it should be. Some expenses are obvious. Others need a sentence of context that only I know. I might pay for work material on a personal card, use one software subscription across several contracts, or look at a healthy balance without remembering that rent and a stack of renewals are about to land. By the time I sit down to sort everything out, I am often trying to remember why I made a purchase weeks earlier. I had been following ChatGPT Finance and Perplexity Finance because asking a question is a much more natural way to explore money than building another spreadsheet. Many finance products and bank connections still do not support New Zealand, though. I saw an opportunity to make something useful straight away for independent contractors, sole traders and small-business owners here. Privacy mattered too. Handing years of transactions, receipts and business information to an online service is a big commitment. Folio can work with a local model through LM Studio, on the owner's computer. If the computer cannot comfortably run a capable model, the owner can explicitly choose a cloud model instead. LM Studio's Bionic also shaped the build. Its local agent experience showed how much the application around a model matters: give the model a focused set of tools, catch bad responses and help it recover. I applied those ideas to finance, then hid most of that machinery from the main screen. Folio is the product I wanted for my own work: I can explain a purchase in ordinary language, ask how the business is doing and get the relevant number, chart or document beside the conversation.

### What it does

Folio opens with a conversation, not a wall of finance widgets. It imports transaction data, works out what deserves attention and asks one useful question at a time. If an answer needs a chart, transaction, table or document, Folio opens it beside the conversation. Close that view and the app returns to a simple thread. The demo follows a fictional New Zealand business through one connected piece of work: Daily Close finds a duplicate software charge, a MITRE 10 purchase with missing context and the current cash position. The owner explains that the MITRE 10 purchase was material for a client fit-out and asks Folio to treat similar purchases under $500 the same way. Folio updates the item, saves the explanation for later and offers Undo. A cash scenario compares buying a laptop now with deferring it, including the effect on the owner's reserve. A Telegram-style message — “Parking for the client meeting, $32.40. Expense it” — adds timely context for the next close. Folio prepares an owner pack from the same saved figures, with open questions and cash assumptions included. Small source links connect important figures to the bank row, owner explanation or document behind them. The default demo uses fictional data. Folio also includes optional read-only Akahu support for New Zealand accounts and settled transactions. A Plaid sandbox path demonstrates its read-only Link and transaction flow. Neither connector is attached to a real bank account in the public demo. For conversation, Folio can use a model loaded in LM Studio or an optional OpenAI model. The financial history stays intact when the owner changes models. How I built it Folio is a standalone Electron app built during OpenAI Build Week. The desktop interface uses React, TypeScript and Vite. A local FastAPI service does the finance work, and SQLite stores conversations, imported records, corrections, findings and generated documents. The language model does not calculate balances or rewrite financial records by itself. Money is stored as integer minor units, while tested Python code handles totals, duplicate detection, corrections, cash scenarios and owner-pack preparation. The model interprets the request, chooses an appropriate finance tool and explains the result. That separation also makes smaller local models more useful. Folio selects a short list of tools for each request instead of presenting the whole catalogue. Tool inputs have narrow schemas. If a response is almost valid, Folio gets one bounded repair attempt; repeated or invalid calls are stopped. Supported finance requests can then fall back to the same local operations used by the demo. Long conversations cannot fit in one prompt forever. Folio keeps the original bank rows, documents and owner messages, then links them to people, businesses, transactions, explanations and later corrections. Each new question receives the relevant part of that history. A correction supersedes the old understanding but does not erase it. The interface uses a closed set of financial views. A model can request a transaction, cash scenario, records table, work receipt or owner pack, but it cannot send arbitrary interface code to Electron. LM Studio runs over the computer's loopback connection. The optional cloud path uses the OpenAI Responses API. The owner chooses the route in Privacy & models; Folio does not switch from local to cloud in the background. I used Codex with GPT-5.6 throughout the week. It helped me investigate finance and local-model products, separate this project from my earlier Hermes Finance experiment, build the API and desktop app, write tests, recover work from failed branches and debug the LM Studio integration. I made the product calls, including a major redesign after the first interface exposed far too much activity and accounting detail. Challenges I ran into The hardest problem was getting useful work from a small local model without trusting a confident-looking answer. Models can choose the wrong tool, leave out an argument, return nearly valid JSON or repeat an action. I put validation, a small repair budget and loop detection around model calls. The finance service remains responsible for every saved amount and change. Conversation history was the second challenge. A useful answer can depend on a bank row, a receipt, something the owner said three weeks ago and a correction made yesterday. Sending the complete history on every turn becomes slow and eventually exceeds the model's context window. Folio instead retrieves a smaller current picture while keeping a route back to the original records. The design took several passes as well. An early version displayed every finding, process stage and evidence record at once. It was technically informative and exhausting to use. The current version keeps the thread calm and opens the extra finance view only when it helps answer the question. Accomplishments that I'm proud of The whole demo runs through one finance service and one saved history: import, Daily Close, duplicate handling, correction, Undo, cash scenarios and owner-pack preparation. The totals in the pack match the figures shown in the conversation. I am also proud of the continuity. The owner can give a detailed explanation, correct it later, restart the app or change models, and Folio can still use the current version without losing the earlier record. The local path fails clearly. If LM Studio is unavailable or a model response cannot be used, Folio preserves the last valid financial state. It does not quietly send the data to a cloud provider or show a made-up result. What makes the project feel finished to me is that it now serves the person I built it for. It helps a contractor deal with the small explanations, timing decisions and loose ends that sit between a bank feed and finished accounts. What I learned A local finance assistant depends as much on its surrounding application as it does on model size. A smaller model does noticeably better with a relevant summary of the business and a few precise tools. Giving it every record and every available action usually makes it worse. I also learned that financial memory needs dates and sources. “MITRE 10 is normally a business expense” is too broad to be useful. Folio needs to know which purchase the owner explained, what they actually said, how far the new rule should reach and whether they later changed their mind. The interface lesson was simpler: internal detail is useful for debugging, but owners mostly need to know what happened, why it matters and what to do next. The audit trail is still there when they want to inspect it.

### What's next

My next step is to put Folio in front of independent contractors and sole traders in New Zealand. I want to run a small Akahu pilot with read-only accounts, improve receipt matching and connect Telegram so an owner can add context while a purchase is still fresh. Scheduled Daily Close summaries are also on the list, so Folio can prepare the next useful update even when the desktop window is closed. The cash view currently compares known commitments and alternative dates. Future work could improve recurring-payment detection, learn categories from owner corrections and compare more cash-flow scenarios while keeping every assumption visible. Folio is free and open source. I want contractors and small businesses to be able to inspect it, adapt it and run it on their own computers. 5.6 helped with reverse engeering tools like lm stuios bionic as well as loking at hermes fincance tool

## README (from the GitHub repository)

# Folio

Folio is a local-first finance operator for New Zealand sole traders and small businesses. It starts as one calm conversation, quietly maintains a source-linked picture of the business, and opens a financial canvas only when an answer needs a chart, table, transaction, evidence view or prepared document.

This repository contains a working Build Week prototype. It is not a bank, accounting ledger, payment product, tax-filing service or financial adviser.

## The product loop

The sample business demonstrates one end-to-end workflow:

1. Folio ingests a synthetic bank CSV and runs an idempotent Daily Close.
2. Deterministic services reconcile transactions, flag a likely duplicate, surface an unsupported expense and calculate a 30-day cash scenario.
3. The conversation leads with the practical meaning instead of exposing a workflow engine.
4. The owner explains a MITRE 10 purchase naturally and at length.
5. Folio stores the full statement, applies a narrowly scoped correction, preserves the previous understanding as superseded history and exposes Undo.
6. A cash scenario or owner pack appears beside the conversation only when requested.
7. Every material amount remains linked to committed source evidence.

The model plans and explains; deterministic finance code owns amounts, transaction selection, effects, forecasts, evidence and generated documents.

## What is implemented

| Capability | Current proof |
|---|---|
| Chat-first Electron/React workspace | Source, TypeScript build and browser runtime |
| Dynamic finance canvas | Living brief, transaction, cash scenario, records, owner pack and receipt surfaces |
| Deterministic finance authority | Exact minor-unit arithmetic, fixture contracts and Python tests |
| Daily Close | Idempotent local API workflow over the synthetic fixture |
| Durable working understanding | Immutable owner statements, structured facts, provenance, retrieval receipts, contradiction tracking and supersession |
| Long-conversation continuity | Restart/model-switch integration test with early-turn retrieval and correction |
| Small-model harness | Closed plan schemas, bounded parsing/repair, validation, loop limits and deterministic fallback |
| Local model route | LM Studio loopback adapter and capability discovery; one Qwen 3.5 9B transport smoke recorded separately |
| Optional cloud route | Thin OpenAI Responses API adapter; no live credential is required for local or fixture operation |
| Evidence-backed artefacts | Deterministic HTML/PDF owner-pack generator and source links |
| Telegram-shaped input | Synthetic fixture adapter only; no real bot or owner account is connected |
| Akahu connector | Sealed NZ fixture by default; optional config-gated read-only live sync |
| Plaid connector | Sealed US fixture by default; optional config-gated sandbox Link / sync |

See [PROTOTYPE_RECEIPT.md](PROTOTYPE_RECEIPT.md) for current verification and explicit gaps.

## Architecture

```text
Electron + React conversation/canvas
                |
        loopback HTTP + SSE
                |
        FastAPI application service
                |
   bounded planner / executor / verifier
          |                 |
 deterministic finance   model router
          |              /            \
   SQLite + artefacts  LM Studio     OpenAI
```

Important boundaries:

- SQLite is the durable source for conversations, finance events, findings, evidence, model receipts and working understanding.
- Source records and owner statements are immutable. Corrections append a replacement and supersession link instead of overwriting history.
- Local, Hybrid and Cloud change model routing, not finance truth or conversation identity.
- The renderer accepts a closed `FinanceSurfaceSpec@1` catalogue. Models cannot emit executable UI code.
- The local API binds only to loopback.

## Quick start

### Requirements

- Node.js 22 or newer
- pnpm 10.33.0
- Python 3.12
- uv 0.9.25 or compatible

### Install

```bash
pnpm install --frozen-lockfile
uv sync --project services/api --frozen
```

### Run the live local application

```bash
./run
```

This starts the FastAPI service on `127.0.0.1:8787`, the Vite renderer on `127.0.0.1:4173`, and the Folio Electron app. Stop it with `Ctrl+C`.

For separate development processes, run:

```bash
pnpm dev
pnpm dev:electron
```

No account or external model is needed for the example workspace. For the intended conversational experience, load a tool-capable model in LM Studio and enable its local server at `127.0.0.1:1234` before opening Folio.

### Open the sealed UI fixture

For UI review without the backend:

```bash
pnpm dev:browser
```

Then open `http://127.0.0.1:4173/?demo=1`. Fixture mode never calls LM Studio or a cloud provider.

## Verification

```bash
pnpm contracts:check
pnpm lint
pnpm typecheck
pnpm test
pnpm build
pnpm test:golden
pnpm eval:offline
```

Optional live local-model evaluation, only when LM Studio already has the configured synthetic-test model loaded:

```bash
FOLIO_LM_STUDIO_MODEL=folio-qwen3.5-9b pnpm eval:lmstudio:live
```

The offline evaluation compares raw model JSON acceptance with Folio's bounded repair and validation path. It is parser/harness evidence, not a claim that every local model performs equally well. The live runner reports model-authored plan accuracy separately from effective accuracy after deterministic fallback.

## Model modes and privacy

- **Local** uses LM Studio on `127.0.0.1`. If the server or selected model is unavailable, Folio reports that state and uses a bounded deterministic fallback; it does not silently call the cloud.
- **Hybrid** keeps finance computation local and permits only a typed projection to the configured cloud adapter.
- **Cloud** may use the OpenAI Responses API for planning/explanation, but deterministic finance services still own amounts and effects.

Model selection is in the quiet Privacy & Models drawer, not in the ordinary conversation flow. No telemetry is included. Do not place credentials, real financial exports, bot updates or customer documents in this repository.

## Synthetic data

All committed data under `fixtures/` is fictional. The example business, its people, accounts, transactions, documents, dates and identifiers are demo material created for this project. Reset with:

```bash
pnpm demo:reset
pnpm demo:daily-close
pnpm demo:golden
```

Repeated ingestion and Daily Close runs use digests and idempotency keys so the same source does not silently create duplicate finance effects.

## Build Week provenance

Folio is a new standalone repository created during OpenAI Build Week. The bootstrap and every implementation commit are dated after the submission period opened. It independently reimplements useful architectural principles learned from public documentation and clean-room inspection; it does not contain Hermes or Bionic branding, proprietary prompts, minified bundles or UI assets.

The key implementation commits are recorded in [BUILD_WEEK.md](BUILD_WEEK.md). Clean-room and reference boundaries are in [CLEAN_ROOM.md](CLEAN_ROOM.md), [SOURCE_REUSE_MAP.md](SOURCE_REUSE_MAP.md), [ATTRIBUTION.md](ATTRIBUTION.md) and [REFERENCE_UI_DECISION.md](REFERENCE_UI_DECISION.md).

Codex with GPT-5.6 was used for research, architecture, implementation, test generation, debugging, integration and adversarial review. The application also contains an optional GPT-5.6 Responses API adapter, but a live cloud runtime result must not be claimed unless separately recorded.

## Current limits

- The default data source is a synthetic fixture, local CSV, or sealed Akahu/Plaid connector feed; live bank sync is config-gated and off by default.
- Telegram support is fixture-backed. No real bot round trip is part of the proof.
- The cash forecast is a deterministic scenario over known fixture commitments, not predictive certainty.
- A local-model transport smoke is recorded; the four-case live model benchmark is optional and may not have been run 

[README truncated for size]

## Detected evidence (automated analysis)

Indexed codebase: 110 recognized source files, 1161 KB.
- CSS (language) — detected in the code
- FastAPI (technology) — detected in the code
- HTML (language) — detected in the code
- Python (language) — detected in the code
- React (technology) — detected in the code
- TypeScript (language) — detected in the code
- OpenAI (technology) — claimed on Devpost, not found in the code

## Codebase structure (from repository index)

### Files (120 of 175)

```
.env.example
.gitignore
apps/desktop/index.html
apps/desktop/package.json
apps/desktop/src/App.tsx
apps/desktop/src/Drawer.tsx
apps/desktop/src/fixtures.ts
apps/desktop/src/format.ts
apps/desktop/src/icons.tsx
apps/desktop/src/main.tsx
apps/desktop/src/main/.gitkeep
apps/desktop/src/main/main.ts
apps/desktop/src/Onboarding.tsx
apps/desktop/src/preload/.gitkeep
apps/desktop/src/preload/preload.cts
apps/desktop/src/renderer/.gitkeep
apps/desktop/src/styles.css
apps/desktop/src/SurfaceRenderer.tsx
apps/desktop/src/transport.ts
apps/desktop/src/types.ts
apps/desktop/src/vite-env.d.ts
apps/desktop/tests/.gitkeep
apps/desktop/tsconfig.electron.json
apps/desktop/tsconfig.json
apps/desktop/vite.config.ts
ATTRIBUTION.md
BOOTSTRAP_RECEIPT.md
BUILD_CONTRACT.md
BUILD_WEEK.md
CLEAN_ROOM.md
contracts/examples/akahu-fixture-request.json
contracts/examples/dialogue-frame.json
contracts/examples/egress-receipt.json
contracts/examples/finance-event.json
contracts/examples/finance-plan.json
contracts/examples/model-receipt.json
contracts/examples/plaid-fixture-request.json
contracts/examples/surface-work-receipt.json
contracts/examples/undo-request.json
contracts/examples/undo-response.json
contracts/manifest.json
contracts/schemas/api-snapshot.schema.json
contracts/schemas/common.schema.json
contracts/schemas/dialogue-frame.schema.json
contracts/schemas/egress-receipt.schema.json
contracts/schemas/finance-event.schema.json
contracts/schemas/finance-plan.schema.json
contracts/schemas/finance-surface-spec.schema.json
contracts/schemas/model-receipt.schema.json
contracts/schemas/run-event-stream.schema.json
contracts/schemas/run-event.schema.json
contracts/schemas/undo-request.schema.json
contracts/schemas/undo-response.schema.json
DEVPOST_DRAFT.md
DEVPOST_SUBMISSION.md
evals/.gitkeep
evals/README.md
evals/results/narrative-guard.json
evals/results/offline-harness.json
evals/run_live_lmstudio_harness.py
evals/run_narrative_guard.py
evals/run_offline_harness.py
evidence/ui/.gitkeep
fixtures/demo/akahu-sync.json
fixtures/demo/canonical-ids.json
fixtures/demo/expected-outcomes.json
fixtures/demo/koru-studio-bank-2026-07.csv
fixtures/demo/plaid-sync.json
fixtures/demo/telegram-attachment-reference.json
fixtures/demo/telegram-update.json
fixtures/ui/daily-close-events.json
fixtures/ui/surface-cash-scenario.json
fixtures/ui/surface-living-brief.json
fixtures/ui/workspace-snapshot.json
LICENSE
package.json
pnpm-workspace.yaml
PROTOTYPE_RECEIPT.md
README.md
REFERENCE_UI_DECISION.md
RESEARCH_ARCHITECTURE_BRIEF.md
run
scripts/contracts_check.py
scripts/demo_control.py
scripts/dev.mjs
scripts/golden_flow.py
scripts/not-implemented.mjs
services/api/pyproject.toml
services/api/README.md
services/api/src/finance_agent/__init__.py
services/api/src/finance_agent/agent/__init__.py
services/api/src/finance_agent/agent/business_discovery.py
services/api/src/finance_agent/agent/catalogue.py
services/api/src/finance_agent/agent/controller.py
services/api/src/finance_agent/agent/DEPENDENCIES.md
services/api/src/finance_agent/agent/dialogue.py
services/api/src/finance_agent/agent/events.py
services/api/src/finance_agent/agent/executor.py
services/api/src/finance_agent/agent/fallback.py
services/api/src/finance_agent/agent/harness.py
services/api/src/finance_agent/agent/narrative.py
services/api/src/finance_agent/agent/parser.py
services/api/src/finance_agent/agent/plan.py
services/api/src/finance_agent/agent/ports.py
services/api/src/finance_agent/api/__init__.py
services/api/src/finance_agent/api/app.py
services/api/src/finance_agent/api/routes/__init__.py
services/api/src/finance_agent/api/routes/dependencies.py
services/api/src/finance_agent/api/routes/router.py
services/api/src/finance_agent/api/services.py
services/api/src/finance_agent/api/working_understanding.py
services/api/src/finance_agent/artifacts/__init__.py
services/api/src/finance_agent/artifacts/owner_pack.py
services/api/src/finance_agent/connectors/__init__.py
services/api/src/finance_agent/connectors/akahu_fixture.py
services/api/src/finance_agent/connectors/akahu.py
services/api/src/finance_agent/connectors/base.py
services/api/src/finance_agent/connectors/plaid_fixture.py
services/api/src/finance_agent/connectors/plaid.py
services/api/src/finance_agent/connectors/README.md
[55 more files omitted for size]
```

### Dependencies

- apps/desktop/package.json: @types/node@26.1.1, @types/react@19.2.17, @types/react-dom@19.2.3, @vitejs/plugin-react@6.0.3, electron@43.1.1, react@19.2.7, react-dom@19.2.7, typescript@7.0.2, vite@8.1.5
- services/api/pyproject.toml: fastapi@>=0.116,<1, httpx@>=0.28,<1, jsonschema@>=4.25,<5, pydantic@>=2.11,<3, python-multipart@>=0.0.20,<1, reportlab@>=4.4,<5, uvicorn@>=0.35,<1

### Recent commits (newest first)

- feat: add one-click demo reset
- fix: finish Folio submission experience
- fix: restore submission acceptance gate
- fix: remember answered business questions and owner profile facts
- merge: Plaid connector and demo trust improvements onto main
- feat: ask thin-profile business questions and tighten demo trust UX
- feat: add config-gated Plaid connector with sealed fixture
- docs: record local model discovery proof
- docs: record final integration and product gaps
- merge: reconcile superseded submission branch into canonical main
- feat: complete Folio submission product
- Ship Folio submission buildout with Akahu fixture and dark Paper desktop.
- feat(desktop): build chat-first Folio workspace
- feat(agent): add durable local finance runtime
- feat: add bounded finance agent harness
- feat: implement deterministic Koru finance core
- chore: complete bootstrap artifact scaffold
- chore: lock finance app bootstrap contracts

## Key source files (fetched from GitHub, selected and truncated for size)

### PROTOTYPE_RECEIPT.md

```markdown
# Folio prototype receipt

This receipt is being refreshed against the recovered persistent checkout. It separates source, tests, runtime, model and external-system proof. Final command results and browser captures are added only after the corresponding check completes.

## Current source

- Recovery source: `folio-recovery-48984ee.bundle`
- Verified recovery head: `48984eecbe7fb8c46042b2e8fff0e6ceb25c189a`
- Bundle SHA-256: `120e96f5c01c2eb2791270b9bd9ceda5a193e3bcac4fbfb830b06de0b2f57f7f`
- Active persistent checkout: `folio-recovered-workspace`

## Proof ledger

| Area | Status | Evidence |
|---|---|---|
| Contract validation | Refresh pending | `pnpm contracts:check` |
| Python tests | Refresh pending | `pnpm test:python` |
| Ruff/MyPy/TypeScript | Refresh pending | `pnpm lint`, `pnpm typecheck` |
| Production build | Refresh pending | `pnpm build` |
| Golden API flow | Refresh pending | `pnpm test:golden`, `pnpm demo:golden` |
| Offline harness | Refresh pending | `pnpm eval:offline` |
| Internal-browser UI | Refresh pending | Light desktop/mobile, dynamic canvas, evidence, onboarding and failure states |
| LM Studio | Prior smoke only | Qwen 3.5 9B loopback transport; full live four-case result not yet recorded |
| OpenAI cloud | Not live-verified | Adapter source and contract behaviour only; no credential supplied |
| Devpost | Draft only | Project `1328264`; no judging submission |

## Explicit non-proof

Passing tests do not prove a packaged judge build, public deployment, public repository, effective licence, live bot, bank connection, YouTube video or submitted Devpost entry.

```

### ATTRIBUTION.md

```markdown
# Attribution and reference register

Folio does not vendor or copy third-party product source, prompts, branding, data or UI assets. Declared package dependencies are installed through pnpm/uv and remain governed by their upstream licences.

## Pattern and interface references

| Source | Version/date | Use in Folio | Code/assets copied? |
|---|---|---|---|
| Hermes Agent / Hermes Finance | Inspected 17 Jul 2026; exact source commit in `SOURCE_REUSE_MAP.md` | Connector, model-adapter and finance-tool boundary research | No |
| LM Studio Bionic | App 1.0.0+1 plus public material | Local harness and split conversation/document principles | No |
| LM Studio developer API | Current public loopback API | Independently authored HTTP adapter | No |
| ChatGPT | Current conversation product | Calm chat-first composition and progressive disclosure | No |
| Manus Refero screen `ede70d77-f1cb-4902-a407-c608023df5a9` | Refero capture inspected 17 Jul 2026 | Historical split-workspace behaviour reference | No |
| Brex Refero style `7471a4ea-ab61-4281-8f19-2d65352efc44` | Refero capture inspected 17 Jul 2026 | Light finance typography and restrained accent research | No |
| Paper Folio prototype `01KXQWFD5CAYZWBV88B3WNFZCA` | Inspected during implementation | Folio-specific hierarchy, canvas and drawer interaction reference | No |

The Manus/Brex direction was subsequently narrowed by Daniel's correction: the default product is a light conversation, not a permanently visible split workspace or finance dashboard. That supersession is recorded in `REFERENCE_UI_DECISION.md`.

## Runtime dependencies

See `pnpm-lock.yaml` and `services/api/uv.lock` for exact dependency versions. React, Vite, Electron, FastAPI, Pydantic, SQLite bindings, ReportLab, httpx, pytest, Ruff and MyPy are ordinary package dependencies; none is vendored in this repository.

## Future adaptations

Before landing copied or substantially adapted third-party code or an asset, add its source, exact version/commit, licence, affected files and the nature of the adaptation here. An inspiration link alone is not a licence.

```

### package.json

```
{
  "name": "folio",
  "version": "0.0.0",
  "private": true,
  "description": "Folio local-first finance workspace",
  "license": "Apache-2.0",
  "packageManager": "pnpm@10.33.0",
  "engines": {
    "node": ">=22"
  },
  "scripts": {
    "install:all": "pnpm install --frozen-lockfile && uv sync --project services/api --frozen",
    "api": "services/api/.venv/bin/uvicorn finance_agent.api.app:app --app-dir services/api/src --host 127.0.0.1 --port 8787",
    "dev": "node scripts/dev.mjs",
    "dev:browser": "pnpm --filter @folio/desktop dev:browser",
    "dev:electron": "pnpm --filter @folio/desktop dev:electron",
    "contracts:check": "services/api/.venv/bin/python scripts/contracts_check.py",
    "lint": "services/api/.venv/bin/ruff check services/api/src services/api/tests && pnpm --filter @folio/desktop typecheck",
    "typecheck": "services/api/.venv/bin/mypy services/api/src/finance_agent && pnpm --filter @folio/desktop typecheck",
    "test:python": "services/api/.venv/bin/pytest -q services/api/tests",
    "test": "pnpm contracts:check && pnpm test:python && pnpm --filter @folio/desktop typecheck",
    "build": "pnpm --filter @folio/desktop build",
    "demo:reset": "services/api/.venv/bin/python scripts/demo_control.py reset",
    "demo:daily-close": "services/api/.venv/bin/python scripts/demo_control.py daily-close",
    "demo:golden": "services/api/.venv/bin/python scripts/golden_flow.py",
    "test:golden": "services/api/.venv/bin/pytest -q services/api/tests/integration/test_golden_api.py",
    "eval:offline": "PYTHONPATH=services/api/src services/api/.venv/bin/python evals/run_offline_harness.py && PYTHONPATH=services/api/src services/api/.venv/bin/python evals/run_narrative_guard.py",
    "eval:lmstudio:live": "PYTHONPATH=services/api/src services/api/.venv/bin/python evals/run_live_lmstudio_harness.py",
    "test:local-model": "services/api/.venv/bin/pytest -q services/api/tests/models/test_lm_studio.py services/api/tests/agent/test_harness_controller.py && pnpm eval:offline",
    "test:cloud-model": "services/api/.venv/bin/pytest -q services/api/tests/models/test_narrative_guard.py services/api/tests/agent/test_harness_controller.py",
    "test:telegram-live": "node scripts/not-implemented.mjs test:telegram-live connectors"
  }
}

```

### apps/desktop/package.json

```
{
  "name": "@folio/desktop",
  "version": "0.1.0",
  "private": true,
  "description": "Folio local-first finance workspace desktop client",
  "license": "Apache-2.0",
  "type": "module",
  "main": "dist-electron/main/main.js",
  "scripts": {
    "dev:browser": "vite",
    "build:electron": "tsc -p tsconfig.electron.json",
    "dev:electron": "pnpm build:electron && electron dist-electron/main/main.js --renderer-url=http://127.0.0.1:4173",
    "typecheck": "tsc -p tsconfig.json --noEmit && tsc -p tsconfig.electron.json --noEmit",
    "build": "pnpm build:electron && vite build"
  },
  "dependencies": {
    "react": "19.2.7",
    "react-dom": "19.2.7"
  },
  "devDependencies": {
    "@types/node": "26.1.1",
    "@types/react": "19.2.17",
    "@types/react-dom": "19.2.3",
    "@vitejs/plugin-react": "6.0.3",
    "electron": "43.1.1",
    "typescript": "7.0.2",
    "vite": "8.1.5"
  }
}

```

### services/api/pyproject.toml

```
[build-system]
requires = ["hatchling>=1.27,<2"]
build-backend = "hatchling.build"

[project]
name = "folio-local-api"
version = "0.0.0"
description = "Loopback API for the Folio local-first finance workspace"
readme = "README.md"
requires-python = ">=3.12,<3.13"
license = "LicenseRef-Provisional-Apache-2.0"
dependencies = [
  "fastapi>=0.116,<1",
  "httpx>=0.28,<1",
  "jsonschema>=4.25,<5",
  "pydantic>=2.11,<3",
  "python-multipart>=0.0.20,<1",
  "reportlab>=4.4,<5",
  "uvicorn>=0.35,<1",
]

[dependency-groups]
dev = [
  "mypy>=1.17,<2",
  "pytest>=8.4,<9",
  "pytest-asyncio>=1.1,<2",
  "ruff>=0.12,<1",
]

[tool.hatch.build.targets.wheel]
packages = ["src/finance_agent"]

[tool.pytest.ini_options]
testpaths = ["tests"]
asyncio_mode = "auto"

[tool.ruff]
target-version = "py312"
line-length = 100

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "SIM"]

[tool.mypy]
python_version = "3.12"
strict = true
packages = ["finance_agent"]
mypy_path = "src"

```

### apps/desktop/src/main.tsx

```typescript
import React from "react";
import ReactDOM from "react-dom/client";
import { App } from "./App";
import "./styles.css";

ReactDOM.createRoot(document.getElementById("root")!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
);

```

### apps/desktop/src/main/main.ts

```typescript
import { app, BrowserWindow, dialog, ipcMain, shell } from "electron";
import { readFile } from "node:fs/promises";
import { dirname, join } from "node:path";
import { fileURLToPath } from "node:url";

const currentDirectory = dirname(fileURLToPath(import.meta.url));
const apiBase = "http://127.0.0.1:8787";

function rendererUrl(): string | null {
  const argument = process.argv.find((value) => value.startsWith("--renderer-url="));
  return argument?.slice("--renderer-url=".length) ?? null;
}

async function createWindow(): Promise<void> {
  const window = new BrowserWindow({
    width: 1440,
    height: 900,
    minWidth: 860,
    minHeight: 640,
    backgroundColor: "#0d0f0e",
    title: "Folio",
    autoHideMenuBar: true,
    show: false,
    webPreferences: {
      contextIsolation: true,
      nodeIntegration: false,
      sandbox: true,
      preload: join(currentDirectory, "..", "preload", "preload.cjs"),
    },
  });

  window.once("ready-to-show", () => {
    window.show();
    if (process.platform === "darwin") {
      window.setSimpleFullScreen(true);
    } else {
      window.setFullScreen(true);
    }
  });
  window.webContents.setWindowOpenHandler(({ url }) => {
    if (url.startsWith(`${apiBase}/v1/artifacts/`)) {
      void shell.openExternal(url);
    }
    return { action: "deny" };
  });
  window.webContents.on("will-navigate", (event, url) => {
    const allowed = rendererUrl();
    if (allowed && url.startsWith(allowed)) return;
    if (url.startsWith("file://")) return;
    event.preventDefault();
  });

  const developmentUrl = rendererUrl();
  if (developmentUrl) {
    await window.loadURL(developmentUrl);
  } else {
    await window.loadFile(join(currentDirectory, "..", "..", "dist", "index.html"));
  }
}

ipcMain.handle("finance:pick-csv", async () => {
  const result = await dialog.showOpenDialog({
    title: "Import a bank CSV",
    properties: ["openFile"],
    filters: [{ name: "CSV files", extensions: ["csv"] }],
  });
  if (result.canceled || !result.filePaths[0]) return null;
  const path = result.filePaths[0];
  const bytes = await readFile(path);
  return {
    name: path.split(/[\\/]/).at(-1) ?? "source.csv",
    base64: bytes.toString("base64"),
  };
});

ipcMain.handle("finance:open-artifact", async (_event, artifactId: string) => {
  if (!/^[a-z][a-z0-9_]{2,95}$/.test(artifactId)) return false;
  await shell.openExternal(`${apiBase}/v1/artifacts/${artifactId}`);
  return true;
});

app.whenReady().then(async () => {
  await createWindow();
  app.on("activate", () => {
    if (BrowserWindow.getAllWindows().length === 0) void createWindow();
  });
});

app.on("window-all-closed", () => {
  if (process.platform !== "darwin") app.quit();
});

```

### services/api/src/finance_agent/api/app.py

```python
"""Loopback-only FastAPI composition root for the runnable local prototype."""

from __future__ import annotations

from collections.abc import AsyncIterator
from contextlib import asynccontextmanager
from pathlib import Path

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.middleware.trustedhost import TrustedHostMiddleware

from finance_agent.api.routes import create_router
from finance_agent.api.services import LocalRouteServices

ROOT = Path(__file__).resolve().parents[5]
DEFAULT_DATABASE = ROOT / "var" / "finance-agent.sqlite3"


def create_app(
    *,
    database_path: str | Path | None = None,
    auto_seed: bool = True,
) -> FastAPI:
    services = LocalRouteServices(database_path or DEFAULT_DATABASE, auto_seed=auto_seed)

    @asynccontextmanager
    async def lifespan(_: FastAPI) -> AsyncIterator[None]:
        yield
        await services.aclose()

    value = FastAPI(
        title="Folio Local Finance API",
        version="0.1.0",
        docs_url="/docs",
        redoc_url=None,
        lifespan=lifespan,
    )
    value.add_middleware(
        TrustedHostMiddleware,
        allowed_hosts=["127.0.0.1", "localhost", "test", "testserver"],
    )
    value.add_middleware(
        CORSMiddleware,
        allow_origins=[
            "http://127.0.0.1:4173",
            "http://localhost:4173",
            "http://127.0.0.1:4174",
            "http://localhost:4174",
        ],
        allow_credentials=False,
        allow_methods=["GET", "POST", "OPTIONS"],
        allow_headers=["Content-Type", "Last-Event-ID"],
    )
    value.include_router(create_router())
    value.state.finance_route_services = services
    return value


app = create_app()


__all__ = ["app", "create_app"]

```

### pnpm-workspace.yaml

```yaml
packages:
  - apps/*

onlyBuiltDependencies:
  - electron

```

### scripts/demo_control.py

```python
"""Small stdlib client for the loopback-only prototype demo controls."""

from __future__ import annotations

import json
import sys
from urllib.error import HTTPError, URLError
from urllib.request import Request, urlopen

API_BASE = "http://127.0.0.1:8787"


def post(path: str, payload: dict[str, object]) -> dict[str, object]:
    request = Request(
        f"{API_BASE}{path}",
        data=json.dumps(payload).encode(),
        headers={"Accept": "application/json", "Content-Type": "application/json"},
        method="POST",
    )
    with urlopen(request, timeout=20) as response:  # noqa: S310 - fixed loopback URL
        return json.loads(response.read())


def reset() -> dict[str, object]:
    result = post("/v1/demo/reset", {"workspaceId": "ws_koru_studio"})
    close = post(
        "/v1/jobs/daily-close",
        {
            "workspaceId": "ws_koru_studio",
            "idempotencyKey": "cli-demo-reset-close",
        },
    )
    return {"reset": result, "dailyClose": close}


def daily_close() -> dict[str, object]:
    return post(
        "/v1/jobs/daily-close",
        {
            "workspaceId": "ws_koru_studio",
            "idempotencyKey": "cli-daily-close",
        },
    )


def main() -> int:
    command = sys.argv[1] if len(sys.argv) > 1 else "reset"
    try:
        result = reset() if command == "reset" else daily_close()
    except (HTTPError, URLError, TimeoutError) as error:
        print(f"Loopback API unavailable: {error}", file=sys.stderr)
        return 1
    print(json.dumps(result, indent=2, sort_keys=True))
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

```

[93 more indexed source files omitted to keep this export small. The full file list is in the Codebase structure section above.]