@morroc/open-ledger 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +191 -0
- package/datasets/defaults/cn.json +1 -0
- package/datasets/defaults/jp.json +1 -0
- package/datasets/defaults/th.json +1 -0
- package/datasets/defaults/us.json +1 -0
- package/datasets/institutions/cn.json +47 -0
- package/datasets/institutions/jp.json +59 -0
- package/datasets/institutions/th.json +99 -0
- package/datasets/institutions/us.json +70 -0
- package/dist/accounts/accounts.js +99 -0
- package/dist/accounts/balances.js +109 -0
- package/dist/accounts/matching.js +72 -0
- package/dist/accounts/resolve.js +118 -0
- package/dist/cli/commands/accounts.js +477 -0
- package/dist/cli/commands/config.js +175 -0
- package/dist/cli/commands/datasets.js +56 -0
- package/dist/cli/commands/doctor.js +153 -0
- package/dist/cli/commands/files.js +72 -0
- package/dist/cli/commands/ingest-commit.js +279 -0
- package/dist/cli/commands/ingest.js +203 -0
- package/dist/cli/commands/merchants.js +140 -0
- package/dist/cli/commands/notes.js +71 -0
- package/dist/cli/commands/open.js +54 -0
- package/dist/cli/commands/questions.js +119 -0
- package/dist/cli/commands/report.js +50 -0
- package/dist/cli/commands/setup.js +61 -0
- package/dist/cli/commands/status.js +187 -0
- package/dist/cli/commands/transactions.js +420 -0
- package/dist/cli/commands/vault.js +65 -0
- package/dist/cli/currency.js +28 -0
- package/dist/cli/db.js +5 -0
- package/dist/cli/format.js +71 -0
- package/dist/cli/index.js +19 -0
- package/dist/cli/output.js +304 -0
- package/dist/cli/program.js +140 -0
- package/dist/config.js +104 -0
- package/dist/context.js +30 -0
- package/dist/datasets/defaults.js +29 -0
- package/dist/datasets/index.js +33 -0
- package/dist/datasets/institutions.js +31 -0
- package/dist/datasets/loader.js +57 -0
- package/dist/db/connection.js +39 -0
- package/dist/db/encryption.js +42 -0
- package/dist/db/migrations/0001_baseline.js +121 -0
- package/dist/db/migrations/index.js +3 -0
- package/dist/db/queries/accounts.js +108 -0
- package/dist/db/queries/balances.js +61 -0
- package/dist/db/queries/files.js +72 -0
- package/dist/db/queries/merchants.js +163 -0
- package/dist/db/queries/notes.js +28 -0
- package/dist/db/queries/questions.js +117 -0
- package/dist/db/queries/transactions-dedup.js +80 -0
- package/dist/db/queries/transactions.js +319 -0
- package/dist/db/queries/vault.js +48 -0
- package/dist/db/schema.js +105 -0
- package/dist/extract/extract.js +89 -0
- package/dist/extract/ocr.js +164 -0
- package/dist/extract/pdf.js +127 -0
- package/dist/extract/presets/index.js +18 -0
- package/dist/extract/presets/lighton-ocr.js +12 -0
- package/dist/extract/presets/typhoon-ocr.js +23 -0
- package/dist/extract/route.js +40 -0
- package/dist/extract/source.js +84 -0
- package/dist/ingest/commit.js +313 -0
- package/dist/ingest/dedup.js +35 -0
- package/dist/ingest/prepare.js +241 -0
- package/dist/ingest/vault.js +56 -0
- package/dist/lib/date.js +6 -0
- package/dist/lib/ids.js +25 -0
- package/dist/lib/json.js +12 -0
- package/dist/lib/masked.js +49 -0
- package/dist/lib/money.js +35 -0
- package/dist/lib/patch.js +29 -0
- package/dist/lib/result.js +15 -0
- package/dist/lib/validate.js +154 -0
- package/dist/privacy/redactor.js +140 -0
- package/dist/setup/hosts.js +32 -0
- package/dist/setup/install.js +60 -0
- package/package.json +60 -0
- package/skills/SKILL.md +18 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this
|
|
152
|
+
License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright 2026 Phureewat Aphibansri
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<picture>
|
|
3
|
+
<source media="(prefers-color-scheme: dark)" srcset="assets/logo-dark.svg">
|
|
4
|
+
<img src="assets/logo.svg" alt="OpenLedger" width="108">
|
|
5
|
+
</picture>
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<h1 align="center">OpenLedger</h1>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<strong>The Harness Layer for Personal Finance</strong>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
<p align="center">
|
|
15
|
+
A harness that turns scattered financial statements into a private, deterministic ledger for your AI.
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="https://www.npmjs.com/package/@morroc/open-ledger"><img src="https://img.shields.io/npm/v/@morroc/open-ledger.svg" alt="npm version" /></a>
|
|
20
|
+
<a href="https://www.npmjs.com/package/@morroc/open-ledger"><img src="https://img.shields.io/npm/dt/@morroc/open-ledger.svg" alt="npm total downloads" /></a>
|
|
21
|
+
</p>
|
|
22
|
+
|
|
23
|
+
<br />
|
|
24
|
+
|
|
25
|
+
You've tried many personal finance apps from the App Store. None of them fits what you need, because each is someone else's idea of your money and lifestyle. So you asked AI to build the one that would, and it failed you too. It hallucinated the numbers, mangled your data, and never quite understood what you wanted.
|
|
26
|
+
|
|
27
|
+
AI fails when it has nowhere reliable to keep the numbers. OpenLedger gives it that place, a deterministic harness that holds every number in your own records.
|
|
28
|
+
|
|
29
|
+
OpenLedger is a secure bookkeeping that serves as a harness for your AI. The data source is what you already receive which are monthly statements from your banks and credit cards. Your AI reads each statement and records what it finds as double-entry bookkeeping.
|
|
30
|
+
|
|
31
|
+
Everything stays on your machine, the database is fully encrypted, and what the harness returns to your AI has PII redacted by default before it sends to AI provider. No bank logins, no bank API keys, no cloud aggregator needed, just the bank documents you already have as the source of truth.
|
|
32
|
+
|
|
33
|
+
By using this harness, your AI can build the app you never found: a budget tracker that fits your lifestyle, a subscription auditor, a retirement planner, a personal money coach. Your finance app is yours to reimagine, and everything you build reads from the same ledger, so you can keep adding without starting over.
|
|
34
|
+
|
|
35
|
+
## Use OpenLedger with your AI
|
|
36
|
+
|
|
37
|
+
The whole skill is one file: [`skills/SKILL.md`](./skills/SKILL.md). Every host gets the same bytes; `oled setup --print` prints them.
|
|
38
|
+
|
|
39
|
+
### AI Chat Apps (ChatGPT, Claude, Gemini, Kimi)
|
|
40
|
+
|
|
41
|
+
1. Install [Node.js](https://nodejs.org) (LTS), then paste into your terminal:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm install -g @morroc/open-ledger
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
2. Paste into your AI chat:
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
Fetch https://raw.githubusercontent.com/phureewat29/open-ledger/main/skills/SKILL.md
|
|
51
|
+
and follow it. oled is installed; help me set up my ledger.
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
If your chat app cannot fetch URLs, paste the skill itself: `oled setup --print | pbcopy` copies it; drop it into the first message or the app's custom instructions.
|
|
55
|
+
|
|
56
|
+
Your AI walks you through the rest.
|
|
57
|
+
|
|
58
|
+
### Coding Agents (Claude Code, Codex, Cursor, Gemini CLI, OpenCode, PI)
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
npm install -g @morroc/open-ledger
|
|
62
|
+
npx skills add phureewat29/open-ledger
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Or run `oled setup`, which writes the skill to `.agents/skills/`, the shared directory most agents read (use `--host claude` for Claude Code).
|
|
66
|
+
|
|
67
|
+
### Your own agent stack
|
|
68
|
+
|
|
69
|
+
Every command speaks `--json` with typed exit codes, built to be scripted. `oled setup --dir <agent-home>` installs the skill anywhere. Two complete references ship in this repo: [`examples/corgi-claude`](./examples/corgi-claude) runs the statement-to-answers loop with `claude -p`, and [`examples/corgi-eval`](./examples/corgi-eval) runs evals against any model and scores how well the harness fits.
|
|
70
|
+
|
|
71
|
+
With the skill installed, give your agent a real task:
|
|
72
|
+
|
|
73
|
+
1. Start with the statements you have waiting: *"Ingest my new statements."* It discovers new files, prepares and reads each one, commits the transactions it finds, and raises a question for anything it can't resolve on its own.
|
|
74
|
+
2. Clear whatever it flagged: *"Show me anything you weren't sure about, and let's resolve it."* It walks you through open questions, such as an unrecognized merchant or an ambiguous account match, one at a time.
|
|
75
|
+
3. With the ledger current, ask for the payoff: *"What's my net worth, and where did most of my spending go last month?"* It reads the answer straight from the ledger.
|
|
76
|
+
|
|
77
|
+
## The Agent Workflow
|
|
78
|
+
|
|
79
|
+
Every row becomes a *transaction*: it debits one account and credits another by the same positive amount.
|
|
80
|
+
|
|
81
|
+
This is the loop the skill teaches an agent to run:
|
|
82
|
+
|
|
83
|
+
1. **Discover**: `oled ingest list --json` to find new/pending files.
|
|
84
|
+
2. **Prepare**: `oled ingest prepare <path>` registers the file and extracts it, unlocking encrypted PDFs via `oled vault`. A PDF carrying its own text layer, or a scan read by a configured OCR endpoint, comes back as a `document` text file. With no text layer and no OCR endpoint, it comes back as one image per page.
|
|
85
|
+
3. **Read**: the agent reads what prepare returned, either the text document or the page images, and picks out every transaction row.
|
|
86
|
+
4. **Commit**: the agent pipes the transactions it extracted (one debit account, one credit account, one positive amount per row; splits go as a compound `linked` group) into `oled ingest commit`. The harness posts them into the ledger and raises a question for anything it can't resolve confidently (unknown merchant, fuzzy account match, uncategorized fallback, cross-currency row).
|
|
87
|
+
5. **Resolve**: the agent (or you) works through `oled questions` for whatever got raised, then closes the file out with `oled ingest done <id>`.
|
|
88
|
+
|
|
89
|
+
## Commands
|
|
90
|
+
|
|
91
|
+
Run `oled --help` (or `oled <noun> --help`) for the full flag reference. Grouped overview:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
oled # Status: config, database, ledger counts, net worth (default)
|
|
95
|
+
oled doctor # Diagnose the harness environment
|
|
96
|
+
oled setup # Install the skill for an agent CLI (--host <id> | --dir <path>)
|
|
97
|
+
oled config # Configuration
|
|
98
|
+
|
|
99
|
+
oled ingest # Ingest pipeline: list / prepare / commit / done / fail
|
|
100
|
+
oled files # Browse ingested files (list / show / drop)
|
|
101
|
+
oled vault # Manage file-password patterns for encrypted statements
|
|
102
|
+
|
|
103
|
+
oled transactions # Transactions: list / show / add / update / delete / recategorize / dedupe / merge
|
|
104
|
+
oled accounts # Manage the chart of accounts
|
|
105
|
+
oled merchants # Manage merchants and their default accounts
|
|
106
|
+
oled questions # List, answer, and defer open questions
|
|
107
|
+
|
|
108
|
+
oled report # Income, expenses, and net
|
|
109
|
+
oled notes # Manage freeform notes
|
|
110
|
+
oled datasets # Reference datasets
|
|
111
|
+
|
|
112
|
+
oled open # Open the data folder in file explorer
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Security & Privacy
|
|
116
|
+
|
|
117
|
+
- All financial data stays on your machine, encrypted with AES-256 (libsql); default `~/.oled/db.sqlite`.
|
|
118
|
+
- The config file (`~/.oled/config.json`) carries `0600` permissions. It holds two secrets at most, the database encryption key and the OCR endpoint API key; `config show` surfaces a fingerprint of each and `status` one of the database key, never the plaintext.
|
|
119
|
+
- Encrypted-PDF passwords sit AES-GCM-encrypted in `db.sqlite` under a filename pattern; plaintext never touches disk.
|
|
120
|
+
- A decrypted statement stays in memory. Only what an agent has to read is written to `cache/`: the extracted text, or the page images.
|
|
121
|
+
- Read commands mask PII in free-text fields by default; `--no-redact` returns verbatim text.
|
|
122
|
+
- No telemetry, no analytics. OpenLedger makes no network calls of its own. The exception is opt-in and goes only to the OCR endpoint you configure: `ingest prepare` sends it the page images to read, and `doctor` asks it which models it serves.
|
|
123
|
+
|
|
124
|
+
## Configuration
|
|
125
|
+
|
|
126
|
+
OpenLedger stores everything in `~/.oled/`:
|
|
127
|
+
|
|
128
|
+
```
|
|
129
|
+
~/.oled/
|
|
130
|
+
config.json # locale, currency, paths, database encryption key (0600 permissions)
|
|
131
|
+
context.md # persistent freeform context an agent can read (path shown as context_path in oled config show)
|
|
132
|
+
db.sqlite # encrypted SQLite database
|
|
133
|
+
data/ # drop your statements here, as PDFs or images (subfolders allowed)
|
|
134
|
+
cache/ # extracted text and page images handed to an agent
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Environment variables
|
|
138
|
+
|
|
139
|
+
See `.env.example` for the current list:
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
# OpenLedger environment variables. Copy this file to `.env` and fill the values.
|
|
143
|
+
|
|
144
|
+
# Optional. Relocates the entire ~/.oled directory. Individual
|
|
145
|
+
# OLED_* overrides below still win for their own paths.
|
|
146
|
+
OLED_DIR=
|
|
147
|
+
|
|
148
|
+
# Optional. Passphrase used to encrypt the local SQLite database (AES-256).
|
|
149
|
+
# `oled config --generate-key` generates one if left blank.
|
|
150
|
+
OLED_DB_ENCRYPTION_KEY=
|
|
151
|
+
|
|
152
|
+
# Optional. Default: ~/.oled/db.sqlite
|
|
153
|
+
OLED_DB_PATH=
|
|
154
|
+
|
|
155
|
+
# Optional. Default: ~/.oled/data
|
|
156
|
+
OLED_DATA_DIR=
|
|
157
|
+
|
|
158
|
+
# Optional. Scratch space for the extracted text and page images handed to external
|
|
159
|
+
# agent CLIs. Default: ~/.oled/cache
|
|
160
|
+
OLED_CACHE_DIR=
|
|
161
|
+
|
|
162
|
+
# Optional. OpenAI-compatible OCR endpoint base URL, including its version
|
|
163
|
+
# segment, e.g. http://127.0.0.1:1234/v1. A non-local URL sends statement page
|
|
164
|
+
# images off this machine.
|
|
165
|
+
OLED_OCR_BASE_URL=
|
|
166
|
+
|
|
167
|
+
# Optional. Model id served at OLED_OCR_BASE_URL. The id picks the built-in
|
|
168
|
+
# prompt, sampling, and page-render profile; blank asks the endpoint for the
|
|
169
|
+
# default profile's own model.
|
|
170
|
+
OLED_OCR_MODEL=
|
|
171
|
+
|
|
172
|
+
# Optional. API key for the OCR endpoint, if it requires one. Set it here or in
|
|
173
|
+
# the shell: `oled config` has no flag for it.
|
|
174
|
+
OLED_OCR_API_KEY=
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Contributing
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
git clone https://github.com/phureewat29/open-ledger
|
|
181
|
+
cd open-ledger
|
|
182
|
+
npm install
|
|
183
|
+
npm run build
|
|
184
|
+
npm link # makes 'oled' available globally
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
`npm run integration` builds the CLI and runs a two-stage integration test against the built binary: a read-surface sweep (NDJSON validity, exit codes, zero ANSI) and a full write-path lifecycle in an isolated environment.
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
OpenLedger is licensed under the [Apache License 2.0](./LICENSE).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "country": "CN", "locale": "zh-CN", "currency": "CNY" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "country": "JP", "locale": "ja-JP", "currency": "JPY" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "country": "TH", "locale": "th-TH", "currency": "THB" }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{ "country": "US", "locale": "en-US", "currency": "USD" }
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"country": "CN",
|
|
3
|
+
"institutions": [
|
|
4
|
+
{ "code": "ICBC", "label": "Industrial and Commercial Bank of China (工商银行)", "kind": "bank", "notes": "Largest of the Big Four; state-owned." },
|
|
5
|
+
{ "code": "CCB", "label": "China Construction Bank (建设银行)", "kind": "bank", "notes": "Big Four; state-owned." },
|
|
6
|
+
{ "code": "ABC", "label": "Agricultural Bank of China (农业银行)", "kind": "bank", "notes": "Big Four; state-owned." },
|
|
7
|
+
{ "code": "BOC", "label": "Bank of China (中国银行)", "kind": "bank", "notes": "Big Four; strongest overseas presence." },
|
|
8
|
+
{ "code": "BOCOM", "label": "Bank of Communications (交通银行)", "kind": "bank", "notes": "Fifth large state bank." },
|
|
9
|
+
{ "code": "PSBC", "label": "Postal Savings Bank of China (邮储银行)", "kind": "bank", "notes": "State-owned; rural reach." },
|
|
10
|
+
{ "code": "CMB", "label": "China Merchants Bank (招商银行)", "kind": "bank", "notes": "Leading retail joint-stock bank." },
|
|
11
|
+
{ "code": "CITIC-CN", "label": "China CITIC Bank (中信银行)", "kind": "bank" },
|
|
12
|
+
{ "code": "SPDB", "label": "Shanghai Pudong Development Bank (浦发银行)", "kind": "bank" },
|
|
13
|
+
{ "code": "CIB", "label": "Industrial Bank (兴业银行)", "kind": "bank" },
|
|
14
|
+
{ "code": "CMBC", "label": "China Minsheng Bank (民生银行)", "kind": "bank", "notes": "Largest private bank." },
|
|
15
|
+
{ "code": "PAB", "label": "Ping An Bank (平安银行)", "kind": "bank", "notes": "Ping An Group subsidiary." },
|
|
16
|
+
{ "code": "CEB", "label": "China Everbright Bank (光大银行)", "kind": "bank" },
|
|
17
|
+
{ "code": "HXB", "label": "Hua Xia Bank (华夏银行)", "kind": "bank" },
|
|
18
|
+
{ "code": "CGB", "label": "China Guangfa Bank (广发银行)", "kind": "bank" },
|
|
19
|
+
{ "code": "WEBANK", "label": "WeBank (微众银行)", "kind": "bank", "notes": "Digital-only; Tencent-backed." },
|
|
20
|
+
{ "code": "MYBANK", "label": "MYbank (网商银行)", "kind": "bank", "notes": "Digital-only; Ant Group-backed." },
|
|
21
|
+
{ "code": "ALIPAY", "label": "Alipay (支付宝)", "kind": "wallet", "notes": "Ant Group; dominant wallet alongside WeChat Pay." },
|
|
22
|
+
{ "code": "WECHATPAY", "label": "WeChat Pay (微信支付)", "kind": "wallet", "notes": "Tencent." },
|
|
23
|
+
{ "code": "JDPAY", "label": "JD Pay (京东支付)", "kind": "wallet", "notes": "JD.com." },
|
|
24
|
+
{ "code": "UNIONPAY", "label": "UnionPay (银联)", "kind": "payment_rail", "notes": "National card network and QuickPass QR rail; appears on statements, not an account." },
|
|
25
|
+
{ "code": "CITICSEC", "label": "CITIC Securities (中信证券)", "kind": "broker", "notes": "Largest broker." },
|
|
26
|
+
{ "code": "HUATAI", "label": "Huatai Securities (华泰证券)", "kind": "broker" },
|
|
27
|
+
{ "code": "GTJA", "label": "Guotai Junan Securities (国泰君安)", "kind": "broker", "notes": "Merged with Haitong (2025) as Guotai Haitong." },
|
|
28
|
+
{ "code": "GFSEC", "label": "GF Securities (广发证券)", "kind": "broker" },
|
|
29
|
+
{ "code": "GALAXY", "label": "China Galaxy Securities (银河证券)", "kind": "broker" },
|
|
30
|
+
{ "code": "EASTMONEY", "label": "East Money Securities (东方财富)", "kind": "broker", "notes": "Leading online/retail broker." },
|
|
31
|
+
{ "code": "FUTU", "label": "Futu (富途牛牛)", "kind": "broker", "notes": "HK-based app broker; serves mainland investors offshore." },
|
|
32
|
+
{ "code": "TIGER", "label": "Tiger Brokers (老虎证券)", "kind": "broker", "notes": "Offshore app broker." },
|
|
33
|
+
{ "code": "PINGAN", "label": "Ping An Insurance (中国平安)", "kind": "insurer", "notes": "Life + P&C; largest insurer." },
|
|
34
|
+
{ "code": "CHINALIFE", "label": "China Life (中国人寿)", "kind": "insurer", "notes": "State-owned life leader." },
|
|
35
|
+
{ "code": "CPIC", "label": "China Pacific Insurance (太平洋保险)", "kind": "insurer" },
|
|
36
|
+
{ "code": "PICC", "label": "People's Insurance Company of China (人保)", "kind": "insurer", "notes": "P&C leader; state-owned." },
|
|
37
|
+
{ "code": "TAIKANG", "label": "Taikang Insurance (泰康保险)", "kind": "insurer", "notes": "Life and pensions." },
|
|
38
|
+
{ "code": "STA", "label": "State Taxation Administration (税务总局)", "kind": "gov", "notes": "Individual income tax (IIT) withholding and filings." },
|
|
39
|
+
{ "code": "SIO", "label": "Social Insurance (社保)", "kind": "gov", "notes": "Pension/medical/unemployment contributions on payslips." },
|
|
40
|
+
{ "code": "HPF", "label": "Housing Provident Fund (公积金)", "kind": "gov", "notes": "Mandatory housing savings; employer-matched." },
|
|
41
|
+
{ "code": "CHINAMOBILE", "label": "China Mobile (中国移动)", "kind": "telco" },
|
|
42
|
+
{ "code": "CHINAUNICOM", "label": "China Unicom (中国联通)", "kind": "telco" },
|
|
43
|
+
{ "code": "CHINATELECOM", "label": "China Telecom (中国电信)", "kind": "telco" },
|
|
44
|
+
{ "code": "STATEGRID", "label": "State Grid (国家电网)", "kind": "utility", "notes": "Electricity for most provinces." },
|
|
45
|
+
{ "code": "CSG", "label": "China Southern Power Grid (南方电网)", "kind": "utility", "notes": "Electricity for the five southern provinces." }
|
|
46
|
+
]
|
|
47
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"country": "JP",
|
|
3
|
+
"institutions": [
|
|
4
|
+
{ "code": "MUFG", "label": "MUFG Bank (三菱UFJ銀行)", "kind": "bank", "notes": "Largest megabank." },
|
|
5
|
+
{ "code": "SMBC", "label": "Sumitomo Mitsui Banking Corporation (三井住友銀行)", "kind": "bank", "notes": "Megabank." },
|
|
6
|
+
{ "code": "MIZUHO", "label": "Mizuho Bank (みずほ銀行)", "kind": "bank", "notes": "Megabank." },
|
|
7
|
+
{ "code": "RESONA", "label": "Resona Bank (りそな銀行)", "kind": "bank" },
|
|
8
|
+
{ "code": "YUCHO", "label": "Japan Post Bank (ゆうちょ銀行)", "kind": "bank", "notes": "Largest deposit base; postal network." },
|
|
9
|
+
{ "code": "RAKUTEN-BANK", "label": "Rakuten Bank (楽天銀行)", "kind": "bank", "notes": "Online-only; largest digital bank." },
|
|
10
|
+
{ "code": "SBI-SHINSEI", "label": "SBI Shinsei Bank (SBI新生銀行)", "kind": "bank", "notes": "Former Shinsei; SBI-owned since 2021." },
|
|
11
|
+
{ "code": "SONYBANK", "label": "Sony Bank (ソニー銀行)", "kind": "bank", "notes": "Online-only; FX-friendly." },
|
|
12
|
+
{ "code": "PAYPAY-BANK", "label": "PayPay Bank (PayPay銀行)", "kind": "bank", "notes": "Former Japan Net Bank; SoftBank/Z group." },
|
|
13
|
+
{ "code": "JIBUN", "label": "au Jibun Bank (auじぶん銀行)", "kind": "bank", "notes": "KDDI + MUFG online bank." },
|
|
14
|
+
{ "code": "SEVENBANK", "label": "Seven Bank (セブン銀行)", "kind": "bank", "notes": "ATM network in 7-Eleven stores." },
|
|
15
|
+
{ "code": "JCB", "label": "JCB", "kind": "card_issuer", "notes": "Japan's domestic card network and issuer." },
|
|
16
|
+
{ "code": "RAKUTEN-CARD", "label": "Rakuten Card (楽天カード)", "kind": "card_issuer", "notes": "Largest issuer by cards in force." },
|
|
17
|
+
{ "code": "SAISON", "label": "Credit Saison (クレディセゾン)", "kind": "card_issuer" },
|
|
18
|
+
{ "code": "SMCC", "label": "Sumitomo Mitsui Card (三井住友カード)", "kind": "card_issuer", "notes": "SMBC group; Visa-centric." },
|
|
19
|
+
{ "code": "ORICO", "label": "Orient Corporation (オリコ)", "kind": "card_issuer", "notes": "Cards and shopping credit." },
|
|
20
|
+
{ "code": "AEON-JP", "label": "AEON Financial Service (イオンカード)", "kind": "card_issuer", "notes": "Retail-linked; distinct from AEON Thailand." },
|
|
21
|
+
{ "code": "VIEWCARD", "label": "View Card (ビューカード)", "kind": "card_issuer", "notes": "JR East; Suica auto-charge." },
|
|
22
|
+
{ "code": "PAYPAY", "label": "PayPay", "kind": "wallet", "notes": "Dominant QR wallet; SoftBank/Z group." },
|
|
23
|
+
{ "code": "RAKUTEN-PAY", "label": "Rakuten Pay (楽天ペイ)", "kind": "wallet" },
|
|
24
|
+
{ "code": "DBARAI", "label": "d Barai (d払い)", "kind": "wallet", "notes": "NTT Docomo; can settle via phone bill." },
|
|
25
|
+
{ "code": "AUPAY", "label": "au PAY", "kind": "wallet", "notes": "KDDI." },
|
|
26
|
+
{ "code": "MERPAY", "label": "Merpay (メルペイ)", "kind": "wallet", "notes": "Mercari's wallet." },
|
|
27
|
+
{ "code": "SUICA", "label": "Suica", "kind": "wallet", "notes": "JR East transit IC money; also PASMO interoperable." },
|
|
28
|
+
{ "code": "ZENGIN", "label": "Zengin System (全銀システム)", "kind": "payment_rail", "notes": "Interbank transfer rail; furikomi descriptors." },
|
|
29
|
+
{ "code": "NOMURA", "label": "Nomura Securities (野村證券)", "kind": "broker", "notes": "Largest full-service broker." },
|
|
30
|
+
{ "code": "DAIWA", "label": "Daiwa Securities (大和証券)", "kind": "broker" },
|
|
31
|
+
{ "code": "SBI-SEC", "label": "SBI Securities (SBI証券)", "kind": "broker", "notes": "Largest online broker." },
|
|
32
|
+
{ "code": "RAKUTEN-SEC", "label": "Rakuten Securities (楽天証券)", "kind": "broker", "notes": "Online; NISA-popular." },
|
|
33
|
+
{ "code": "MONEX", "label": "Monex Securities (マネックス証券)", "kind": "broker" },
|
|
34
|
+
{ "code": "MATSUI", "label": "Matsui Securities (松井証券)", "kind": "broker" },
|
|
35
|
+
{ "code": "KABUCOM", "label": "au Kabucom Securities (auカブコム証券)", "kind": "broker", "notes": "MUFG + KDDI." },
|
|
36
|
+
{ "code": "BITFLYER", "label": "bitFlyer", "kind": "crypto_exchange", "notes": "FSA-licensed; largest by BTC volume." },
|
|
37
|
+
{ "code": "COINCHECK", "label": "Coincheck", "kind": "crypto_exchange", "notes": "Monex group." },
|
|
38
|
+
{ "code": "GMOCOIN", "label": "GMO Coin (GMOコイン)", "kind": "crypto_exchange" },
|
|
39
|
+
{ "code": "BITBANK", "label": "bitbank", "kind": "crypto_exchange" },
|
|
40
|
+
{ "code": "SBIVC", "label": "SBI VC Trade", "kind": "crypto_exchange", "notes": "SBI group." },
|
|
41
|
+
{ "code": "NIPPONLIFE", "label": "Nippon Life (日本生命)", "kind": "insurer", "notes": "Life; largest mutual." },
|
|
42
|
+
{ "code": "DAIICHILIFE", "label": "Dai-ichi Life (第一生命)", "kind": "insurer", "notes": "Life; listed." },
|
|
43
|
+
{ "code": "MEIJIYASUDA", "label": "Meiji Yasuda Life (明治安田生命)", "kind": "insurer" },
|
|
44
|
+
{ "code": "SUMITOMOLIFE", "label": "Sumitomo Life (住友生命)", "kind": "insurer" },
|
|
45
|
+
{ "code": "TOKIO-MARINE-JP", "label": "Tokio Marine & Nichido (東京海上日動)", "kind": "insurer", "notes": "Non-life leader; parent of Tokio Marine Thailand." },
|
|
46
|
+
{ "code": "SOMPO", "label": "Sompo Japan (損保ジャパン)", "kind": "insurer", "notes": "Non-life." },
|
|
47
|
+
{ "code": "NTA", "label": "National Tax Agency (国税庁)", "kind": "gov", "notes": "Income tax; nenmatsu-chosei year-end adjustment." },
|
|
48
|
+
{ "code": "NENKIN", "label": "Japan Pension Service (日本年金機構)", "kind": "gov", "notes": "National and employee pension contributions." },
|
|
49
|
+
{ "code": "DOCOMO", "label": "NTT Docomo", "kind": "telco" },
|
|
50
|
+
{ "code": "KDDI", "label": "au (KDDI)", "kind": "telco" },
|
|
51
|
+
{ "code": "SOFTBANK", "label": "SoftBank", "kind": "telco" },
|
|
52
|
+
{ "code": "RAKUTEN-MOBILE", "label": "Rakuten Mobile (楽天モバイル)", "kind": "telco" },
|
|
53
|
+
{ "code": "TEPCO", "label": "Tokyo Electric Power (東京電力)", "kind": "utility", "notes": "Kanto electricity." },
|
|
54
|
+
{ "code": "KEPCO-JP", "label": "Kansai Electric Power (関西電力)", "kind": "utility", "notes": "Kansai electricity." },
|
|
55
|
+
{ "code": "CHUBU", "label": "Chubu Electric Power (中部電力)", "kind": "utility" },
|
|
56
|
+
{ "code": "TOKYOGAS", "label": "Tokyo Gas (東京ガス)", "kind": "utility" },
|
|
57
|
+
{ "code": "OSAKAGAS", "label": "Osaka Gas (大阪ガス)", "kind": "utility" }
|
|
58
|
+
]
|
|
59
|
+
}
|