Skip to content
guywilsonPublic

About

Command line Personal Finance Manager

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Repository files navigation

NAME

pfm - personal finance manager

SYNOPSIS

pfm [options]

DESCRIPTION

PFM is a personal finance application that uses a command-line interface to interact with accounts, transactions and recurring charges.

PFM supports multiple accounts, transactions, recurring charges, categories and payees. The data is stored in an encrypted SQLite database file, requiring a password to open.

BUILDING FROM SOURCE

PFM requires a C++20 compiler, GNU make, and the development headers and libraries for GNU Readline/History, curses or terminfo, SQLCipher, libgcrypt, libcred, libhttpserver and libmicrohttpd. The nlohmann JSON headers are also required. Install Pandoc to build and install the manual page.

Generate the configure script using Autoconf (2.69 or newer; autoreconf also uses Automake's helper tools):

autoreconf --install

Then configure, build and install:

./configure --prefix=/usr/local
make -j4
make install

The script is named configure, invoked as ./configure. It generates a makefile; the hand-written predecessor is kept as makefile.original. Installation may require elevated permissions depending on the chosen prefix. Use make install DESTDIR=/path/to/staging for a staged installation.

For dependencies outside the compiler's default search paths, supply their include and library directories, for example:

./configure CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib"

Choose a debug or release build when configuring:

./configure --enable-debug    # -g -O0: debug symbols, no optimization
./configure --disable-debug   # -O2: release, no -g (the default)

Run one of these commands with any required dependency flags, then run make. Reconfiguring changes the generated makefile, so make recompiles existing objects with the selected flags. Explicit CFLAGS or CXXFLAGS override the defaults for that language, including debug and optimization flags.

Both modes retain the original makefile's -Wall -pedantic warnings, SQLITE_HAS_CODEC definition, and dependency generation. C++ builds use -std=c++20, and compilation/linking retain pthread support. Debug builds also define RUN_IN_DEBUGGER and DEBUG_PASSWORD (empty by default), matching the original debugger-specific application behavior. Use make DEBUG_PASSWD=example to override the debug password; if changing it after compiling, run make clean first. The test-suite definition remains controlled by --enable-test-suite.

Additional transitive libraries, if needed for static linking, can be supplied with LIBS. Use ./configure --enable-test-suite to compile PFM's built-in test suite. The checked-in src/version.c supplies the application version; normal builds do not require vbuild or increment the version.

To explicitly increment the version using the existing vbuild tool:

make version
make -j4

configure locates vbuild; its absence does not prevent normal builds. Override its location with ./configure VBUILD=/path/to/vbuild or make version VBUILD=/path/to/vbuild. The major and minor numbers come from the MAJOR.MINOR version in AC_INIT in configure.ac. When changing that release series, update AC_INIT, regenerate configure, and reconfigure.

make version increments pfm.ver and regenerates src/version.c, including the timestamp, in the source tree even when using a separate build directory. Run it once before building a release, then commit both files and tag the release commit (for example, v2.4.015). Run make version and make as separate commands so that a parallel build cannot race the version update. Configuration and ordinary builds preserve the recorded version and timestamp.

Separate build directories are supported:

mkdir -p build/autoconf
cd build/autoconf
../../configure
make -j4

Without Pandoc, make builds only the executable; make man and make install require Pandoc. make clean removes build products, and make distclean also removes the generated makefile and configuration results.

OPTIONS

-db [db file]

Specifies the filename of the SQLite database to open. If you do not specify this option, it assumes a database file named ‘.pfm’ in the current directory.

--headless

Explicitly tells PFM that it is running in a headless (server) environment. Without this, PFM will try to work it out for itself. PFM uses this to determine if it should get the database key from secure storage (macOS keychain, GNU Key Manager or Windows Credential Manager) or from the user entering a password.

-port, -p [port number]

Specifies the port to listen on when starting the API server. If not specified, PFM will attempt to read from the DB config table. The user can set up the config item with the add-config command, PFM expects the config for the port to have the key 'server.port'.

--start-server

Automatically starts the server listening on the specified port when the program starts.

--license, -l

Prints the license information of the PFM program and exits.

--version, -v

Prints the version information of the PFM program and exits.

-h, -?

Prints the supported command line options and exits.

NOTES

PFM uses an encrypted SQLite database file using the SQLCipher library. When a new database file is created, the user is prompted for a password to encrypt the database with, it is important to make this password both memorable (so you don’t forget it) and secure (so it cannot be easily guessed). The User will also be prompted for an access password, whose key is stored as a config item (see commands add-config-item, list-config-items below). For certain commands, the user is prompted for this access password to make sure you really want to run the command.

The following config items (see the add-config-item command below) are created when a new database is created:

Item Notes
cycle.end = last-working-day The day each cycle ends. Possible values are: last-working-day, last-day, last-friday, any valid day of the month, e.g. 25
limits.row = 50 Limit the number of rows retrieved
money.local = “” Locale for the currency symbol in money fields (leave blank for the default system locale)
audit.write = no Whether to record DB writes into the audit interaction table. Any INSERT, UPDATE or DELETE statement will be recorded in the audit interaction table.

PFM supports shortcuts to commands that you run frequently. Shortcuts are activated by following with the backslash character '' which will replace the shortcut with the command you have specified.

PFM also supports import and export of entities via the import/export comands, these all accept/output files in JSON format, other than the export-transasctions-csv command which will output a CSV file, useful; for analysis in a spreadsheet program for example.

JSON import files must be in the format:

	{
		"className": "DBAccount",
		"accounts": [
			{
				"code": "BANK",
				"name": "Current account",
				"openingBalance": "2312.56",
				"openingData", "2025-06-15"
			}
		]
	}

The PFM command save-json-template will save an example json file for the entity you choose, making it easy to edit this in your favourite text editor.

[!TIP] Google Sheets has extensions available to allow export of spreadsheet data into JSON format

COMMANDS

PFM uses a command line interface, the user enters commands into the ‘pfm>’ prompt. Commands are listed below with the full name followed by accepted short forms in brackets.

Some commands take parameters, these take the form of:

parameter_name:parameter_value

Some commands, particularly those that update or delete an entity take a parameter to identify the particular entity, that is typically shown when the entities are listed. Sometimes this identifier is a code (as is the case with category or payee), and sometimes it is a sequence number (as is the case with transaction or recurring charge). This parameter is shown in square brackets after the command name. These parameters do not take the form above, they are simply the command followed by the code/sequence. If the parameter is a code, it is case sensitive.

Date fields accept the formats yyyy-mm-dd , dd-mm-yyyy, yyyy-Mmm-dd or dd-Mmm-yyyy only. Text fields should be delimited with "" if they contain spaces, e.g.

desc:"The quick brown fox jumped over the lazy dog"
Command Description
add-account (aa) Add a new account to the system. The user is prompted to enter the account details such as the account name and opening balance.
list-accounts (la) List all accounts, displaying current balance, reconciled balance and balance after bills.
update-account (ua) [account code] Update the account details with the given account code.
delete-account (da) [account code] Delete the account with the given account code. This will also delete all transactions and recurring charges associated with the account.
list-audit-interaction (lai) [parameters] List audit interaction records.- date>:[date after] - The records after this date are listed - date<:[date before] - The records before this date are listed
show-audit-interacton (sai) [audit interaction sequence number] Shows the details of the audit interaction record with the given sequence number.
delete-audit-interaction (dai) [parameters] Delete audit interaction records. If no parameters are supplied, the command deletes records before 3 months ago. Parameters: date<:[date before] - delete the records before this date.
add-config-item (acfg) Add a new config item. The user is prompted to enter the config item details.
list-config-items (lcfg) List all config items with their values.
update-config-item (ucfg) [config item code] Update the config item with the given config item code.
delete-config-item (dcfg) [config item code] Delete the config item with the given code.
add-category (ac) Add a new category to the system. The user is prompted to enter the category details.
list-categories (lc) List all categories with their codes and descriptions.
update-category (uc) [category code] Update the category details with the given category code.
delete-category (dc) [category code] Delete the category with the given category code.
add-payee (ap) Add a new payee to the system. The user is prompted to enter the payee details.
list-payees (lp) List all payees with their codes and names.
update-payee (up) [payee code] Update the payee details with the given payee code.
delete-payee (dp) [payee code] Delete the payee with the given payee code.
add-recurring-charge (arc) (See extended form below) Add a new recurring charge to the currently selected account. The user is prompted to enter the charge details if no parameters are supplied.
list-recurring-charges (lrc) List all recurring charges for the currently selected account, displaying their details and sequence numbers.
update-recurring-charge (urc) [recurring charge sequence number] Update the recurring charge details with the given sequence number.
delete-recurring-charge (drc) [recurring charge sequence number] Delete the recurring charge with the given sequence number.
add-transaction (at, add) (See extended form below) Add a new transaction to the currently selected account. The user is prompted to enter the transaction details if no parameters are supplied.
copy-transaction (ct, copy) [transaction sequence number] Copy the transaction with the given sequence number. If no sequence number is supplied, copy the last non-recurring transaction created.
show-transaction (show, st) [transaction sequence number] Show the details of the transaction with the given sequence number.
list-transactions (list, lt) (See extended forms below) List transactions for the currently selected account, displaying their details and sequence numbers. By default, show up to 25 non-recurring transactions in descending date order.
update-transaction (ut) [transaction sequence number] Update the transaction details with the given sequence number.
delete-transaction (dt) [transaction sequence number] Delete the transaction with the given sequence number.
transfer-transaction (transfer, tr) (See extended form below) Transfer money from the currently selected account to another account, creating a transaction in each account. The user is prompted to enter the transfer details if no parameters are supplied.
list-transfer-records (ltr) List all transfer records, displaying their details and sequence numbers.
delete-transfer-record (dtr) [transfer record sequence number] Delete the transfer record with the given sequence number. This will also delete both transactions associated with the transfer.
add-report (arp) Add a new transaction report to the system. The user is prompted to enter the report details and transaction selection criteria.
list-reports (show-reports, lrp) List all saved transaction reports with their details and sequence numbers.
update-report (urp) [report sequence number] Update the transaction report details and transaction selection criteria with the given sequence number.
delete-report (drp) [report sequence number] Delete the saved transaction report with the given sequence number.
run-report (run) [report sequence number] Run the specified transaction report and display the results. Running a report is equivalent to running the find-transaction (find) command specifying the sql parameter.
reconciliation-report (rr) (See extended form below) Run the reconciliation report against the specified bank CSV file
add-shortcut (ash) Add a new shortcut to the system, the user is prompted to add the shortcut details.
list-shortcuts (lsh) List all the shortcuts stored in the system including the sequence number.
update-shortcut (ush) [shortcut sequence number] Update the given shortcut, the user is prompted to enter the details.
delete-shortcut (dsh) [shortcut sequence number] Delete the given shortcut from the system.
import-categories (ic) [JSON file path] Import categories from the supplied JSON file that complies to the template above.
export-categories (xc) [JSON file path] Export all categories to the supplied JSON file.
import-payees (ip) [JSON file path] Import payees from the supplied JSON file that complies to the template above.
export-payees (xp) [JSON file path] Export all payees to the supplied JSON file.
import-recurring-charges (irc) [JSON file path] Import recurring charges from the supplied JSON file that complies to the template above.
export-recurring-charges (xrc) [JSON file path] Export all recurring charges to the supplied JSON file.
import-transactions (it) [JSON file path] Import transactions from the supplied JSON file that complies to the template above.
export-transactions (xt) [JSON file path] Export all transactions to the supplied JSON file.
export-transactions-csv (xtc) [CSV file path] Export all transactions to the supplied CSV file.
list-outstanding-charges (loc) Lists the oustanding charges this period for the currently selected account.
list-paid-charges (llc) Lists the paid charges this period for the currently selected account.
use [account-code] Set the current account context to the account specified with account-code. The list-accounts command will show which account is the primary account, the initial state will set this account as the current account context until it is changed with the use command.
save-json-template (sjt) Presents a menu to choose which entity to create a json template for, choose from account, payee, category, recurring charge, transaction. A file with the name _template.json is created in the current directory.
set-primary-account (spa) [account code] Sets the primary account, like the immortals in Highlander, there can be only one. On pfm startup, the primary account is selected so you don’t need to issue a use command.
clear-categories Deletes all stored categories, used for example if you don’t want any of the default categories created with a new file.
reconcile-transaction (reconcile, rt) [sequence number] Toggle the reconciled status of the transaction specified by sequence.
change-password Change the database password.
version Print the pfm version string.
help Display some usage information.
exit (quit, q) Quit the application.

EXTENDED FORM

add-recurring-charge (arc) [parameters]

  • c:[category code] - The category code of the charge
  • p:[payee code] - The payee code of the charge
  • start:[date] - The start date for the charge (defaults to today)
  • end:[date] - The end date for the charge (defaults to N/A)
  • desc:[description] - The description
  • freq:[frequency code] - The frequency of the charge - n[y|m|w|d], e.g. '1m' for monthly
  • amnt:[amount] - The amount
  • to:[account code] - The account code to transfer to, e.g. recurring transfer

list-transactions (lt, list) [parameters]

  • num - number of results to be returned
  • all - return non-recurring and recurring transactions
  • nr - return only non-recurring transactions (the default)
  • rc - return only recurring transactions
  • period - return transactions in the current period
  • any - return transations from any timeframe
  • asc - sort the results in ascending date order
  • desc - sort the results in descending date order (the default)

An example list command could be:

list 50 all desc

find-transactions (find) [parameters]

Parameters are listed below, any parameters that accept wildcards recognise * as any string, ? as any character, e.g. desc:travel*.

  • date:[date] - transactions on the specified date(s)
  • date>:[date] - transactions after this date
  • date<:[date] - transactions before this date
  • desc:[description] - transactions with this description, wildcards are accepted
  • acc:[account code] - transactions with this account code
  • c:[category code] - transactions with this category code
  • p:[payee code] - transactions with this payee code
  • ref:[reference] - transactions with this reference, wildcards are accepted
  • rec:[r/n] - transactions that are [r]ecurring or [n]on-recurring
  • type:[DB/CR] - transactions with type either debit or credit
  • amnt>:[amount] - transactions where the amount is greater than this
  • amnt<:[amount] - transactions where the amount is less than this
  • sql:[where clause parameters] - find transactions specified by the criteria. When you run a report, it will run this command with the report’s SQL criteria.

This option will likely be useful only to those familiar with SQL (Structured Query Language). The find command queries a view with the following column names:

  • account - the account code of the transaction
  • recurring - whether the transaction is a recurring charge ('Y' or 'N')
  • date - the date the transaction was posted for
  • reference - the transaction reference
  • description
  • payee - the transaction payee code
  • category - the transaction category code
  • type - whether this transacion is a CRedit or a DeBit ('CR' or 'DB')
  • amount
  • reconciled - whether the transaction has been reconciled ('Y' or 'N')

An example:

find sql:"category = 'BOOKS' AND amount > 25 AND recurring = 'N'"

The query used in the find command can be saved as a report by issuing the save-report or save command.

transfer-transaction (transfer, tr) [parameters]

  • to:[account code] - The code of the account to transfer to
  • c:[category code] - The category code of the transaction
  • date:[date] - The date for the transaction (defaults to today)
  • desc:[description] - The description
  • amnt:[amount] - The amount
  • rec:[Y/N] - Is the transaction reconciled or not

reconciliation-report (rr) [parameters]

  • acc:[account code] - The code of the account to run the report against
  • csv:[csv file] - The CSV to reconcile against, typically from a bank export
  • map:[mapping file] - The json mapping file for the CSV fields

sql-mode

Presents the user with a new ‘sql>’ prompt where they can enter standard SQLite SQL to query (and INSERT, UPDATE & DELETE) records in the database. The user is prompted for their access password to enter this mode. Do not use unless you are familiar with SQL and understand the consequences of your actions.

To leave sql mode, enter the command ‘.quit’.

To familiarise yourself with the database entities, I suggest you look at the PFM source code at: https://github.com/guywilson/pfm

About

Command line Personal Finance Manager

Topics

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages