beanhand 0.7.2__tar.gz
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.
- beanhand-0.7.2/AGENTS.md +111 -0
- beanhand-0.7.2/COPYING +674 -0
- beanhand-0.7.2/MANIFEST.in +10 -0
- beanhand-0.7.2/Makefile +41 -0
- beanhand-0.7.2/PKG-INFO +368 -0
- beanhand-0.7.2/README.md +351 -0
- beanhand-0.7.2/beanhand/__init__.py +0 -0
- beanhand-0.7.2/beanhand/client/__init__.py +0 -0
- beanhand-0.7.2/beanhand/client/beancount_loader.py +574 -0
- beanhand-0.7.2/beanhand/client/beanfiles.py +507 -0
- beanhand-0.7.2/beanhand/client/cli.py +84 -0
- beanhand-0.7.2/beanhand/client/commands/__init__.py +0 -0
- beanhand-0.7.2/beanhand/client/commands/associate.py +384 -0
- beanhand-0.7.2/beanhand/client/commands/fetch.py +24 -0
- beanhand-0.7.2/beanhand/client/commands/importcmd.py +218 -0
- beanhand-0.7.2/beanhand/client/commands/ingest.py +171 -0
- beanhand-0.7.2/beanhand/client/commands/listaccts.py +30 -0
- beanhand-0.7.2/beanhand/client/commands/listcmds.py +38 -0
- beanhand-0.7.2/beanhand/client/commands/organize.py +64 -0
- beanhand-0.7.2/beanhand/client/commands/process.py +39 -0
- beanhand-0.7.2/beanhand/client/commands/refine.py +446 -0
- beanhand-0.7.2/beanhand/client/commands/remove.py +21 -0
- beanhand-0.7.2/beanhand/client/config.py +180 -0
- beanhand-0.7.2/beanhand/client/display.py +13 -0
- beanhand-0.7.2/beanhand/client/server.py +230 -0
- beanhand-0.7.2/beanhand/server/RECEIPT_CONVERSION_PROMPT.md +52 -0
- beanhand-0.7.2/beanhand/server/RECEIPT_INFO_PROMPT.md +5 -0
- beanhand-0.7.2/beanhand/server/RECEIPT_MATCH_PROMPT.md +20 -0
- beanhand-0.7.2/beanhand/server/TRANSACTION_REFINEMENT_PROMPT.md +94 -0
- beanhand-0.7.2/beanhand/server/__init__.py +0 -0
- beanhand-0.7.2/beanhand/server/cli.py +79 -0
- beanhand-0.7.2/beanhand/server/commands/__init__.py +0 -0
- beanhand-0.7.2/beanhand/server/commands/associate.py +133 -0
- beanhand-0.7.2/beanhand/server/commands/fetch.py +51 -0
- beanhand-0.7.2/beanhand/server/commands/listcmds.py +70 -0
- beanhand-0.7.2/beanhand/server/commands/process.py +107 -0
- beanhand-0.7.2/beanhand/server/commands/refine.py +137 -0
- beanhand-0.7.2/beanhand/server/commands/remove.py +42 -0
- beanhand-0.7.2/beanhand/server/config.py +255 -0
- beanhand-0.7.2/beanhand/server/llm.py +115 -0
- beanhand-0.7.2/beanhand/server/pdf.py +81 -0
- beanhand-0.7.2/beanhand/server/storage.py +140 -0
- beanhand-0.7.2/beanhand/structs.py +101 -0
- beanhand-0.7.2/beanhand/tests/example.beancount +71 -0
- beanhand-0.7.2/beanhand/tests/test_account_list_server.py +212 -0
- beanhand-0.7.2/beanhand/tests/test_beancount_lock.py +283 -0
- beanhand-0.7.2/beanhand/tests/test_do_refine.py +287 -0
- beanhand-0.7.2/beanhand/tests/test_do_refine_server.py +86 -0
- beanhand-0.7.2/beanhand/tests/test_fetch_mtime.py +134 -0
- beanhand-0.7.2/beanhand/tests/test_file_modification.py +91 -0
- beanhand-0.7.2/beanhand/tests/test_import_result.py +512 -0
- beanhand-0.7.2/beanhand/tests/test_load_live_accounts.py +472 -0
- beanhand-0.7.2/beanhand/tests/test_local_receipt_backend.py +370 -0
- beanhand-0.7.2/beanhand/tests/test_refine_helpers.py +131 -0
- beanhand-0.7.2/beanhand/tests/test_refine_targets.py +183 -0
- beanhand-0.7.2/beanhand/tests/test_split_at_transaction_by_line_number.py +894 -0
- beanhand-0.7.2/beanhand/tests/test_update_document_metadata.py +271 -0
- beanhand-0.7.2/beanhand.egg-info/PKG-INFO +368 -0
- beanhand-0.7.2/beanhand.egg-info/SOURCES.txt +81 -0
- beanhand-0.7.2/beanhand.egg-info/dependency_links.txt +1 -0
- beanhand-0.7.2/beanhand.egg-info/entry_points.txt +4 -0
- beanhand-0.7.2/beanhand.egg-info/requires.txt +7 -0
- beanhand-0.7.2/beanhand.egg-info/top_level.txt +1 -0
- beanhand-0.7.2/docs/Commands.md +133 -0
- beanhand-0.7.2/docs/Features.md +112 -0
- beanhand-0.7.2/docs/Roadmap.md +70 -0
- beanhand-0.7.2/docs/specs/Associating receipts with transactions.md +157 -0
- beanhand-0.7.2/docs/specs/Dynamic account list from Beancount data.md +307 -0
- beanhand-0.7.2/docs/specs/Ingesting receipts and creating transactions.md +283 -0
- beanhand-0.7.2/docs/specs/Refine existing Beancount transactions.md +306 -0
- beanhand-0.7.2/docs/specs/Refine multi-range target specification.md +159 -0
- beanhand-0.7.2/docs/specs/Rendering of PDF documents to images.md +115 -0
- beanhand-0.7.2/mypy.ini +10 -0
- beanhand-0.7.2/pyproject.toml +20 -0
- beanhand-0.7.2/qubes-rpc/beanhand.Fetch +3 -0
- beanhand-0.7.2/qubes-rpc/beanhand.HelpAssociateReceipt +3 -0
- beanhand-0.7.2/qubes-rpc/beanhand.ListUnassociated +3 -0
- beanhand-0.7.2/qubes-rpc/beanhand.ListUningested +3 -0
- beanhand-0.7.2/qubes-rpc/beanhand.Process +3 -0
- beanhand-0.7.2/qubes-rpc/beanhand.Refine +3 -0
- beanhand-0.7.2/qubes-rpc/beanhand.Remove +3 -0
- beanhand-0.7.2/setup.cfg +4 -0
- beanhand-0.7.2/tox.ini +15 -0
beanhand-0.7.2/AGENTS.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# AGENTS.md — beanhand
|
|
2
|
+
|
|
3
|
+
## Structure
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
beanhand/
|
|
7
|
+
├── docs/*.md # general documentation of the program, features, commands, and use
|
|
8
|
+
└── docs/specs/… # specs for features in development or developed
|
|
9
|
+
│── pyproject.toml # Python project definition and configuration ifle
|
|
10
|
+
│
|
|
11
|
+
├── beanhand/structs.py # request/response TypedDicts shared by client and server
|
|
12
|
+
│
|
|
13
|
+
├── beanhand/server/ # Runs on server VM which has access to receipts and LLM
|
|
14
|
+
│ ├── cli.py # beanhand-server entry point: build_parser() + dispatch table
|
|
15
|
+
│ ├── commands/ # one module per beanhand.* subcommand
|
|
16
|
+
│ │ ├── listcmds.py # beanhand.ListUningested / beanhand.ListUnassociated
|
|
17
|
+
│ │ ├── process.py # beanhand.Process
|
|
18
|
+
│ │ ├── fetch.py # beanhand.Fetch
|
|
19
|
+
│ │ ├── associate.py # beanhand.HelpAssociateReceipt
|
|
20
|
+
│ │ ├── remove.py # beanhand.Remove
|
|
21
|
+
│ │ └── refine.py # beanhand.Refine
|
|
22
|
+
│ ├── config.py # server-side configuration
|
|
23
|
+
│ ├── llm.py # shared LLM/streaming helpers (file_to_image_parts, …)
|
|
24
|
+
│ ├── storage.py # WebDAV client helpers
|
|
25
|
+
│ ├── pdf.py # PDF→PNG conversion for receipt images
|
|
26
|
+
│ └── *_PROMPT.md # prompts for LLMs
|
|
27
|
+
│
|
|
28
|
+
└── beanhand/client/ # Runs on client VM which has Beancount data
|
|
29
|
+
├── cli.py # beanhand entry point: build_parser() + dispatch table
|
|
30
|
+
├── commands/ # one module per beanhand subcommand
|
|
31
|
+
│ ├── listcmds.py # beanhand list-uningested / list-unassociated
|
|
32
|
+
│ ├── ingest.py # beanhand ingest
|
|
33
|
+
│ ├── importcmd.py # beanhand import
|
|
34
|
+
│ ├── associate.py # beanhand associate
|
|
35
|
+
│ ├── refine.py # beanhand refine
|
|
36
|
+
│ ├── process.py # beanhand process
|
|
37
|
+
│ ├── fetch.py # beanhand fetch
|
|
38
|
+
│ ├── remove.py # beanhand remove
|
|
39
|
+
│ └── organize.py # beanhand organize
|
|
40
|
+
├── config.py # client-side configuration
|
|
41
|
+
├── beancount_loader.py # loads Beancount data (queries / candidate contexts)
|
|
42
|
+
├── beanfiles.py # raw Beancount file ops: tx splitting, doc metadata, receipt organization
|
|
43
|
+
├── server.py # qrexec/subprocess transport (RemoteVM) + LLM streaming capture
|
|
44
|
+
└── display.py # colored unified-diff printing
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Tox (`tox --current-env`) is the test framework; it runs doctests, pytest, Ruff and MyPy.
|
|
48
|
+
You can invoke the entire suite of tests using command `make qa`. If you are iterating
|
|
49
|
+
through code changes, first run `pytest -vv` in the project directory to verify much more
|
|
50
|
+
quickly which tests are failing. When those tests are passing, make use of `make qa`
|
|
51
|
+
to catch further problems with the code.
|
|
52
|
+
|
|
53
|
+
## How to run
|
|
54
|
+
|
|
55
|
+
**beanhand-server** — runs on the VM that has receipt files + LLM access. CLI subcommands:
|
|
56
|
+
- `beanhand-server beanhand.ListUningested` / `beanhand.ListUnassociated` list receipts as JSON
|
|
57
|
+
- `beanhand-server beanhand.Process <filename>` processes one receipt via OpenAI-compatible API (produces JSONL output)
|
|
58
|
+
- `beanhand-server beanhand.Refine` refines a transaction; request arrives as plain JSON on stdin (no positional argument, produces JSONL output)
|
|
59
|
+
- `beanhand-server beanhand.HelpAssociateReceipt <filename>` matches a receipt against candidate transactions (candidates arrive on stdin)
|
|
60
|
+
|
|
61
|
+
**beanhand** — runs on the VM with Beancount data. CLI subcommands:
|
|
62
|
+
- `beanhand list-uningested` / `list-unassociated` → print receipt filenames (one per line)
|
|
63
|
+
- `beanhand process <file>` → streams LLM response, prints parsed Beancount tx to stdout
|
|
64
|
+
- `beanhand refine <file_path> <target>...` → refine one or more transactions using their linked documents; each target is a 1-based line number (N), an inclusive line range (A-B), or an open range to the end of the file (A-end); targets must be strictly ascending and non-overlapping (see docs/specs/Refine multi-range target specification.md)
|
|
65
|
+
- `beanhand ingest` / `import <filename>` / `associate` / `fetch` / `remove` / `organize`
|
|
66
|
+
|
|
67
|
+
Default config: `~/.config/beanhand.json`. Both clients also support `--config <path>` and `$BEANHAND_CONFIG`.
|
|
68
|
+
|
|
69
|
+
**Local testing**: set `"target_vm": null` in client config so the client spawns the server as a subprocess
|
|
70
|
+
(arguments hex-encoded just as if the server were running in a separate VM).
|
|
71
|
+
|
|
72
|
+
## Configuration (`~/.config/beanhand.json`)
|
|
73
|
+
|
|
74
|
+
Both programs read from the same config file by default `~/.config/beanhand.json` (but see below for more).
|
|
75
|
+
|
|
76
|
+
Refer to `README.md` for configuration details and values.
|
|
77
|
+
|
|
78
|
+
## Server-client transport
|
|
79
|
+
|
|
80
|
+
For security reasons, the software is split into two parts:
|
|
81
|
+
|
|
82
|
+
1. The client: runs on the virtual machine dedicated to accounting, where all the
|
|
83
|
+
Beancount files reside.
|
|
84
|
+
2. The server: runs on the virtual machine that has the receipts, and also access
|
|
85
|
+
to an OpenAI-compatible LLM API that will process the receipts and turn them into
|
|
86
|
+
Beancount-formatted transactions.
|
|
87
|
+
|
|
88
|
+
- **Same host** (`target_vm: null`): client spawns server via subprocess, passes hex-encoded subcommand + args.
|
|
89
|
+
- **Different VM** (qrexec): service endpoint is `<subcommand>+<hex-encoded-args>`. The RPC handler lives at `/etc/qubes/rpc/beanhand.*` on the server VM.
|
|
90
|
+
|
|
91
|
+
When server and client are on the same machine (client's `config.json` says `target_vm: null`), then
|
|
92
|
+
client spawns server as subprocess and passes subcommand + command line argument directly, albeit encoding
|
|
93
|
+
argument as hex before invocation.
|
|
94
|
+
|
|
95
|
+
When server is on another VM, qrexec communication is used, and the service call endpoint becomes
|
|
96
|
+
the subcommand joined with a plus sign to the hex-encoded argument (if needed by the call).
|
|
97
|
+
|
|
98
|
+
Client has the ability to send stdin to server, and server can respond via stdout.
|
|
99
|
+
|
|
100
|
+
## Key files (do not change without checking spec)
|
|
101
|
+
|
|
102
|
+
- `RECEIPT_CONVERSION_PROMPT.md` — tested LLM prompt for receipt→Beancount conversion. Do not modify without verifying against docs/specs.
|
|
103
|
+
- `RECEIPT_INFO_PROMPT.md` — also do not change, it's manually tested.
|
|
104
|
+
- `RECEIPT_MATCH_PROMPT.md` — same. Do not change.
|
|
105
|
+
|
|
106
|
+
## Gotchas
|
|
107
|
+
|
|
108
|
+
- Config is a singleton per process: calling `Configuration.load()` a second time returns the first result silently. If testing different configs, use separate processes or `--config`.
|
|
109
|
+
- `BeancountConfiguration` takes an exclusive advisory lock on `main_file` as soon as it is instantiated (and `Configuration.load()` instantiates it). The lock is held until `unlock()` or process exit, so data-modifying subcommands queue up. Consequences: `main_file` must exist at config load time (a missing file raises `FileNotFoundError`); tests that build multiple configs pointing at the same file in one process will block; and two concurrent `beanhand` invocations against the same file serialize.
|
|
110
|
+
- Server emits JSONL with no buffering delay (flushes every 10 chunks). Over qrexec this can be slow; client handles line-by-line reading.
|
|
111
|
+
- `beanhand refine` refines one or more transactions: you can indicate which transactions to refine by referring to a line number (selects the transaction containing it) or a range A-B (selects every transaction that *begins* on a line within the inclusive span); the range may also be written A-end, where `end` means the end of the file; a line number may point at any line *within* a transaction; lines / ranges must be strictly ascending and non-overlapping. It writes the file once, at the end, only if at least one accepted refinement changed it.
|