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.
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.
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.
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.
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.
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-usThe 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.
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 pytestRun 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.pyAuthenticate with an account that has access before downloading from a private Hugging Face repository:
hf auth loginVerify 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.
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-cpuRun 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 32Inspect one decoded reconciliation:
uv run cfo-hrm-demo runs/reconciliation/best.pt \
--device cuda \
--seed 3000031 \
--index 0Evaluation 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.
After downloading the Mindweave datasets above, download the promoted checkpoint:
hf download aznatkoiny/cfo-hrm \
--include best.pt \
--local-dir models/cfo-hrmEvaluate 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.jsonExport 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.jsonlUse --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.
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.
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.
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
- Build harder datasets with split and aggregated payments, corrupted references, FX differences, intercompany activity, GL-only items, and multi-period close scenarios.
- Add pairwise-MLP and parameter-matched Transformer baselines, then ablate hierarchy, recurrence, segment count, and deep supervision.
- Train separately evaluated specialist models for AP, close management, cash forecasting, and planning before composing them behind typed contracts.
- 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.
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.