Skip to content

Aznatkoiny/cfo-hrm

Repository files navigation

CFO-HRM

CFO-HRM is a fully local learning project that applies ideas from the Hierarchical Reasoning Model to a structured CFO workflow: matching bank transactions to general-ledger (GL) entries and routing exceptions for review.

This is an educational prototype, not accounting software. It must not post journal entries, move money, approve reconciliations, or make autonomous financial decisions. Its outputs are proposals for human review.

Released artifacts

The promoted checkpoint and aggregate experiment artifacts live in the CFO-HRM Hugging Face repository. Repository access depends on its current visibility and your account permissions.

Try the public, Gradio-based CFO-HRM Accounting Lab with fictional reconciliation cases.

The source code is licensed under Apache-2.0. The released weights were trained with Mindweave data licensed under CC BY-NC 4.0 and are released under CC BY-NC 4.0; they are for non-commercial learning and research, not commercial accounting use. See THIRD_PARTY_DATA.md for the exact datasets, pinned revisions, attribution, and derived-label policy.

What it does

Each example contains padded bank and GL rows. The model scores permitted bank-to-GL pairs, an unmatched choice for every bank row, and exception classes. A deterministic decoder converts the scores into a globally optimal one-to-one assignment.

bank rows + GL rows + masks
            |
       field encoding
            |
  low/high recurrent reasoning
            |
 pair / unmatched / exception scores
            |
 candidate mask + Hungarian decoder
            |
 proposed matches and review queue
            |
 accounting controls + human approval

Bank reconciliation is useful for studying hierarchical reasoning because the inputs are structured, global consistency matters, and answers can be checked against hard constraints.

Architecture

CFOHierarchicalReasoningModel encodes a batch as [CLS] + bank rows + [SEP] + GL rows using:

  • signed log amount, normalized date, and amount sign;
  • currency, entity, account, counterparty, reference, and description IDs;
  • row-type and learned position embeddings; and
  • bank/GL padding masks plus a conservative candidate-pair mask.

Both levels use padding-aware, non-causal native PyTorch scaled-dot-product attention, Post-RMSNorm, and SwiGLU blocks. Within one segment the low-level module runs multiple fast cycles while the high-level module updates less often. Earlier recurrent passes run without autograd; only the final low/high updates retain a gradient graph. Recurrent state is detached between deep-supervision segments. The current implementation uses a fixed segment count and no adaptive halting.

Output heads produce pair, unmatched, and exception logits. Training combines link classification, exception classification, and a soft one-to-one penalty. At inference, a pure-NumPy rectangular Hungarian solver enforces that each bank row selects one GL row or its own unmatched option and that each GL row is used at most once. Hard assignment remains outside the network.

The project uses native PyTorch attention and has no FlashAttention dependency.

Synthetic data

SyntheticReconciliationDataset generates every sample deterministically from its seed and index, without touching global NumPy or PyTorch RNG state. Bank and GL rows are shuffled independently.

Cases include:

  • ordinary matches;
  • bank-only and GL-only items;
  • bank fees;
  • duplicate bank rows;
  • timing differences;
  • paired reversals routed to review;
  • missing or altered references and descriptions; and
  • positive and negative amounts.

Candidate blocking uses entity, currency, date, and amount tolerances and always preserves true links. Current targets are one-to-one; split settlements and aggregated deposits are future work. Strong synthetic results do not establish performance on a real close.

Mindweave data

The external-data experiment combines revision-pinned synthetic bank and accounting-ledger datasets from Mindweave. Download them into the paths expected by the adapter:

mkdir -p data/raw/mindweave

hf download mindweave/bank-transactions-us \
  --type dataset \
  --revision 290e657395a1ce25837642b8309ca9a741f85303 \
  --local-dir data/raw/mindweave/bank-transactions-us

hf download mindweave/accounting-ledger-us \
  --type dataset \
  --revision b2f2d0890353438b4473f2c3b2d2b5e15a5132a0 \
  --local-dir data/raw/mindweave/accounting-ledger-us

The adapter derives labels from unique source provenance, keeps ambiguous rows out of the matching loss, independently shuffles bank and GL rows, and uses period-disjoint chronological splits. The pinned snapshot contains 3,232 bank rows in 145 cases.

Local setup

Requirements are Python 3.11+, uv, the Hugging Face hf CLI, Go 1.24+ for the control plane, and a PyTorch build appropriate for the machine:

git clone https://github.com/Aznatkoiny/cfo-hrm.git
cd cfo-hrm
uv sync --extra dev
uv run pytest

Run the same read-only accounting lab locally:

uv run --python 3.12 \
  --with 'gradio[mcp]==6.20.0' \
  --with-requirements space/requirements.txt \
  python space/app.py

Authenticate with an account that has access before downloading from a private Hugging Face repository:

hf auth login

Verify acceleration:

uv run python -c "import torch; print(torch.__version__); print(torch.cuda.is_available()); print(torch.cuda.get_device_name() if torch.cuda.is_available() else 'CPU')"

On the local GB10, the locked environment currently resolves to a CUDA 13 PyTorch build. If a future lock refresh installs a build that does not recognize the GB10, install the current compatible Linux/AArch64 PyTorch wheel and verify torch.cuda.is_available() before training. Training, data, metrics, checkpoints, and logs stay local; no cloud logger or financial-data upload is used.

Train, evaluate, and inspect

Run a small CPU smoke experiment:

uv run cfo-hrm-train \
  --device cpu \
  --no-amp \
  --steps 2 \
  --segments 2 \
  --train-samples 64 \
  --val-samples 32 \
  --batch-size 8 \
  --eval-every 1 \
  --eval-batches 1 \
  --output-dir runs/smoke-cpu

Run the default learning experiment on the GPU:

uv run cfo-hrm-train \
  --device cuda \
  --steps 1000 \
  --segments 4 \
  --batch-size 32 \
  --output-dir runs/reconciliation

--steps counts outer batches; every segment performs an optimizer update. Use --help for model, data, optimizer, logging, evaluation, device, and AMP flags. The run directory contains config.json, metrics.jsonl, last.pt, and the validation-F1-selected best.pt.

Evaluate a deterministic held-out set:

uv run cfo-hrm-eval runs/reconciliation/best.pt \
  --device cuda \
  --samples 512 \
  --batch-size 32

Inspect one decoded reconciliation:

uv run cfo-hrm-demo runs/reconciliation/best.pt \
  --device cuda \
  --seed 3000031 \
  --index 0

Evaluation reports match precision/recall/F1, bank-row assignment accuracy, exact-batch accuracy, exception accuracy, unmatched recall, and dollar-weighted accuracy. Candidate blocking can make simple synthetic matches easy, so compare against deterministic rules and non-hierarchical baselines before crediting the HRM architecture.

Run the promoted checkpoint

After downloading the Mindweave datasets above, download the promoted checkpoint:

hf download aznatkoiny/cfo-hrm \
  --include best.pt \
  --local-dir models/cfo-hrm

Evaluate the fixed held-out test split, including the deterministic baseline:

uv run cfo-hrm-eval-mindweave \
  models/cfo-hrm/best.pt \
  --bank-dir data/raw/mindweave/bank-transactions-us \
  --ledger-dir data/raw/mindweave/accounting-ledger-us \
  --split test \
  --device cuda \
  --confidence-threshold 0.9 \
  --output runs/mindweave-hf-test.json

Export held-out case 8 as a typed review request and apply the Go accounting controls:

uv run cfo-hrm-export-review \
  models/cfo-hrm/best.pt \
  --bank-dir data/raw/mindweave/bank-transactions-us \
  --ledger-dir data/raw/mindweave/accounting-ledger-us \
  --split test \
  --case-index 8 \
  --device cuda \
  --output /tmp/cfo-review-request.json

