specify 256 bits
fix dependencies
replace sha256 with blake3 from funcool/buddy-core
Pond is a double-entry accounting system inspired by Nix's approach to reproducible builds. Just as Nix tracks dependencies and transformations through cryptographic hashes, Pond tracks financial transactions and their derived states through a similar content-addressed approach.
.pond
filesTransformations are defined in .pond
files:
;; $XDG_DATA_HOME/pond/transforms/my_company/price_resolution.pond
(ns my-company.transforms.price-resolution
(:require
[clojure.string :as str] ; Core Clojure lib
[pond.core.price :as price])) ; Core Pond module
(transform price-resolution
{:inputs []} ; No transform inputs needed
[{:keys [entry state env]} ctx]
(let [prices (:prices env)
resolve-price (fn [posting]
(if-let [price (price/get-price prices
(:asset-code (:amount posting))
(:date entry))]
(assoc-in posting [:amount :meta :exchange-rate] price)
posting))]
{:entry (update entry :postings #(map resolve-price %))
:state state
:env env
:context (assoc-in ctx [:transform-data :price-resolution :resolved] true)}))
;; Initialize registry
user=> (require '[pond.registry :as r])
nil
user=> (def registry (r/create-registry))
#'user/registry
;; Load transformation
user=> (r/load-transform! registry "$XDG_DATA_HOME/pond/transforms/my_company/price_resolution.pond")
{:namespace 'my-company.transforms.price-resolution
:hash "b3-256:8f4K9zjJD6K2Vz+wYP..." ; Hash of source
:status :loaded}
;; Create test state and environment
user=> (def initial-state
{:entries
[{:date "2024-01-20"
:postings
[{:account {:silo :asset
:path [:investments :stocks]}
:amount {:asset-code "VWRA"
:asset-quantity 200}}]}]})
user=> (def env
{:runtime {:clojure-version "1.11.1" ; Runtime versions
:java-version "17"}
:price-db {"VWRA" {:date "2024-01-20"
:price 5.00M
:currency "USD"}}})
;; Apply transformation
user=> (r/apply-transform registry 'my-company.transforms.price-resolution initial-state env {})
{:result {...} ; New state with resolved prices
:hash "b3-256:Kj82nX7..." ; Depends on:
; - Runtime versions
; - Initial state
; - Transform source
; - Price data
:inputs [{:id :runtime :hash "b3-256:7dK9..."}
{:id :initial-state :hash "b3-256:9dF3..."}
{:id :transform :hash "b3-256:8f4K..."}
{:id :price-data :hash "b3-256:92nK..."}]}
;; Verify reproducibility
user=> (r/verify-reproducible! "b3-256:Kj82nX7...")
{:reproducible? true
:verification-hash "b3-256:Kj82nX7..."
:time-taken 42}
pond/
├── src/
│ └── pond/
│ ├── core.clj # Core functionality
│ ├── parser.clj # Transform parser
│ ├── registry.clj # Transform registry
│ ├── hash.clj # Hash computation
│ ├── dgraph.clj # Dependency graph
│ └── transforms/ # Core transforms
│ ├── price_resolution.pond
│ └── balance_validation.pond
├── test/
│ └── pond/
│ ├── parser_test.clj
│ ├── dgraph_test.clj
│ └── core_test.clj
└── $XDG_DATA_HOME/pond/
└── transforms/ # User transforms
└── my_company/
└── custom.pond
Dependencies:
Setup:
# Run tests
clj -M:test
# Run specific test namespace
clj -M:test --focus pond.parser-test
# Start REPL
clj -M:dev -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]"
Currently in early development. Basic features:
Reproducibility
Auditability
Extensibility
.pond
filesDeveloper Experience
.pond
file:(ns my-company.transforms.custom
(:require [pond.core.price :as price]))
(transform custom
{:inputs []}
[{:keys [entry state env]} ctx]
;; Transform implementation...
)
$XDG_DATA_HOME/pond/transforms/my_company/custom.pond
(r/load-transform! registry "path/to/custom.pond")
(r/apply-transform registry 'my-company.transforms.custom state env ctx)
Transform Development
Web Interface
Tax Integration
Ecosystem Support
See DESIGN.md for architectural details and implementation.md for technical specifics.
clj -P
clj -M:test
clj -M:dev -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]"
Follow the transform specification:
Test thoroughly:
Document clearly:
CeCILL License. See LICENSE.md for details.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the CECILL-2.1 license, will be licensed as above, without any additional terms or conditions.