Skip to main content

actualq

Read an Actual Budget export from the command line.

No server. No credentials. No dependencies. One file of standard-library Python.

$ actualq accounts
account       on budget  closed   balance  transactions  first       last
------------  ---------  ------  --------  ------------  ----------  ----------
Checking      yes                 4,182.03          593  2023-10-18  2026-08-18
Credit Card   yes                  -514.60          610  2023-10-24  2026-08-18
Savings       yes                12,000.00          184  2025-07-28  2026-07-31

$ actualq txns --since 2026-08 --category Grocery --json
[
  {
    "date": "2026-08-14",
    "account": "Checking",
    "payee": "Costco",
    "category": "Everyday / Grocery",
    "amount": -142.87,
    "amount_cents": -14287,
    ...
  }
]

Why

Every other way to get at Actual data programmatically — the official @actual-app/cli, actualpy, the community CLIs — needs a running actual-server and its password. That is a lot of setup to answer "what did I spend on groceries in July".

You already have the answer on disk. Actual's export (Settings → Export data) is a zip holding an ordinary SQLite database. actualq reads it.

That makes it a good fit for LLM agents in particular: one binary-free command, JSON out, nothing to authenticate, and no way to damage the budget.

Install

uv tool install actualq     # or: pipx install actualq

Or run it once without installing anything:

uvx actualq accounts

Or take the file. It has no dependencies and needs only Python 3.11+, so there is nothing to install if you would rather not:

curl -O https://raw.githubusercontent.com/madhurdeepjain/actualq/main/actualq.py
python3 actualq.py accounts

Use

With no -f, it reads the newest .zip in the current directory, so the usual session is cd to wherever you export and start asking.

actualq accounts                                  # balances, ranges, row counts
actualq txns --since 2026-01 --account Checking   # transactions
actualq categories --since 2026-07 --until 2026-07
actualq payees --limit 20
actualq sql "select ..."                          # anything else
actualq schema                                    # the field guide

txns filters: --since --until --account --category --payee --search --limit --uncategorized --no-transfers --splits.

Dates take a year, a month or a day — --since 2026, --since 2026-08, --since 2026-08-22 — and --until means the last day of whatever you name.

Output is an aligned table by default, --json for an array, --csv for CSV.

What it will not do

It does not write. There is no import, no edit, no sync. The export is copied to a temp directory and opened read-only, so nothing here can reach the budget you actually use, and actualq sql "delete from ..." fails rather than working.

It does not compute budget-vs-actual. The rollover arithmetic behind Actual's budget screen is genuinely involved, and a number that is nearly right is worse than no number in a tool you would use to check yourself. The raw zero_budgets / reflect_budgets tables are there for actualq sql.

The part worth reading: actualq schema

Actual's schema has four traps, and every one of them fails quietly — you get plausible numbers that are wrong. This is most of why this tool exists.

1. Read v_transactions, never transactions. Payees and categories are indirected through mapping tables (payee_mapping.targetId, category_mapping.transferId). transactions.description holds a payee id that may have been merged away, so joining payees directly returns NULL for every payee you ever renamed or merged — and those rows read as having no payee at all. Categories do the same and read as uncategorised.

2. Splits are counted twice if you let them. A split is a parent row carrying the full amount plus children carrying the pieces. Both are real rows. Actual computes balances over is_parent = 0. On a real file:

--splits leaves     5724 rows   matches the account balances   <- the default
--splits parents    5718 rows   matches them too, one row per bank transaction
--splits all        5728 rows   over by the whole value of every split

3. Dates and amounts are integers. date is 20260822, an INTEGER, not a string. amount is cents, negative for money out. actualq gives you both amount (readable) and amount_cents (exact) so nothing has to round twice.

4. Deleted rows are still in the file. Nothing is deleted, it gets tombstone = 1, because Actual syncs by CRDT and has to remember the deletion. Query accounts, categories or payees yourself without WHERE tombstone = 0 and you report on things the user threw away.

actualq schema prints all of this, plus the tables worth knowing about, so an agent can read it before writing SQL.

Tests

python3 -m unittest discover

schema.sql is Actual's own schema, structure only, no data. The tests build a synthetic budget from it containing one of each thing that is easy to get wrong, and pin the behaviour above.

Compatibility

Written against Actual's schema as of 2026. The views it depends on (v_transactions, v_payees) are what the app itself reads, so they are the most stable surface available — but this is not a documented API, and a future migration could change it.

License

MIT

Metadata

Release files for actualq 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for actualq 0.1.1
File Size Uploaded Provenance
actualq-0.1.1.tar.gz 16.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for actualq 0.1.1
File Interpreter ABI Platform
actualq-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 27.7 kB

Release files / actualq-0.1.1.tar.gz

Download URL actualq-0.1.1.tar.gz
Size 16.1 kB
Tags Source
SHA-256 checksum
How to use checksums
aff39c4e115dabe9b82b7fd12bc2337ad4930e00cb12029e719852a50f0ca7f1
BLAKE2b-256 checksum
How to use checksums
e73c718ec371275bf5d316214b00acb336fea343a1a15abe8f185c9c109d7a03
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.

Transparency log

Release files / actualq-0.1.1-py3-none-any.whl

Download URL actualq-0.1.1-py3-none-any.whl
Size 11.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c5aaf9132dc81a747ee784e495c694410f46f79a415cd3edac8513cf7eb2c560
BLAKE2b-256 checksum
How to use checksums
8b7a30cecd912f887ccafe7a9198c71e65670d9a2aa3314fc12d3c94ef1df1d2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.

Transparency log

Security for actualq 0.1.1

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for actualq-0.1.1.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Aug 25, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page