Introduction
Welcome to the kakei documentation!
kakei is a command-line application for managing personal finances using the Japanese kakeibo (家計簿) method. It provides transaction tracking, categorization, and powerful Lisp-based table transformations for flexible analysis and reporting.
What is Kakeibo?
Kakeibo (家計簿) is a Japanese household financial ledger system that emphasizes mindful spending and saving. The word combines:
- 家計 (kakei): household finances
- 簿 (bo): ledger/account book
Key Features
- 📊 Transaction Management: Add, list, and manage financial transactions
- 🏷️ Category & Account Organization: Organize transactions by customizable categories and accounts
- 🔄 Lisp-Based Transformations: Transform and analyze transaction data using a small Lisp dialect
- 📋 Table Display: Beautiful table formatting using the
tabledcrate - 💾 SQLite Database: Persistent storage with automatic migrations
- ⚙️ Configuration: Customizable categories and accounts
Why kakei?
Traditional financial tracking tools can be rigid and inflexible. kakei takes a different approach:
- Flexible Data Analysis: Use Lisp expressions to transform and analyze your financial data in any way you need
- Command-Line First: Designed for developers and power users who prefer the command line
- Open and Portable: Your data is stored in a standard SQLite database that you fully control
- Extensible: The Lisp-based transformation system allows for unlimited customization
Getting Started
If you're new to kakei, we recommend:
- Start with the Installation guide to get kakei installed on your system
- Follow the Quick Start guide to initialize your database and add your first transactions
- Explore the Commands reference to learn all available commands
- Learn about Lisp Functions to unlock powerful data transformations
Contributing
kakei is open source and welcomes contributions! See the Contributing guide for more information.
License
kakei is licensed under the MIT License. See the repository's LICENSE file for details.
Author
haruki7049 tontonkirikiri@gmail.com
Repository
https://github.com/haruki7049/kakei
Installation
This guide covers all the ways you can install kakei on your system.
Choose the installation method that works best for you:
- Prerequisites - System requirements
- Build from Source - Build the latest version yourself
- Install via Cargo - Quick install if you have Rust
- Binary Releases - Download pre-built binaries
- Install via Nix - Install with Nix package manager
- Platform Notes - Platform-specific information
Verifying Installation
After installation, verify that kakei is correctly installed:
kakei --help
You should see the help message with available commands.
Next Steps
Now that you have kakei installed, proceed to the Quick Start guide to initialize your database and start tracking your finances!
Prerequisites
Before installing kakei, ensure you have:
- Rust 1.91.1 or later (for building from source)
- SQLite 3 (for database functionality)
Build from Source
Building from source gives you the latest version and allows you to customize the build:
git clone https://github.com/haruki7049/kakei.git
cd kakei
cargo build --release
The binary will be available at target/release/kakei. You can copy it to a directory on your PATH (e.g., /usr/local/bin) if desired:
sudo cp target/release/kakei /usr/local/bin/
Install via Cargo
The easiest way to install kakei if you already have Rust installed:
From the repository root:
cargo install --path .
This installs kakei to your cargo bin directory (usually ~/.cargo/bin).
Make sure ~/.cargo/bin is in your PATH:
export PATH="$HOME/.cargo/bin:$PATH"
Binary Releases
Pre-built binaries may be available for download on the GitHub Releases page.
To install from a release:
- Download the appropriate archive for your platform
- Extract the
kakeibinary - Move it to a directory on your PATH (e.g.,
/usr/local/bin/) - Make it executable:
chmod +x /usr/local/bin/kakei
Install via Nix
If you have Nix with flakes enabled, you can install kakei directly from the repository:
Quick Run (without installing)
# Run directly without installing
nix run github:haruki7049/kakei -- --help
Install to Profile
# Install from the flake
nix profile install github:haruki7049/kakei
Development Environment
For local development, the flake provides a development shell:
# Enter development shell with Rust toolchain and dependencies
nix develop
The flake provides:
packages.default: The kakei binarydevShells.default: Development environment with Rust toolchain and dependencies
Platform Notes
Linux
On Linux, kakei follows the XDG Base Directory Specification:
- Configuration:
~/.config/kakei/(or$XDG_CONFIG_HOME/kakei/) - Data:
~/.local/share/kakei/(or$XDG_DATA_HOME/kakei/)
macOS
On macOS, if XDG environment variables are not set, kakei will use:
- Configuration:
~/Library/Application Support/kakei/ - Data:
~/Library/Application Support/kakei/
Windows
On Windows, if XDG environment variables are not set, kakei will use:
- Configuration:
%APPDATA%\kakei\ - Data:
%APPDATA%\kakei\
Verifying Installation
After installation, verify that kakei is correctly installed:
kakei --help
You should see the help message with available commands.
Next Steps
Now that you have kakei installed, proceed to the Quick Start guide to initialize your database and start tracking your finances!
Quick Start
This guide will walk you through the basic workflow of using kakei to manage your finances.
- Initialize Database - Set up your kakei database
- Add Transactions - Record financial transactions
- List Transactions - View your transaction history
- Transform with Lisp - Analyze data with Lisp expressions
Initialize Database
Before you can start tracking transactions, you need to initialize the database:
kakei init
This command:
- Creates the database file at the appropriate location for your platform
- Linux (XDG):
~/.local/share/kakei/kakei.db - macOS:
~/Library/Application Support/kakei/kakei.db - Windows:
%APPDATA%\kakei\kakei.db
- Linux (XDG):
- Runs database migrations to set up the schema
- Initializes default categories: Food, Transport, Daily Goods, Hobby, Salary
- Initializes default accounts: Cash, Bank
You only need to run this command once when you first start using kakei.
Add Transactions
Now you can start adding financial transactions. The kakei add command requires several pieces of information:
Basic Expense
Record a simple expense:
kakei add --date 2025-01-01 --amount -1000 --category Food --account Cash
Expense with Memo
Add a note to help remember what the transaction was for:
kakei add --date 2025-01-02 --amount -2000 --category Transport --account Cash --memo "Train pass"
Recording Income
Positive amounts represent income:
kakei add --date 2025-01-15 --amount 50000 --category Salary --account Bank --memo "Monthly salary"
Different Currency
By default, kakei uses JPY (Japanese Yen), but you can specify other currencies:
kakei add --date 2025-01-20 --amount -50 --category Food --account Cash --currency USD
Understanding Amounts
The --amount parameter expects values in the currency's minor units as an integer:
-
For JPY (no subunits): Use integer yen
-1000represents ¥-1,000 (expense)50000represents ¥50,000 (income)
-
For USD, EUR, etc.: Use cents
-1050represents $-10.50 (expense)50000represents $500.00 (income)
Negative amounts = expenses (money going out)
Positive amounts = income (money coming in)
List Transactions
View your recent transactions in a formatted table:
kakei list
Example output:
╭────────────┬────────┬───────────┬─────────┬──────────────╮
│ Date │ Amount │ Category │ Account │ Memo │
├────────────┼────────┼───────────┼─────────┼──────────────┤
│ 2025-01-15 │ ¥50000 │ Salary │ Bank │ Monthly sal… │
│ 2025-01-02 │ ¥-2000 │ Transport │ Cash │ Train pass │
│ 2025-01-01 │ ¥-1000 │ Food │ Cash │ │
╰────────────┴────────┴───────────┴─────────┴──────────────╯
The list command displays the 20 most recent transactions by default, showing:
- Date
- Amount (with currency symbol)
- Category
- Account
- Memo
Transform with Lisp
One of kakei's most powerful features is the ability to transform and analyze your transaction data using Lisp expressions.
View All Transactions
kakei transform --program "table"
The table variable contains all your transactions as a Lisp data structure.
Group by Category
See spending broken down by category:
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'category (cdr pair)))))"
Group by Account
See transactions grouped by account:
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'account (cdr pair)))))"
Get First Transaction
kakei transform --program "(cons (car table) ())"
Skip First Transaction
kakei transform --program "(cdr table)"
Get First Two Transactions
kakei transform --program "(cons (car table) (cons (car (cdr table)) ()))"
Commands
Complete reference for all kakei commands.
- init - Initialize the database and configuration
- add - Add a new financial transaction
- list - List recent transactions
- transform - Transform and analyze data with Lisp
init
Initialize the database and configuration.
Usage
kakei init
Description
The init command sets up kakei for first-time use:
-
Creates the database file at the platform-appropriate location:
- Linux (XDG):
~/.local/share/kakei/kakei.db - macOS:
~/Library/Application Support/kakei/kakei.db - Windows:
%APPDATA%\kakei\kakei.db
- Linux (XDG):
-
Runs database migrations to create the necessary tables and schema
-
Initializes default categories:
- Food
- Transport
- Daily Goods
- Hobby
- Salary
-
Initializes default accounts:
- Cash
- Bank
When to Use
- Run this command once when you first install kakei
- If you delete your database and want to start fresh
- After moving kakei to a new system
Example
$ kakei init
Database initialized successfully!
add
Add a new financial transaction to the database.
Usage
kakei add --date <DATE> --amount <AMOUNT> --category <CATEGORY> --account <ACCOUNT> [OPTIONS]
Required Arguments
-
--date <DATE>- Transaction date in YYYY-MM-DD format
- Example:
2025-01-15
-
--amount <AMOUNT>- Transaction amount in minor units (integer)
- Negative for expenses (money out)
- Positive for income (money in)
- Example:
-1000(¥-1,000 expense) or50000(¥50,000 income)
-
--category <CATEGORY>- Category name for the transaction
- Must match one of your configured categories
- Example:
Food,Transport,Salary
-
--account <ACCOUNT>- Account name for the transaction
- Must match one of your configured accounts
- Example:
Cash,Bank,Card
Optional Arguments
-
--currency <CURRENCY>- Currency code (default:
JPY) - Example:
USD,EUR,GBP
- Currency code (default:
-
--memo <MEMO>- Optional note or description
- Example:
"Monthly train pass"
Examples
Simple Expense
kakei add --date 2025-01-01 --amount -1000 --category Food --account Cash
Expense with Memo
kakei add --date 2025-01-02 --amount -2000 --category Transport --account Cash --memo "Monthly train pass"
Recording Income
kakei add --date 2025-01-15 --amount 50000 --category Salary --account Bank
USD Transaction
kakei add --date 2025-01-20 --amount -5000 --category Food --account Cash --currency USD --memo "Dinner in NYC"
Amount Format
The --amount parameter uses minor units (the smallest subdivision of a currency):
| Currency | Minor Unit | Example Input | Actual Value |
|---|---|---|---|
| JPY | Yen (no subunit) | -1000 | ¥-1,000 |
| USD | Cents | -1050 | $-10.50 |
| EUR | Cents | -2099 | €-20.99 |
| GBP | Pence | -1500 | £-15.00 |
list
Display recent transactions in a formatted table.
Usage
kakei list
Description
The list command displays your 20 most recent transactions in a beautifully formatted table with rounded borders.
Output Format
╭────────────┬────────┬───────────┬─────────┬──────────────╮
│ Date │ Amount │ Category │ Account │ Memo │
├────────────┼────────┼───────────┼─────────┼──────────────┤
│ 2025-01-15 │ ¥50000 │ Salary │ Bank │ Monthly sal… │
│ 2025-01-02 │ ¥-2000 │ Transport │ Cash │ Train pass │
│ 2025-01-01 │ ¥-1000 │ Food │ Cash │ │
╰────────────┴────────┴───────────┴─────────┴──────────────╯
Columns
- Date: Transaction date (YYYY-MM-DD)
- Amount: Formatted amount with currency symbol
- Category: Transaction category
- Account: Account used
- Memo: Optional note (truncated if long)
Example
$ kakei list
╭────────────┬────────┬───────────┬─────────┬──────────────╮
│ Date │ Amount │ Category │ Account │ Memo │
├────────────┼────────┼───────────┼─────────┼──────────────┤
│ 2025-01-15 │ ¥50000 │ Salary │ Bank │ Monthly sal… │
│ 2025-01-02 │ ¥-2000 │ Transport │ Cash │ Train pass │
│ 2025-01-01 │ ¥-1000 │ Food │ Cash │ │
╰────────────┴────────┴───────────┴─────────┴──────────────╯
transform
Transform and analyze transaction data using Lisp programs.
Usage
kakei transform --program <LISP_PROGRAM>
Required Arguments
--program <LISP_PROGRAM>- A Lisp expression that transforms the transaction table
- The variable
tablecontains all transactions - See Lisp Functions for available functions
Description
The transform command is kakei's most powerful feature. It allows you to:
- Filter transactions based on criteria
- Group transactions by category, account, or custom logic
- Perform calculations and aggregations
- Extract specific transaction fields
- Create custom reports
The transaction data is provided as a Lisp data structure in the table variable.
Examples
View All Transactions
kakei transform --program "table"
Group by Category
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'category (cdr pair)))))"
Group by Account
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'account (cdr pair)))))"
Get First Transaction Only
kakei transform --program "(cons (car table) ())"
Skip First Transaction
kakei transform --program "(cdr table)"
Get First Two Transactions
kakei transform --program "(cons (car table) (cons (car (cdr table)) ()))"
Shell Quoting
Be careful with shell quoting when passing Lisp programs:
POSIX shells:
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'category (cdr pair)))))"
PowerShell:
kakei transform --program '(group-by table (lambda (pair) (cdr (assoc ''category'' (cdr pair)))))'
See Also
- Data Format - Understanding transaction data structure
- Lisp Functions - Complete reference of available Lisp functions
- Examples - Real-world transformation examples
Data Format
Understanding how kakei represents transaction data internally is essential for effective use of the transform command.
- Transaction Structure - How individual transactions are represented
- Table Structure - How the table of transactions is organized
Transaction Structure
Each transaction in kakei is represented as an association list (alist) in Lisp format. An association list is a list of key-value pairs.
Single Transaction Example
(ID-001 . ((date . "2025-01-01")
(amount . -1000)
(category . "Food")
(account . "Cash")
(memo . "")))
Transaction Fields
Each transaction contains the following fields:
| Field | Type | Description | Example |
|---|---|---|---|
| ID | String | Unique transaction identifier | "ID-001" |
| date | String | Transaction date (YYYY-MM-DD) | "2025-01-01" |
| amount | Integer | Amount in minor units | -1000 (¥-1,000) |
| category | String | Category name | "Food" |
| account | String | Account name | "Cash" |
| memo | String | Optional note (empty string if none) | "Train pass" |
Understanding the Structure
The transaction is a pair (cons cell):
- Car (first element): Transaction ID
- Cdr (second element): Association list of fields
(ID-001 . field-list)
The field list is itself a list of pairs:
((date . "2025-01-01")
(amount . -1000)
(category . "Food")
(account . "Cash")
(memo . ""))
Table Structure
The table variable provided to transform commands contains a list of transactions:
((ID-001 . ((date . "2025-01-01") (amount . -1000) ...))
(ID-002 . ((date . "2025-01-02") (amount . -2000) ...))
(ID-003 . ((date . "2025-01-15") (amount . 50000) ...))
...)
Table Operations
Access First Transaction
(car table)
Returns:
(ID-001 . ((date . "2025-01-01") (amount . -1000) ...))
Access Remaining Transactions
(cdr table)
Returns a table without the first transaction.
Get Transaction ID
(car (car table))
or
(car (car table))
Get Transaction Fields
(cdr (car table))
Returns the association list of fields for the first transaction.
Lisp Functions
The kakei_lisp dialect provides a set of built-in functions for transforming and analyzing transaction data. This reference covers all available functions.
- Core Functions - lambda, define, if
- List Operations - cons, car, cdr
- Comparison Functions - equal?, null?
- Association List Functions - assoc and working with alists
- Table Manipulation - group-by and other table operations
Core Functions
lambda
Create anonymous (unnamed) functions.
Syntax:
(lambda (parameter ...) body)
Examples:
; Function that adds 1 to its argument
(lambda (x) (+ x 1))
; Function that gets the category from a transaction
(lambda (pair) (cdr (assoc 'category (cdr pair))))
Usage in transform:
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'category (cdr pair)))))"
define
Define variables or functions for reuse within a program.
Syntax:
(define name value)
Examples:
; Define a constant
(define pi 3.14159)
; Define a function
(define (double x) (+ x x))
; Use the defined function
(double 5) ; => 10
if
Conditional evaluation - execute different code based on a condition.
Syntax:
(if condition then-expr else-expr)
Examples:
; Check if a value is empty
(if (null? x) "empty" "not empty")
; Check equality
(if (equal? category "Food") "food-related" "other")
List Operations
cons
Construct a pair (cons cell) - the fundamental building block of Lisp lists.
Syntax:
(cons first second)
Examples:
(cons 1 2) ; => (1 . 2)
(cons 1 ()) ; => (1)
(cons 1 (cons 2 ())) ; => (1 2)
Usage:
; Create a list with the first transaction only
(cons (car table) ())
car
Get the first element of a pair.
Syntax:
(car pair)
Examples:
(car (cons 1 2)) ; => 1
(car '(1 2 3)) ; => 1
(car table) ; => first transaction
Usage:
# Get the first transaction
kakei transform --program "(car table)"
cdr
Get the second element of a pair (everything after the first element).
Syntax:
(cdr pair)
Examples:
(cdr (cons 1 2)) ; => 2
(cdr '(1 2 3)) ; => (2 3)
(cdr table) ; => all transactions except first
Usage:
# Skip the first transaction
kakei transform --program "(cdr table)"
Comparison Functions
equal?
Test if two values are equal.
Syntax:
(equal? value1 value2)
Examples:
(equal? "Food" "Food") ; => #t (true)
(equal? "Food" "Transport") ; => #f (false)
(equal? 100 100) ; => #t
(equal? 100 200) ; => #f
Usage:
; Filter transactions where category is "Food"
(if (equal? (cdr (assoc 'category (cdr pair))) "Food")
pair
())
null?
Test if a value is nil (empty).
Syntax:
(null? value)
Examples:
(null? ()) ; => #t (true)
(null? '(1 2 3)) ; => #f (false)
(null? "") ; => #f (false - empty string is not nil)
Usage:
; Check if we've reached the end of a list
(if (null? remaining-transactions)
"No more transactions"
"More transactions exist")
Association List Functions
assoc
Find a key in an association list and return the key-value pair.
Syntax:
(assoc key alist)
Examples:
(assoc 'category '((date . "2025-01-01") (category . "Food")))
; => (category . "Food")
(assoc 'amount '((date . "2025-01-01") (amount . -1000)))
; => (amount . -1000)
Usage:
# Get the category field from first transaction
kakei transform --program "(assoc 'category (cdr (car table)))"
To get just the value (not the pair), combine with cdr:
# Get the category value
kakei transform --program "(cdr (assoc 'category (cdr (car table))))"
Common Pattern: Extracting Field Values
; Get category of a transaction
(cdr (assoc 'category (cdr transaction)))
; Get amount of a transaction
(cdr (assoc 'amount (cdr transaction)))
; Get date of a transaction
(cdr (assoc 'date (cdr transaction)))
; Get account of a transaction
(cdr (assoc 'account (cdr transaction)))
; Get memo of a transaction
(cdr (assoc 'memo (cdr transaction)))
Table Manipulation
group-by
Group a table of transactions by a key function. This is one of the most powerful functions for analysis.
Syntax:
(group-by table key-fn)
Parameters:
table: The list of transactionskey-fn: A lambda function that extracts the grouping key from each transaction
Returns: A list of groups, where each group is:
("GroupName" (transaction1) (transaction2) ...)
Examples:
Group by Category
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'category (cdr pair)))))"
Output structure:
(("Food"
(ID-001 . ((date . "2025-01-01") (amount . -1000) ...)))
("Transport"
(ID-002 . ((date . "2025-01-02") (amount . -2000) ...)))
("Salary"
(ID-003 . ((date . "2025-01-15") (amount . 50000) ...))))
Group by Account
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'account (cdr pair)))))"
Group by Date
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'date (cdr pair)))))"
How it Works:
For each transaction in the table:
- The lambda function extracts a grouping key (e.g., category name)
- Transactions with the same key are grouped together
- The result is a list of groups labeled by their key
Configuration
Learn how to configure kakei to match your financial tracking needs.
- Configuration File - Format and location of config.toml
- Database Location - Where kakei stores your data
Configuration File
kakei uses a TOML configuration file to customize default categories and accounts.
Location
The configuration file location depends on your operating system:
- Linux (XDG):
~/.config/kakei/config.toml(or$XDG_CONFIG_HOME/kakei/config.toml) - macOS:
~/Library/Application Support/kakei/config.toml - Windows:
%APPDATA%\kakei\config.toml
Format
The configuration file uses TOML format:
default_categories = ["Food", "Transport", "Daily Goods", "Hobby", "Salary"]
default_accounts = ["Cash", "Bank"]
Creating a Configuration File
kakei automatically creates a default configuration when you run kakei init. If you want to customize it:
-
Locate the config file (see locations above)
-
Edit with your favorite text editor:
# Linux/macOS nano ~/.config/kakei/config.toml # Or use any editor you prefer vim ~/.config/kakei/config.toml code ~/.config/kakei/config.toml -
Add your custom categories and accounts
Example Configurations
Personal Finance Tracking
default_categories = [
"Food",
"Transport",
"Housing",
"Utilities",
"Healthcare",
"Entertainment",
"Shopping",
"Salary",
"Freelance",
"Investment"
]
default_accounts = [
"Cash",
"Bank",
"Credit Card",
"Savings",
"Investment Account"
]
Business Expense Tracking
default_categories = [
"Office Supplies",
"Software",
"Travel",
"Meals",
"Marketing",
"Payroll",
"Revenue",
"Consulting"
]
default_accounts = [
"Business Checking",
"Business Savings",
"Business Credit Card",
"Petty Cash"
]
Minimal Setup
default_categories = ["Expense", "Income"]
default_accounts = ["Main"]
Database Location
The SQLite database file stores all your transaction data.
Default Location
- Linux (XDG):
~/.local/share/kakei/kakei.db(or$XDG_DATA_HOME/kakei/kakei.db) - macOS:
~/Library/Application Support/kakei/kakei.db - Windows:
%APPDATA%\kakei\kakei.db
Customizing Database Location
Currently, kakei automatically determines the database location based on your operating system's conventions. To use a different location:
-
Set the XDG_DATA_HOME environment variable (Linux):
export XDG_DATA_HOME=/path/to/custom/location -
Run kakei commands - they will now use the custom location
Backing Up Your Database
Since your financial data is stored in a single SQLite file, backing up is simple:
# Linux/macOS
cp ~/.local/share/kakei/kakei.db ~/backup/kakei-backup-$(date +%Y%m%d).db
# Or create a scheduled backup script
#!/bin/bash
BACKUP_DIR=~/kakei-backups
mkdir -p "$BACKUP_DIR"
cp ~/.local/share/kakei/kakei.db "$BACKUP_DIR/kakei-$(date +%Y%m%d-%H%M%S).db"
Database Schema
The database is a standard SQLite database. You can inspect it directly using SQLite tools:
sqlite3 ~/.local/share/kakei/kakei.db
# Inside sqlite3:
.tables # List tables
.schema # Show schema
SELECT * FROM transactions LIMIT 5; # Query transactions
Warning: Directly modifying the database outside of kakei commands may cause data corruption. Always use kakei commands for data manipulation, and only use direct SQL for read-only queries.
Examples
Real-world examples of using kakei for various financial tracking scenarios.
- Monthly Budget Tracking - Track monthly income and expenses
- Analyzing Spending Patterns - Understand where your money goes
Monthly Budget Tracking
Track your monthly income and expenses to understand your budget.
Setup
First, add your transactions for the month:
# Add various expenses
kakei add --date 2025-01-05 --amount -1200 --category Food --account Cash --memo "Lunch"
kakei add --date 2025-01-10 --amount -3000 --category Transport --account Card --memo "Monthly pass"
kakei add --date 2025-01-12 --amount -500 --category Hobby --account Cash --memo "Book"
kakei add --date 2025-01-20 --amount -800 --category Food --account Cash --memo "Dinner"
# Add income
kakei add --date 2025-01-15 --amount 50000 --category Salary --account Bank --memo "January salary"
View All Transactions
kakei list
Output:
╭────────────┬────────┬───────────┬─────────┬──────────────╮
│ Date │ Amount │ Category │ Account │ Memo │
├────────────┼────────┼───────────┼─────────┼──────────────┤
│ 2025-01-20 │ ¥-800 │ Food │ Cash │ Dinner │
│ 2025-01-15 │ ¥50000 │ Salary │ Bank │ January sal… │
│ 2025-01-12 │ ¥-500 │ Hobby │ Cash │ Book │
│ 2025-01-10 │ ¥-3000 │ Transport │ Card │ Monthly pass │
│ 2025-01-05 │ ¥-1200 │ Food │ Cash │ Lunch │
╰────────────┴────────┴───────────┴─────────┴──────────────╯
Group by Category
See spending breakdown by category:
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'category (cdr pair)))))"
This shows all transactions grouped by their category, making it easy to see where your money is going.
Calculate Category Totals
While kakei's Lisp dialect doesn't have arithmetic functions yet, you can group by category and manually sum the amounts:
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'category (cdr pair)))))"
Look at the amounts in each group to understand your spending patterns.
Analyzing Spending Patterns
Group by Account
See where your money is being spent:
kakei transform --program "(group-by table (lambda (pair) (cdr (assoc 'account (cdr pair)))))"
This helps you understand:
- How much you're spending from each account
- Whether you're using cash vs. card appropriately
- If your bank balance matches your expectations
View Recent Transactions Only
Get just the most recent transaction:
kakei transform --program "(cons (car table) ())"
Get the two most recent transactions:
kakei transform --program "(cons (car table) (cons (car (cdr table)) ()))"
Skip Old Transactions
Skip the first (oldest) transaction:
kakei transform --program "(cdr table)"
This is useful when you want to exclude historical data from analysis.
Architecture
Understanding kakei's internal architecture helps developers contribute effectively and users understand how the application works.
Project Structure
kakei is organized as a Rust workspace with multiple crates:
kakei/
├── src/ # Main CLI application
├── crates/
│ └── processor/
│ ├── src/ # Business logic and transformations
│ └── crates/
│ ├── database/ # Database layer (SQLite)
│ ├── money/ # Money type with currency support
│ └── klisp/ # Embedded Lisp dialect
├── tests/ # Integration tests
├── book/ # Documentation (mdBook)
└── Cargo.toml # Workspace configuration
Crate Overview
kakei (Main Crate)
Location: src/
Purpose: Command-line interface and user interaction
Responsibilities:
- Parse command-line arguments using
clap - Handle user input and output
- Coordinate between other crates
- Format output tables using
tabled - Manage configuration with
confy
Key Files:
src/main.rs: Application entry pointsrc/commands/: Command implementations (init, add, list, transform)
kakei_processor
Location: crates/processor/
Purpose: Business logic and table transformations
Responsibilities:
- Transaction management logic
- Table transformation orchestration
- Integration between database and Lisp interpreter
- Data conversion between formats
Dependencies:
kakei_database: For data persistencekakei_lisp: For Lisp evaluationkakei_money: For money types
kakei_database
Location: crates/processor/crates/database/
Purpose: Database layer with SQLite
Responsibilities:
- SQLite database connection management
- Transaction CRUD operations
- Database migrations
- Query execution
Key Technologies:
sqlx: Async SQLite driver with compile-time query verificationchrono: Date/time handling
Schema:
CREATE TABLE transactions (
id TEXT PRIMARY KEY,
date TEXT NOT NULL,
amount INTEGER NOT NULL,
category TEXT NOT NULL,
account TEXT NOT NULL,
currency TEXT NOT NULL DEFAULT 'JPY',
memo TEXT
);
kakei_money
Location: crates/processor/crates/money/
Purpose: Money type with currency support
Responsibilities:
- Type-safe money representation
- Currency handling (JPY, USD, EUR, etc.)
- Amount formatting with proper symbols
- Minor unit conversion
Key Types:
#![allow(unused)] fn main() { pub struct Money { amount: i64, // Amount in minor units currency: Currency, // Currency type } pub enum Currency { JPY, USD, EUR, GBP, // ... } }
Features:
- Amounts stored in minor units (cents, yen, etc.)
- Currency-specific formatting
- Decimal conversion utilities
kakei_lisp
Location: crates/processor/crates/klisp/
Purpose: Embedded Lisp dialect for data transformation
Responsibilities:
- Lisp parsing (using
nomparser combinator) - Expression evaluation
- Built-in function implementations
- Runtime environment
Language Features:
- S-expressions:
(func arg1 arg2) - Lambda functions:
(lambda (x) (+ x 1)) - Core functions:
cons,car,cdr,if,define - Association lists:
assoc - Table manipulation:
group-by
Architecture:
Input String
↓
Parser (nom)
↓
AST (Abstract Syntax Tree)
↓
Evaluator
↓
Result Value
Data Flow
Adding a Transaction
User Command
↓
CLI (kakei)
↓
Parse Arguments (clap)
↓
Create Transaction Object
↓
Processor (kakei_processor)
↓
Database Layer (kakei_database)
↓
SQLite Database
Listing Transactions
User Command
↓
CLI (kakei)
↓
Processor (kakei_processor)
↓
Database Layer (kakei_database)
↓
Query SQLite
↓
Convert to Money Types (kakei_money)
↓
Format as Table (tabled)
↓
Display to User
Transform Command
User Command with Lisp Program
↓
CLI (kakei)
↓
Processor (kakei_processor)
↓
Database: Load Transactions
↓
Convert to Lisp Data Structure
↓
Lisp Interpreter (kakei_lisp)
↓
Parse Lisp Program
↓
Evaluate Against Transaction Data
↓
Convert Result Back
↓
Format as Table
↓
Display to User
Key Technologies
Rust Edition
- Rust 2024 Edition (Edition 2024)
- Minimum Rust Version: 1.91.1
Major Dependencies
| Crate | Version | Purpose |
|---|---|---|
clap | 4.4.11 | Command-line argument parsing |
sqlx | 0.8.6 | Async SQLite with compile-time checks |
tokio | 1.48.0 | Async runtime |
chrono | 0.4.42 | Date and time handling |
tabled | 0.20.0 | Table formatting |
nom | 8.0.0 | Parser combinators for Lisp |
serde | 1.0.219 | Serialization/deserialization |
confy | 0.6.1 | Configuration management |
directories | 6.0.0 | Platform-appropriate directories |
xdg | 3.0.0 | XDG Base Directory support |
Testing
assert_cmd: CLI testingpredicates: Assertion helperstempfile: Temporary files for tests
Nix Integration
kakei includes Nix flakes support for reproducible builds:
flake.nix: Flake definitionflake.lock: Locked dependenciesdefault.nix: Traditional Nix buildshell.nix: Development shell
Design Patterns
Workspace Organization
The workspace structure allows:
- Independent testing of each component
- Clear separation of concerns
- Reusable components (e.g.,
kakei_moneycould be used elsewhere) - Faster incremental builds
Error Handling
kakei uses thiserror for custom error types:
#![allow(unused)] fn main() { #[derive(Error, Debug)] pub enum KakeiError { #[error("Database error: {0}")] Database(#[from] sqlx::Error), #[error("Configuration error: {0}")] Config(String), // ... } }
Async/Await
Database operations are async using tokio:
#[tokio::main] async fn main() -> Result<()> { // Async operations }
Type Safety
Strong typing throughout:
Moneytype ensures currency safetyTransactionstructs validate data- Compile-time SQL query verification
Configuration Management
Directory Resolution
Check XDG Environment Variables
↓ (if not set)
Platform-Specific Defaults
↓
Create Directory if Missing
↓
Load/Create Config File
Configuration Flow
confy crate
↓
Load config.toml
↓
Parse with TOML parser
↓
Deserialize to Config struct
↓
Use in Application
Database Management
Migrations
Migrations are handled at application startup:
- Check if database exists
- Create if missing
- Run pending migrations
- Initialize default data (categories, accounts)
Connection Pooling
SQLx provides connection pooling for efficient database access:
#![allow(unused)] fn main() { let pool = SqlitePool::connect(&database_url).await?; }
Performance Considerations
Query Optimization
- Indexes on frequently queried columns
- Limit clauses for list operations (default: 20 transactions)
- Efficient date-based queries
Memory Usage
- Streaming results for large datasets
- Lazy evaluation in Lisp interpreter
- Efficient cons cell representation
Build Optimization
- Release builds with optimizations enabled
- Incremental compilation in workspace
- Cargo cache for dependencies
Security Considerations
Data Safety
- SQLite ACID properties ensure data integrity
- Transactions for atomic operations
- Regular backups recommended
Input Validation
- Command-line argument validation via
clap - SQL injection prevention via parameterized queries (sqlx)
- Type-safe APIs throughout
File Permissions
- Configuration and database files are user-readable/writable only
- No sensitive data in configuration (categories/accounts only)
Future Architecture Considerations
Potential areas for expansion:
- Plugin System: Allow custom Lisp functions via plugins
- Multiple Databases: Support for multiple financial ledgers
- Import/Export: CSV/JSON import/export capabilities
- Web Interface: Optional web UI using the same core crates
- Sync: Cloud sync or multi-device support
- More Lisp Functions: Additional built-ins for calculations
Contributing to Architecture
When contributing, consider:
- Maintain separation of concerns - keep crates focused
- Add tests - especially for new Lisp functions
- Document public APIs - use Rust doc comments
- Follow existing patterns - match the codebase style
- Consider performance - especially for database operations
See Also
- Development - Building and testing
- Contributing - Contribution guidelines
- Repository - Source code
Development
Guide for developers working on kakei.
- Running Tests - How to run the test suite
- Linting - Code quality checks
- Building - Building the project
Running Tests
Run All Tests
cargo test --workspace
This runs:
- Unit tests in each crate
- Integration tests in
tests/ - Doc tests in documentation comments
Run Tests for Specific Crate
# Test the Lisp interpreter
cargo test --package kakei_lisp
# Test the database layer
cargo test --package kakei_database
# Test the processor
cargo test --package kakei_processor
Run with Output
See test output (normally hidden for passing tests):
cargo test -- --nocapture
Run Specific Test
cargo test test_name
Run Tests in Parallel
By default, Cargo runs tests in parallel. To run serially:
cargo test -- --test-threads=1
Doc Tests
Run only documentation tests:
cargo test --doc
Linting
Clippy
Run the Clippy linter for best practices and common mistakes:
cargo clippy --workspace
Fix warnings automatically (when possible):
cargo clippy --workspace --fix
Clippy with all warnings as errors:
cargo clippy --workspace -- -D warnings
Format Check
Check if code is properly formatted:
cargo fmt --check
Format Code
Auto-format all code:
cargo fmt
Building
Debug Build
For development, use debug builds (faster compilation, includes debug symbols):
cargo build
The binary will be at target/debug/kakei.
Release Build
For production use or performance testing:
cargo build --release
The binary will be at target/release/kakei.
Build Specific Crate
Build only a specific crate in the workspace:
# Build just the Lisp interpreter
cargo build --package kakei_lisp
# Build the database layer
cargo build --package kakei_database
Build All Workspace Members
cargo build --workspace
Contributing
Thank you for your interest in contributing to kakei! This guide will help you get started.
- How to Build Locally - Set up your development environment
- Preview Documentation - Build and preview the docs locally
- Submitting Pull Requests - How to submit your changes
How to Build Locally
To build kakei locally for development:
Clone the Repository
git clone https://github.com/haruki7049/kakei.git
cd kakei
Build with Cargo
cargo build
Run Tests
cargo test --workspace
Run the Application
cargo run -- --help
For more details, see the Development guide.
Preview Documentation
To preview the documentation locally:
Install mdBook
cargo install mdbook
Build and Serve
cd docs/book
mdbook serve
Then open http://localhost:3000 in your browser.
Making Changes
- Edit the markdown files in
docs/book/src/ - The documentation will automatically reload when you save changes
- Review your changes in the browser
For more information, see the docs/book/README.md.
Submitting Pull Requests
Before Submitting
- Fork the repository on GitHub
- Create a feature branch from
main - Make your changes with clear, focused commits
- Test your changes - run
cargo test --workspace - Lint your code - run
cargo clippy --workspace - Format your code - run
cargo fmt
Creating the Pull Request
- Push your branch to your fork
- Open a pull request on GitHub
- Fill in the PR template with:
- Description of changes
- Related issues
- Testing done
- Wait for review - maintainers will review your PR
After Submission
- Respond to feedback - address review comments promptly
- Keep your PR updated - rebase if needed
- Be patient - reviews may take time
PR Guidelines
- Keep PRs focused on a single feature or fix
- Write clear commit messages
- Update documentation if needed
- Add tests for new functionality