cd orchestrator-go

go run ./cmd/cfo-orchestrator evaluate \
  --input /tmp/cfo-review-request.json \
  --output /tmp/cfo-decision.json \
  --audit /tmp/cfo-audit.jsonl

go run ./cmd/cfo-orchestrator verify-audit \
  --audit /tmp/cfo-audit.jsonl

Use --device cpu --no-amp instead of --device cuda on a machine without a compatible NVIDIA GPU. The complete workflow and output contract are documented in docs/end-to-end-review.md.

Held-out results

The promoted step-50 checkpoint was evaluated on 30 cases containing 702 bank rows from October through December 2025. Selective metrics use a 0.90 confidence threshold.

System Match F1 Exception accuracy Bank-fee recall Auto-match coverage False auto-match rate
Deterministic evidence baseline 100% 99.57% 0% 99.57% 0%
Robust fine-tuned HRM 100% 100% 100% 83.90% 0%

The baseline's perfect matching result is the central caveat: this synthetic dataset is largely solvable using exact amount, date, and provenance evidence, so the experiment does not establish an HRM advantage for matching. The measured gain is exception classification, especially bank fees. With references removed, HRM match F1 fell to 95.42%; with source module, reference, and description removed, it reached 96.28% and bank-fee recall fell to zero. See the full experiment report.

Control boundary

The neural network is a scorer, not a control system. The Go boundary applies deterministic controls for source lineage, unique IDs, one-to-one use, entity, currency, amount and date tolerances, confidence, and disposition. Every result still enters a human-review queue, and posting_authorized is always false. No component contains an ERP posting or approval client. Introduce real data only via approved, anonymized, read-only exports and keep controller approval mandatory.

Project layout

cfo-hrm/
├── README.md
├── THIRD_PARTY_DATA.md
├── pyproject.toml
├── uv.lock
├── docs/
│   ├── end-to-end-review.md
│   └── mindweave-experiment-2026-07-23.md
├── src/cfo_hrm/
│   ├── data.py                 # deterministic synthetic batches
│   ├── mindweave.py            # external-data adapter and splits
│   ├── model.py                # HRM recurrence and scoring heads
│   ├── matching.py             # exact assignment decoder
│   ├── baselines.py            # deterministic evidence baseline
│   ├── metrics.py              # calibration and selective metrics
│   ├── train_mindweave.py      # robust external-data fine-tuning
│   ├── evaluate_mindweave.py   # raw and masked-evidence evaluation
│   ├── export_review.py        # typed model-to-control proposal
│   └── secure_json.py          # atomic owner-only JSON output
├── orchestrator-go/
│   ├── cmd/cfo-orchestrator/   # evaluate and audit-verification CLI
│   ├── internal/contracts/     # versioned review/decision contracts
│   ├── internal/controls/      # deterministic accounting controls
│   ├── internal/audit/         # hash-chained audit log
│   └── examples/
└── tests/                      # Python and integration tests

Next work

  1. Build harder datasets with split and aggregated payments, corrupted references, FX differences, intercompany activity, GL-only items, and multi-period close scenarios.
  2. Add pairwise-MLP and parameter-matched Transformer baselines, then ablate hierarchy, recurrence, segment count, and deep supervision.
  3. Train separately evaluated specialist models for AP, close management, cash forecasting, and planning before composing them behind typed contracts.
  4. Run a governed shadow-mode study on approved, anonymized, read-only exports with accounting-owner review, access and retention controls, signed audit events, monitoring, and explicit promotion criteria.

License

The source code is licensed under Apache-2.0; see LICENSE. Released model weights are licensed under CC BY-NC 4.0 because their training data is non-commercial. Dataset licenses and attribution are documented in THIRD_PARTY_DATA.md.

About

Local hierarchical reasoning for CFO bank-to-GL reconciliation, with PyTorch training, deterministic matching, calibrated abstention, and a Go human-review control plane.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages