Personal Community Finance
  • Swift 99%
  • Shell 0.7%
  • Makefile 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
agent-int aa66c15914
Some checks failed
ci / macos (push) Successful in 3m59s
ci / linux (push) Has been cancelled
ci / proto (push) Has been cancelled
ci / purity (push) Has been cancelled
Merge pull request 'fix: namespace idempotency keys by principal (#6 item D)' (#13) from fix/issue-6-idempotency-principal into main
Reviewed-on: #13
2026-06-29 17:13:04 -07:00
.github/workflows P3b.3 + P3b.4: GRPCDataSource (full-parity gRPC client) + mode switch + liveChanges + reload serialization + differential test -- refs #18 2026-06-28 19:49:09 -07:00
Commons.xcodeproj fix: app/server hardening follow-ups (#6) 2026-06-29 16:54:39 -07:00
deploy P5.3-P5.7: container deploy stack + Litestream restore gate -- refs #18 2026-06-29 08:31:09 -07:00
scripts P1: per-context read/write ports in CommonsCore; LedgerStore conforms 2026-06-26 15:01:09 -07:00
Sources fix: namespace idempotency keys by principal (#6 item D) 2026-06-29 17:12:42 -07:00
Tests fix: namespace idempotency keys by principal (#6 item D) 2026-06-29 17:12:42 -07:00
.dockerignore P5.3-P5.7: container deploy stack + Litestream restore gate -- refs #18 2026-06-29 08:31:09 -07:00
.gitignore P0: SwiftPM-ify Commons for cross-platform (Linux) builds 2026-06-26 14:28:50 -07:00
buf.yaml P2 (part 2): gRPC service surface -- ListAccounts + differential test 2026-06-26 15:45:09 -07:00
Makefile docs: rewrite README for the server-split architecture 2026-06-29 16:28:38 -07:00
Package.resolved chore: lock cross-platform Package.resolved (Linux transitive pins) -- refs #18 2026-06-29 09:12:51 -07:00
Package.swift P5.2: MCP Streamable-HTTP host + OAuth 2.1 resource server -- refs #18 2026-06-29 08:19:44 -07:00
project.yml P5.6: retire in-process direct-store mode as the shipping default -- refs #18 2026-06-29 08:33:40 -07:00
README.md docs: rewrite README for the server-split architecture 2026-06-29 16:28:38 -07:00

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 against commons-server (with its own role=agent service 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.