Local-first double-entry accounting, queryable by humans and agents — MCP over a SQLite ledger.
0
stars
41
commits
Python
primary language
Sep 8, 2026
updated
Local-first double-entry accounting, queryable by humans and agents.
SQLite-backed ledger. MCP server with 15 tools. Immutable transactions, contra-posting corrections, append-only audit log.
Part of a family of local-first agent services: open-crm (memory) · openwatch (observability) · openledger (money).

cd open-ledger
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python scripts/seed.py # bootstrap a fresh dev DB with sample books
python run_mcp.py # stdio transport (default)
For Claude Code:
claude mcp add openledger -s user -- \
/absolute/path/to/open-ledger/.venv/bin/python \
/absolute/path/to/open-ledger/run_mcp.py
See docs/claude-connector.md for the full setup.
┌─────────────────────────────────────┐
│ SQLite ledger │
│ accounts · transactions · │
│ entry_lines · audit_log · settings │
└──────────────────┬──────────────────┘
│
▼
MCP server (stdio / SSE :8791)
15 tools — reads + safe writes
│
▼
Claude Desktop, Claude Code,
agent frameworks
A layered architecture (SOLID): the transport, business rules, and persistence
are separated, and each depends only on the layer's abstraction — not its
implementation. Swapping SQLite for Postgres later touches only repositories/
and container.py.
src/
├── domain/ pure constants + typed error hierarchy (no I/O)
├── infrastructure/ Database connection, Unit of Work, id/clock helpers
├── repositories/ protocols.py — narrow Reader/Writer contracts
│ sqlite.py — the only code that writes SQL (aiosqlite)
├── services/ accounts · ledger · reports (Strategy) · audit · query
│ — the only layer with business rules / invariants
├── serialization.py response/error envelope helpers
├── container.py composition root — wires SQLite repos into services
└── mcp_server.py thin MCP transport adapter over the services
run_mcp.py stdio entry point for Claude Desktop / Code
scripts/ seed.py (sample data) · schema.sql · smoke_test.py
tests/ service-level tests of the core invariants
Querying is raw parameterized SQL over aiosqlite (no ORM); all SQL lives
behind the repository protocols, so services never see a query.
sum(debits) == sum(credits) — enforced
in the write path inside one DB transaction.reverse_transaction (contra posting), never UPDATE/DELETE.| Group | Tools |
|---|---|
| Accounts | list_accounts · get_account · get_balance · get_account_ledger · create_account |
| Journal | get_transaction · search_transactions · post_transaction · transfer_funds · reverse_transaction |
| Reports | get_trial_balance · get_profit_loss · get_balance_sheet |
| Audit | get_audit_log |
| Escape hatch | run_query (SQL SELECT only) |
| Env var | Default | Notes |
|---|---|---|
OPENLEDGER_DB | ./data/openledger.db | SQLite path |
MCP_TRANSPORT | stdio (via run_mcp.py) | stdio or sse |
MCP_PORT | 8791 | SSE only |
Contributions welcome — see CONTRIBUTING.md and our Code of Conduct. Report vulnerabilities per SECURITY.md.
Licensed under the Apache License 2.0 — see LICENSE.
30 commits
11 commits
Python
98.6%
Dockerfile
1.4%
Local-first double-entry accounting, queryable by humans and agents — MCP over a SQLite ledger.
0
stars
41
commits
Python
primary language
Sep 8, 2026
updated
Local-first double-entry accounting, queryable by humans and agents.
SQLite-backed ledger. MCP server with 15 tools. Immutable transactions, contra-posting corrections, append-only audit log.
Part of a family of local-first agent services: open-crm (memory) · openwatch (observability) · openledger (money).

cd open-ledger
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
python scripts/seed.py # bootstrap a fresh dev DB with sample books
python run_mcp.py # stdio transport (default)
For Claude Code:
claude mcp add openledger -s user -- \
/absolute/path/to/open-ledger/.venv/bin/python \
/absolute/path/to/open-ledger/run_mcp.py
See docs/claude-connector.md for the full setup.
┌─────────────────────────────────────┐
│ SQLite ledger │
│ accounts · transactions · │
│ entry_lines · audit_log · settings │
└──────────────────┬──────────────────┘
│
▼
MCP server (stdio / SSE :8791)
15 tools — reads + safe writes
│
▼
Claude Desktop, Claude Code,
agent frameworks
A layered architecture (SOLID): the transport, business rules, and persistence
are separated, and each depends only on the layer's abstraction — not its
implementation. Swapping SQLite for Postgres later touches only repositories/
and container.py.
src/
├── domain/ pure constants + typed error hierarchy (no I/O)
├── infrastructure/ Database connection, Unit of Work, id/clock helpers
├── repositories/ protocols.py — narrow Reader/Writer contracts
│ sqlite.py — the only code that writes SQL (aiosqlite)
├── services/ accounts · ledger · reports (Strategy) · audit · query
│ — the only layer with business rules / invariants
├── serialization.py response/error envelope helpers
├── container.py composition root — wires SQLite repos into services
└── mcp_server.py thin MCP transport adapter over the services
run_mcp.py stdio entry point for Claude Desktop / Code
scripts/ seed.py (sample data) · schema.sql · smoke_test.py
tests/ service-level tests of the core invariants
Querying is raw parameterized SQL over aiosqlite (no ORM); all SQL lives
behind the repository protocols, so services never see a query.
sum(debits) == sum(credits) — enforced
in the write path inside one DB transaction.reverse_transaction (contra posting), never UPDATE/DELETE.| Group | Tools |
|---|---|
| Accounts | list_accounts · get_account · get_balance · get_account_ledger · create_account |
| Journal | get_transaction · search_transactions · post_transaction · transfer_funds · reverse_transaction |
| Reports | get_trial_balance · get_profit_loss · get_balance_sheet |
| Audit | get_audit_log |
| Escape hatch | run_query (SQL SELECT only) |
| Env var | Default | Notes |
|---|---|---|
OPENLEDGER_DB | ./data/openledger.db | SQLite path |
MCP_TRANSPORT | stdio (via run_mcp.py) | stdio or sse |
MCP_PORT | 8791 | SSE only |
Contributions welcome — see CONTRIBUTING.md and our Code of Conduct. Report vulnerabilities per SECURITY.md.
Licensed under the Apache License 2.0 — see LICENSE.
30 commits
11 commits
Python
98.6%
Dockerfile
1.4%