feat: the CPA package carries the evidence; the site answers 'why not QuickBooks?'

CPA package: every receipt behind the period's entries with an index,
company documents, the journal as IIF, the 1099 worksheet, and a README;
include_receipts=false for a light package. The scaffolded AGENTS.md
covers receipts from email, switching from QuickBooks/Xero/spreadsheets,
and working with the CPA. GUI: a books copy without a server database
reads 'Read-only copy'. Site: example prompts, QuickBooks comparison,
what it does and doesn't do yet, the CPA section, FAQ.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MtYEaR6M6Ybdhm6X98BWNu
This commit is contained in:
swaitsandClaude Opus 5.5 committed 2026-10-12 17:14:42 -07:00
1 parent 9694d2a89a
commit 45784266b5
7 files changed
+338 -48

No files matched your search

+33 -1
View File
@@ -871,13 +871,18 @@ fn mcp_statement_pdfs_and_cpa_package_over_stdio() {
.map(|i| zip.by_index(i).unwrap().name().unwrap().to_string())
.collect();
names.sort();
let (receipts, rest): (Vec<&String>, Vec<&String>) =
names.iter().partition(|n| n.starts_with("receipts/"));
assert_eq!(
names,
rest,
[
"1099-worksheet-2026.csv",
"README.txt",
"balance-sheet.pdf",
"balance-sheet.xlsx",
"cash-flow.pdf",
"cash-flow.xlsx",
"general-journal.iif",
"general-journal.xlsx",
"general-ledger.xlsx",
"profit-and-loss.pdf",
@@ -888,9 +893,36 @@ fn mcp_statement_pdfs_and_cpa_package_over_stdio() {
"trial-balance.xlsx"
]
);
// Every receipt behind the period's entries, plus an index tying them
// to their entries.
assert!(receipts.iter().any(|n| *n == "receipts/index.csv"));
let files = receipts.len() - 1;
assert!(files > 0, "receipts included");
let mut index = String::new();
std::io::Read::read_to_string(&mut zip.by_name("receipts/index.csv").unwrap(), &mut index)
.unwrap();
assert_eq!(
index.lines().count(),
files + 1,
"one index row per receipt"
);
let mut readme = String::new();
std::io::Read::read_to_string(&mut zip.by_name("README.txt").unwrap(), &mut readme).unwrap();
assert!(readme.contains("hash-chained journal"), "{readme}");
let mut cf = Vec::new();
std::io::Read::read_to_end(&mut zip.by_name("cash-flow.pdf").unwrap(), &mut cf).unwrap();
assert!(cf.starts_with(b"%PDF"));
// Without receipts, a lighter package.
let light = mcp.call(
"books.export_cpa_package",
json!({"as_of": "2026-10-31", "cash_accounts": ["1000"], "include_receipts": false}),
);
let light = zip::ZipArchive::new(std::io::Cursor::new(
b64.decode(light["content_base64"].as_str().unwrap())
.unwrap(),
))
.unwrap();
assert_eq!(light.len(), rest.len());
}
#[test]