ZecBooks · site: zecbooks.app · source: sane-apps/SaneBooks (historical repo path).
Private books for shielded Zcash — Mac-native, local-first. Import a viewing key, classify income / change / expense, and share a scoped proof pack with your accountant. Cannot spend ZEC.
Download for Mac · MIT open source (LICENSE)
CipherPay gets you paid privately. ZBooks runs team treasury. ZecBooks is the Mac bookkeeping layer: private money, kept with honest books — change ≠ income, and an expiring .sanebooks pack — not a permanent UFVK.
Shielded Zcash already has viewing keys (ZIP 316). Merchants can take ZEC privately. What is missing is an accountant layer: classify change so it is not counted as income and hand a CPA a scoped artifact — not a permanent UFVK and not an unreviewed wallet dump. Fiat marks remain user/import supplied; ZecBooks does not currently claim a live price-source integration.
Community signal: Is anyone actually using viewing keys for business accounting? (Jun 2026).
| Step | What happens |
|---|---|
| 1 | Import a UFVK (uview…) for bookkeeper mode (or UIVK for receivables-only, with a permanent degraded-mode banner) |
| 2 | Sync compact history via lightwalletd (ZcashLightClientKit 2.7.0-rc.4; demo via SANEBOOKS_FORCE_MOCK=1) |
| 3 | Tag rows: Income / Expense / Change / Fee — change is excluded from income totals |
| 4 | Build an encrypted, Reader-expiring .sanebooks pack or intentionally export non-expiring plaintext CSV/PDF |
| 5 | Accountant opens Reader mode — read-only rows, no vault key, no chain sync |
The Appearance settings include persisted Standard, Large, and Extra Large text sizes. This is app-managed because Apple documents that SwiftUI Dynamic Type does not change text size on macOS; the large layouts scroll instead of compressing or hiding primary controls.
- Not a wallet — no seeds, no spending keys, no send UI
- Not CipherPay — CipherPay is merchant checkout / IVK payment detect; ZecBooks starts after money arrives
- Not ZBooks — ZBooks is team/DAO treasury + SIWZ + approved ZIP 321 payouts (web). ZecBooks is solo owner → CPA on a local Mac with expiring proof packs
- Not tax software — we export accountant-ready rows; the CPA owns filing
- Not “temporary UFVK access” — viewing keys are irrevocable; share packs, not raw keys
- Reject seed phrases and spending-key strings at import
- Prefer bookkeeper mode on UFVK; UIVK never claims complete books
- Proof packs carry fingerprint + classified rows only — never embed UFVK/UIVK
- Pack footer names lightwalletd endpoint + tip height + “assumes honest LWD”
- No iCloud / CloudKit for vault data; the imported key uses ThisDeviceOnly Keychain storage. Live sync also creates sensitive, owner-only Zcash SDK account data in backup-excluded Application Support storage.
- CSV/PDF are plainly labeled non-expiring plaintext; only
.sanebooksis encrypted and Reader-expiring - Pack format v2 uses PBKDF2-HMAC-SHA256 (600,000 iterations), ChaCha20-Poly1305, authenticated canonical headers, and encrypted private metadata
NU6.3 / Ironwood activated on mainnet at height 3,428,143 (ZIP 258). New shielded receives land in Ironwood, not Orchard.
ZecBooks links ZcashLightClientKit 2.7.0-rc.4 (Ironwood receive/sync; tracking issue #1806 closed). Live path imports a UFVK as view-only and syncs against a configurable lightwalletd (default zec.rocks:443). Demo/offline still uses MockSyncFacade when SANEBOOKS_FORCE_MOCK=1 or the fixture demo key is used.
UIVK/receivables mode cannot import via the public SDK yet — that path stays degraded/honest.
- Build and run (below)
- Import Viewing Key → Use Demo Key → Continue
- Wait for mock sync to catch up
- Open a row → classify → New Proof Pack → export
.sanebooks/ CSV - Reader → unlock pack with passphrase
Requirements: macOS 14+, Xcode 16+.
Use the project wrapper so the Mini, nonzero-test gate, framework repair, receipts, and process cleanup are all applied:
cd ~/SaneApps/apps/SaneBooks
xcodegen generate
./scripts/SaneMaster.rb verify --timeout 1800
./scripts/SaneMaster.rb verify --ui --timeout 1800
./scripts/SaneMaster.rb launchDirect SwiftPM commands are focused diagnostics only, not release or E2E proof. Debug runs without the sandbox; the Release configuration enables App Sandbox, outbound networking, and user-selected files.
Public distribution is the notarized ZecBooks 0.1.1 Sparkle/direct zip:
- Download: https://zecbooks.app/download → https://dist.zecbooks.app/updates/ZecBooks-0.1.1.zip
- Provenance (SHA-256 + Gatekeeper/stapler):
docs/ZecBooks-0.1.1-PROVENANCE.md - Appcast: https://zecbooks.app/appcast.xml
Mini verify --ui was green on the current tree (122 tests including UI journeys).
Historical Mini captures live under:
outputs/visual-audit-sanebooks/
They are useful references, not proof of the current source. Current clean app-only, minimum-size user-journey captures live under outputs/e2e/2026-08-04/final-green/cropped/; build/test receipts live under outputs/verify/ and are qualified in the current session handoff.
Custody and exchange teams run the zecbooks command on Windows, Linux, or macOS. It is a library and a binary, not a second desktop app. It cannot spend.
Keep the spending key offline. Put an incoming viewing key, or a unified full viewing key, on the detection host. Pass --endpoint for that host's own lightwalletd. There is no hidden server. The ledger stays on the host. zecbooks pack writes an expiring .sanebooks proof pack. An accountant opens it with zecbooks open or with the Mac app. The pack does not contain the viewing key.
zecbooks check --key-file viewing.key
zecbooks sync --key-file viewing.key --endpoint https://lwd.example:9067 --out ledger.json
zecbooks classify --ledger ledger.json --id ROW --as change
zecbooks pack --ledger ledger.json --from 2025-01-01 --to 2025-12-31 --expire 2026-04-15 --passphrase-file pass.txt --out year.sanebooks
zecbooks open --pack year.sanebooks --passphrase-file pass.txt
A full viewing key marks notes on the change address as change, and those rows stay out of the income total. An incoming-only key cannot see that address, so you classify those notes yourself. A partial scan will not seal unless you pass --acknowledge-partial. A start after shielded activation is partial unless you pass --birthday for the account. Spends that cannot be tied to a note in this scan also mark the history partial. Prefer --key-file. --key is accepted and warned, because the shell history keeps it.
Build and test from this repo:
cargo test --manifest-path rust/Cargo.toml --lockedContainer, from the rust directory: docker build -f Containerfile . Mount the key file and the ledger on /data. Do not copy them into the image.
GitHub Actions builds a checksummed binary for Windows, Linux, and macOS. Nothing in the tool phones home.
A viewing key reveals shielded history. Treat the key file like a bank-feed password.
| Doc | Purpose |
|---|---|
| docs/GRANT_PROPOSAL.md | Coinholder-Directed Retroactive Grant application |
| docs/ZecBooks-0.1.1-PROVENANCE.md | SHA-256 + notarization check for 0.1.1 |
| docs/SUBMIT_PACKET.md | FPF + forum paste packet |
| docs/COMPETITIVE_POSITIONING.md | vs CipherPay, Zodl, ZGo, Koinly, ZBooks |
| docs/WALLET_VIEWING_KEY_GUIDE.md | How to export a UFVK from common wallets |
| docs/LIVE_PROBE_FUNDING.md | How to fund the live probe UA for a real ledger row |
| SECURITY.md / PRIVACY.md | Threat model and data boundaries |
| AGENTS.md | Agent / contributor project facts |
MIT. Contact: hi@saneapps.com




