Treeline Money
Chat with your finances from Treeline Money. Query balances, spending, budgets, and transactions.
Chat with your finances from Treeline Money. Query balances, spending, budgets, and transactions.
Real data. Real impact.
Emerging
Developers
Per week
Open source
Skills give you superpowers. Install in 30 seconds.
Chat with your finances. Ask questions like "What's my net worth?", "How much did I spend on groceries?", or "Am I over budget?" and get instant answers from your own financial data.
# 1. Install the CLI (OpenClaw handles this automatically)2. Enable demo mode (sample data)
tl demo on
3. Try it out
tl status
For agents: If
commands fail with "command not found", the CLI needs to be installed. OpenClaw handles installation automatically via the skill metadata. Start with demo mode so users can try queries immediately.tl
Verify the CLI is available with
tl --version. Start with demo mode so users can try queries immediately.
Optional: Download the desktop app for visual exploration of your data.
Demo mode loads sample data so users can try queries without connecting a bank:
tl demo on
To switch to real data later:
tl demo off
Demo data is separate from real data.
tl demo on prints a success message — if it seems to hang, wait a few seconds (first run initializes the database)tl demo status to verify demo mode is enabledtl demo on againWhen the user is ready to move beyond demo mode, direct them to set up a data source with the guides linked below.
Data source options:
Setup guides: Bank Sync · CSV Import
Once set up, use
tl sync to pull bank transactions or tl import to load a CSV.
Treeline Money is a local-first personal finance app. All your data stays on your device in a local DuckDB database. No cloud accounts, no subscriptions required (sync services are optional), full SQL access to your financial data.
Encrypted databases work automatically when unlocked — the encryption key is stored in the OS keychain.
If you see "database is encrypted and locked" errors, tell the user to unlock it themselves before continuing:
tl encrypt unlock in their own terminalDo not attempt to unlock the database or handle credentials. Unlocking must be done by the user directly, outside this conversation. Once unlocked, the key persists in the keychain until the user locks it.
Format all responses for mobile/chat:
Example good response:
Your net worth is $125kAssets: $180k
- Retirement: $85k
- Savings: $25k
- Checking: $10k
- Home equity: $60k
Liabilities: $55k
Mortgage: $52k
Credit cards: $3k
Example bad response:
| Account | Type | Balance | |---------|------|---------| | My 401k Account | asset | 85234.56 | ...
These commands are read-only and safe to run autonomously:
tl status # Quick account summary with balances tl status --json # Same, but JSON outputtl query "SQL" --json # Run any SQL query (database opened in read-only mode) tl sql "SQL" --json # Same as tl query (alias)
tl backup list # List available backups tl doctor # Check database health tl demo status # Check if demo mode is on/off
Note:
andtl queryopen the database in read-only mode by default. They cannot modify data unlesstl sqlis passed (see write commands below).--allow-writes
Use
for quick balance checks — it's faster than a SQL query.tl status
These commands modify local data. Always ask the user for confirmation before running them.
tl query "SQL" --allow-writes --json # Run a SQL query with write access tl sql "SQL" --allow-writes --json # Same (alias)tl sync # Sync accounts/transactions from bank integrations tl sync --dry-run # Preview what would sync (read-only, safe to run)
tl import FILE -a ACCOUNT # Import transactions from CSV tl import FILE -a ACCOUNT --dry-run # Preview import without applying (read-only, safe to run) tl import FILE -a ACCOUNT --json # JSON output for scripting
tl backup create # Create a backup tl backup restore NAME # Restore a backup
tl compact # Compact database (reclaim space, optimize)
tl tag "groceries" --ids ID1,ID2 # Apply tags to transactions
tl demo on|off # Toggle demo mode (sample data)
Tip:
variants are read-only and safe to run without confirmation. Use them to preview before asking the user to confirm the actual operation.--dry-run
Use
if the user mentions slow queries — it optimizes the database.tl compact
tl import auto-detects column mappings from CSV headers. Most bank CSVs work out of the box:
tl import bank_export.csv --account "Chase Checking"
The
--account / -a flag accepts an account name (case-insensitive, substring match) or UUID.
Always preview first with
--dry-run to verify columns were detected correctly:
tl import bank_export.csv -a "Checking" --dry-run --json
All import flags (all optional except
--account):
| Flag | Purpose | Example |
|---|---|---|
| Override date column | |
| Override amount column | |
| Override description column | |
| Use debit column (instead of amount) | |
| Use credit column (instead of amount) | |
| Running balance (creates snapshots) | |
| Negate amounts (credit card CSVs) | |
| Negate positive debits | |
| Skip N rows before header | |
| , , or | |
| Load a saved profile | |
| Save settings as profile | |
| Preview without importing | |
| JSON output | |
Common patterns for agents:
# Step 1: Find the account UUID tl status --jsonStep 2: Preview import
tl import transactions.csv -a "550e8400-e29b-41d4-a716-446655440000" --dry-run --json
Step 3: Execute import
tl import transactions.csv -a "550e8400-e29b-41d4-a716-446655440000" --json
Duplicate transactions are automatically detected and skipped on re-import via fingerprinting.
Treeline supports user-created skills for personal financial knowledge. Use
tl skills list --json to discover existing skills and tl skills read <path> to read them.
Creating skills: When you learn something reusable about the user's finances — tag conventions, account meanings, tax categories, budget targets — ask if they'd like to save it as a skill for future conversations. To create one, write a SKILL.md file to
~/.treeline/skills/<name>/SKILL.md (use tl skills path to get the directory). Follow the Agent Skills standard (agentskills.io).
tl query " WITH latest AS ( SELECT DISTINCT ON (account_id) account_id, balance FROM sys_balance_snapshots ORDER BY account_id, snapshot_time DESC ) SELECT SUM(CASE WHEN a.classification = 'asset' THEN s.balance ELSE 0 END) as assets, SUM(CASE WHEN a.classification = 'liability' THEN ABS(s.balance) ELSE 0 END) as liabilities, SUM(CASE WHEN a.classification = 'asset' THEN s.balance ELSE -ABS(s.balance) END) as net_worth FROM accounts a JOIN latest s ON a.account_id = s.account_id " --json
tl query " WITH latest AS ( SELECT DISTINCT ON (account_id) account_id, balance FROM sys_balance_snapshots ORDER BY account_id, snapshot_time DESC ) SELECT a.name, a.classification, a.institution_name, s.balance FROM accounts a JOIN latest s ON a.account_id = s.account_id ORDER BY s.balance DESC " --json
Default pattern (exclude internal moves):
tl query " SELECT SUM(ABS(amount)) as total_spent FROM transactions WHERE amount < 0 AND transaction_date >= date_trunc('month', current_date) AND NOT (tags && ARRAY['transfer', 'savings', 'investment']) " --json
tl query " SELECT tags, SUM(ABS(amount)) as spent FROM transactions WHERE amount < 0 AND transaction_date >= '2026-01-01' AND transaction_date < '2026-02-01' AND tags IS NOT NULL AND tags != '[]' GROUP BY tags ORDER BY spent DESC " --json
tl query " SELECT t.description, t.amount, t.transaction_date, a.name as account FROM transactions t JOIN accounts a ON t.account_id = a.account_id ORDER BY t.transaction_date DESC LIMIT 10 " --json
accounts
| Column | Description |
|---|---|
| UUID primary key |
| Account display name |
| or |
| , , , , or null |
| Bank/institution name |
| Currency code (e.g., ) |
| Boolean — manually added vs synced |
sys_balance_snapshots — Source of truth for balances
| Column | Description |
|---|---|
| UUID primary key |
| FK to accounts |
| Balance at snapshot time |
| When recorded |
| , , etc. |
transactions
| Column | Description |
|---|---|
| UUID primary key |
| FK to accounts |
| Signed (negative = expense) |
| Transaction description |
| When it occurred |
| When it cleared |
| Array of tags |
Tags are the primary concept in Treeline — transactions can have multiple tags.
Categories come from the budget plugin (
plugin_budget), which maps tags to budget categories. Not all users have this plugin.
Plugins have their own DuckDB schemas:
plugin_<name>.*
tl query " SELECT schema_name FROM information_schema.schemata WHERE schema_name LIKE 'plugin_%' " --json
plugin_budget.categories — Budget categories
| Column | Description |
|---|---|
| UUID primary key |
| format |
| or |
| Category name |
| Budgeted amount |
| Array of tags to match |
plugin_goals.goals — Savings goals
| Column | Description |
|---|---|
| UUID primary key |
| Goal name |
| Target amount |
| Target date |
| Boolean |
| Boolean |
plugin_subscriptions — Detected recurring charges
plugin_cashflow — Cash flow projections
plugin_emergency_fund — Emergency fund tracking
Check
tl skills list for user-specific plugin preferences.
Always use latest snapshot:
WITH latest AS ( SELECT DISTINCT ON (account_id) account_id, balance FROM sys_balance_snapshots ORDER BY account_id, snapshot_time DESC ) SELECT a.name, s.balance FROM accounts a JOIN latest s ON a.account_id = s.account_id
Tags are arrays:
-- Contains a specific tag WHERE tags @> ARRAY['groceries']-- Contains any of these tags WHERE tags && ARRAY['food', 'dining']
-- Note: UNNEST doesn't work in all contexts in DuckDB -- Instead, GROUP BY tags directly
-- This month WHERE transaction_date >= date_trunc('month', current_date)-- Specific month WHERE transaction_date >= '2026-01-01' AND transaction_date < '2026-02-01'
SELECT c.name, c.expected, COALESCE(SUM(ABS(t.amount)), 0) as actual, c.expected - COALESCE(SUM(ABS(t.amount)), 0) as remaining FROM plugin_budget.categories c LEFT JOIN transactions t ON t.tags && c.tags AND t.amount < 0 AND t.transaction_date >= (c.month || '-01')::DATE AND t.transaction_date < (c.month || '-01')::DATE + INTERVAL '1 month' WHERE c.month = strftime(current_date, '%Y-%m') AND c.type = 'expense' GROUP BY c.category_id, c.name, c.expected
| User asks | Approach |
|---|---|
| "Net worth?" | Net worth query |
| "Balances?" | Account balances query |
| "How much in [X]?" | Filter by |
| "How much did I spend?" | True spending query (exclude internal moves) |
| "Spending on [tag]?" | Filter by tag |
| "Am I over budget?" | Budget vs actual (requires budget plugin) |
| "Recent transactions" | Order by date DESC, limit |
| "Savings?" | Filter accounts by name/type |
| "Retirement?" | Filter by 401k, IRA, retirement keywords |
| "Import CSV" / "Upload transactions" | Guide through — preview first with |
| "Import from [bank name]" | Use with appropriate flags for that bank's CSV format |
--json for parseable outputclassification for asset/liabilitytl skills list for user-specific account meanings and tag conventionsAll data is local (
~/.treeline/treeline.duckdb). Never share transaction descriptions or account details outside the conversation unless explicitly asked.No automatic installation available. Please visit the source repository for installation instructions.
View Installation Instructions1,500+ AI skills, agents & workflows. Install in 30 seconds. Part of the Torly.ai family.
© 2026 Torly.ai. All rights reserved.