- Swift 99%
- Shell 0.7%
- Makefile 0.3%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .github/workflows | ||
| Commons.xcodeproj | ||
| deploy | ||
| scripts | ||
| Sources | ||
| Tests | ||
| .dockerignore | ||
| .gitignore | ||
| buf.yaml | ||
| Makefile | ||
| Package.resolved | ||
| Package.swift | ||
| project.yml | ||
| README.md | ||
Commons
A local-first, single-user double-entry ledger for personal and business finance, built in Swift as a thin gRPC server, a native macOS client, and an MCP surface for AI agents. The correctness model is an append-only ledger, lossless decimal money, and content-hash idempotency. No third-party aggregators: you own the book and the server it runs on.
The design docs (docs/design/server-split.md, docs/DATA_MODEL.md) and the issue history
live in the seltzerhq/pecun repo; the code lives here.
Components
commons-server-- the thin gRPC backend. Owns the SQLite book through a single-writer serial executor plus a read pool, enforces the double-entry invariants, and authenticates every call with a JWT interceptor. Linux-first.- Commons.app -- the native SwiftUI macOS client. Talks to the server over gRPC via
CommonsClient; it never touches the database directly. commons-mcp-- the agent surface. An MCP server that exposes the ledger to AI agents as tools, backed by the same gRPC client againstcommons-server(with its ownrole=agentservice token -- no token pass-through, per the confused-deputy rule).
What the app does
- Accounts sidebar grouped GnuCash-style (Assets, Liabilities, Income, Expenses, Equity) with live all-time balances.
- Register per account: an editable table with date, description, cleared/superseded flags, amount, running balance, category, and memo.
- Reconcile against a statement balance with a cleared-split checklist and a difference summary; optionally post a balancing adjustment.
- Dashboard: net worth, change since last session, runway, asset/liability rollups, a 90-day cashflow projection (Swift Charts), recent reconciliations, report warnings, and a projection-overrides manager.
- Import CSV / OFX / QFX statements (idempotent on re-import; detects amount corrections), with a one-click Bank of America CSV normalizer.
- Tools: revalue an account, accrue interest on lines of credit, manage projection overrides, export to CSV, and hot-backup the book.
The ledger is append-only: edits never mutate a posted transaction. An "edit" posts a reversing
entry plus a replacement whose supersedes_id points at the original, so the audit trail is the
feature and the running balance reflects the net.
Architecture
CommonsCore pure domain + report engine (no I/O; purity-gated). Money (Decimal), currency,
normalization, categorization, net worth / runway / 90-day projection / warnings.
Builds and tests on macOS and Linux.
CommonsStore SQLite persistence + commands + importers. schema 0001 (verbatim from pecun,
incl. the double-entry triggers), 3-step atomic write protocol, content-hash
idempotency, supersedes/correction machinery, CSV/OFX/QFX import, BofA convert.
CommonsProto the gRPC + protobuf wire contract. Swift is generated at build time by the
GRPCProtobufGenerator plugin -- no generated sources are committed.
CommonsServer the backend library: single-writer serial executor, read pool, change registry,
grpc-swift-2 service, and the JWT auth interceptor.
commons-server the runnable server: opens a book, wires the CommonsServer stack, serves it over
the HTTP/2 NIO transport, and mints dev HS256 tokens.
CommonsClient a domain-typed gRPC client (reads + a live-changes stream + auth), transport-
agnostic so the app injects HTTP/2 and tests inject the in-process transport.
CommonsMCP the agent MCP surface: ledger tools backed by CommonsClient, a Streamable-HTTP
host (NIO adapter), and OAuth 2.1 resource-server token validation.
commons-mcp the runnable MCP server (stdio transport entrypoint).
CommonsApp the SwiftUI macOS front-end (NavigationSplitView, Swift Charts, native menus +
file panels, drag-and-drop import), gRPC-backed via CommonsClient.
CSQLite a C sqlite3 system-library shim so CommonsStore builds on Linux.
Commons.app --gRPC--> commons-server --owns--> SQLite book
AI agents --MCP---> commons-mcp --gRPC--> commons-server
Money is always Decimal -- no Double ever touches a money path (charts downcast to Double
for plotting only). The on-disk schema is byte-compatible with pecun, so an existing pecun.db
opens directly. CommonsCore is the pure domain and is forbidden from importing infrastructure
(DB drivers, crypto, networking, gRPC); the gate is scripts/check_core_purity.sh.
Build and test
The cross-platform core (CommonsCore, CommonsStore, the server, client, and MCP) builds and
tests with SwiftPM. Linux is the server's first-class platform and the primary CI gate:
swift build --build-tests
swift test
Run the server and mint a dev bearer token it accepts:
make run-server # serves commons-server on 127.0.0.1:50051 (plaintext dev)
make mint-token ROLE=user # prints a token; capture with COMMONS_GRPC_TOKEN=$(make -s mint-token)
The macOS app lives in the Xcode project, regenerated from project.yml via
XcodeGen:
make build # xcodegen generate + xcodebuild build (Commons.app)
make test # builds the app and runs the CommonsAppTests parity suite
make install # copy Commons.app to /Applications
Proto IDL hygiene and the core-purity gate (both also enforced in CI):
buf lint && buf format --diff --exit-code && buf build
bash scripts/check_core_purity.sh
Requires the Swift 6 toolchain (>= 6.1 for dependency resolution) and, for the app, Xcode 16+ with XcodeGen. The platform floor is macOS 15.
Deploy
A self-hostable container deploy -- the gRPC backend, the MCP host, Litestream point-in-time
recovery, and Traefik behind PocketId SSO -- lives in deploy/. See deploy/README.md.
Data model
Every transaction has 2+ splits whose signed amounts sum to exactly zero, in a single currency.
The invariant is defended in three layers: an application gate, a DB sentinel trigger on commit,
and a write-once committed_at immutability trigger. See Sources/CommonsStore/Schema.swift for
the schema and pecun's docs/DATA_MODEL.md for the full rationale.
License
MIT OR Apache-2.0, matching the upstream pecun project.