Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
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.
Quick Start
# 1. Install the CLI (OpenClaw handles this automatically)# 2. Enable demo mode (sample data)
tl demo on
tl status
# 3. Try it out
First Time Setup
For agents: If tl 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.
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
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.
CLI Behavior Notes
tl demo on prints a success message — if it seems to hang, wait a few seconds (first run initializes the database)
Use tl demo status to verify demo mode is enabled
Some commands may take a few seconds on first run due to database initialization
If you see errors about missing tables, try tl demo on again
Connecting Real Data
When the user is ready to move beyond demo mode, direct them to set up a data source with the guides linked below.
Once set up, use tl sync to pull bank transactions or tl import to load a CSV.
What is Treeline?
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
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:
Open the Treeline desktop app and unlock from there, or
Run tl encrypt unlock in their own terminal
Do 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.
Response Formatting
Format all responses for mobile/chat:
Use bullet points, not markdown tables
Round numbers for readability ($1,234 not $1,234.56)
Lead with the answer, details second
Keep responses concise — chat isn't a spreadsheet
Use line breaks to separate sections
Example good response:
Your net worth is $125k
Assets: $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 |
...
CLI Commands
Read commands (run freely)
These commands are read-only and safe to run autonomously:
tl status # Quick account summary with balances
tl status --json # Same, but JSON output
tl 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:tl query and tl sql open the database in read-only mode by default. They cannot modify data unless --allow-writes is passed (see write commands below).
Use tl status for quick balance checks — it's faster than a SQL query.
Write commands (ask the user first)
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:--dry-run variants are read-only and safe to run without confirmation. Use them to preview before asking the user to confirm the actual operation.
Use tl compact if the user mentions slow queries — it optimizes the database.
CSV Import Details
tl import auto-detects column mappings from CSV headers. Most bank CSVs work out of the box:
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
--date-column
Override date column
--date-column "Post Date"
--amount-column
Override amount column
--amount-column "Amt"
--description-column
Override description column
--description-column "Memo"
--debit-column
Use debit column (instead of amount)
--debit-column "Debit"
--credit-column
Use credit column (instead of amount)
--credit-column "Credit"
--balance-column
Running balance (creates snapshots)
--balance-column "Balance"
--flip-signs
Negate amounts (credit card CSVs)
--flip-signs
--debit-negative
Negate positive debits
--debit-negative
--skip-rows N
Skip N rows before header
--skip-rows 3
--number-format
us, eu, or eu_space
--number-format eu
--profile NAME
Load a saved profile
--profile chase
--save-profile NAME
Save settings as profile
--save-profile chase
--dry-run
Preview without importing
--dry-run
--json
JSON output
--json
Common patterns for agents:
# Step 1: Find the account UUID
tl status --json
# Step 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.
User Skills
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).
Quick Reference
Net Worth
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
Account Balances
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
True Spending (Excluding Internal Moves)
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
Spending by Tag
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
Recent Transactions
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
Database Schema
Core Tables
accounts
Column
Description
account_id
UUID primary key
name
Account display name
classification
asset or liability
account_type
credit, investment, Loan, other, or null
institution_name
Bank/institution name
currency
Currency code (e.g., USD)
is_manual
Boolean — manually added vs synced
sys_balance_snapshots — Source of truth for balances
Column
Description
snapshot_id
UUID primary key
account_id
FK to accounts
balance
Balance at snapshot time
snapshot_time
When recorded
source
sync, manual, etc.
transactions
Column
Description
transaction_id
UUID primary key
account_id
FK to accounts
amount
Signed (negative = expense)
description
Transaction description
transaction_date
When it occurred
posted_date
When it cleared
tags
Array of tags
Tags vs Categories
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.
Plugin System
Plugins have their own DuckDB schemas: plugin_<name>.*
Discovering Installed Plugins
tl query "
SELECT schema_name
FROM information_schema.schemata
WHERE schema_name LIKE 'plugin_%'
" --json
Common Plugin Schemas
plugin_budget.categories — Budget categories
Column
Description
category_id
UUID primary key
month
YYYY-MM format
type
income or expense
name
Category name
expected
Budgeted amount
tags
Array of tags to match
plugin_goals.goals — Savings goals
Column
Description
id
UUID primary key
name
Goal name
target_amount
Target amount
target_date
Target date
completed
Boolean
active
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.
Common Patterns
Getting Current Balances
Always use latest snapshot:
WITH latest AS (
SELECTDISTINCTON (account_id) account_id, balance
FROM sys_balance_snapshots
ORDERBY account_id, snapshot_time DESC
)
SELECT a.name, s.balance
FROM accounts a
JOIN latest s ON a.account_id = s.account_id
Working with Tags
Tags are arrays:
-- Contains a specific tagWHERE tags @>ARRAY['groceries']
-- Contains any of these tagsWHERE tags &&ARRAY['food', 'dining']
-- Note: UNNEST doesn't work in all contexts in DuckDB-- Instead, GROUP BY tags directly
Date Filters
-- This monthWHERE transaction_date >= date_trunc('month', current_date)
-- Specific monthWHERE transaction_date >='2026-01-01'AND transaction_date <'2026-02-01'
Budget vs Actual
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
LEFTJOIN transactions t ON t.tags && c.tags
AND t.amount <0AND t.transaction_date >= (c.month ||'-01')::DATEAND t.transaction_date < (c.month ||'-01')::DATE+INTERVAL'1 month'WHERE c.month = strftime(current_date, '%Y-%m')
AND c.type ='expense'GROUPBY c.category_id, c.name, c.expected
Question Mapping
User asks
Approach
"Net worth?"
Net worth query
"Balances?"
Account balances query
"How much in [X]?"
Filter by name ILIKE '%X%'
"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 tl import — preview first with --dry-run
"Import from [bank name]"
Use tl import with appropriate flags for that bank's CSV format
Tips
Always use --json for parseable output
Amounts are signed — negative = expense
Use classification for asset/liability
Balances live in snapshots, not the accounts table
Check tl skills list for user-specific account meanings and tag conventions
Privacy Note
All data is local (~/.treeline/treeline.duckdb). Never share transaction descriptions or account details outside the conversation unless explicitly asked.