Agent-first YNAB tooling: a CLI and MCP server backed by a local SQLite mirror.
Why a mirror? YNAB rate-limits at 200 requests/hour. Agents are chatty. So API access
happens once via cheap delta sync (last_knowledge_of_server), and every analytical
query runs locally against SQLite — fast, free, offline.
- Node >= 22.13 (uses the built-in
node:sqlite— zero native dependencies) - A YNAB Personal Access Token: https://app.ynab.com/settings/developer
npm install
npm run build
export YNAB_TOKEN=<your token>
node dist/cli/index.js budgets # find your budget id (or use "last-used")
node dist/cli/index.js config set budgetId <id>
# expense floor is a dated schedule: each month's actuals are compared
# against the floor in effect at that time
node dist/cli/index.js config set-floor 2025-12 10000
node dist/cli/index.js config set-floor 2026-01 12500 # e.g. after moving
node dist/cli/index.js sync # first sync is full; subsequent are deltasOptionally npm link to get ynab-agent and ynab-agent-mcp on your PATH.
ynab-agent sync # delta-sync into SQLite mirror
ynab-agent accounts # balances
ynab-agent tx list --since 2026-01 --category Dining --json
ynab-agent tx list --payee Legoland --min 50
ynab-agent spend --months 6 # monthly outflow/inflow/net
ynab-agent spend --by category --months 3
ynab-agent observe # drift report to stdout
ynab-agent observe --sync --write observed.md # refresh + write for skill ingestion
ynab-agent observe --sync --gist # publish to secret gist (needs GITHUB_TOKEN; creates + remembers gist id)
# institutional memory: explain anomalies so reports self-explain
ynab-agent note add "May spike = whole-summer camp prepay" --category "Happy Hall" --month 2026-05
ynab-agent note list
# exclude business/property cashflows from the household floor comparison;
# they get their own netted P&L section in observe instead
ynab-agent config set floorExcludeGroups '["Investment Property"]'
ynab-agent config set offsets '{"Investment Property": ["Winnemac"]}'--json on any command gives agent-friendly output. Amounts are YNAB milliunits
unless suffixed _usd.
Stdio transport. Register in your MCP client:
{
"mcpServers": {
"ynab": {
"command": "node",
"args": ["/path/to/ynab-agent/dist/mcp/server.js"],
"env": { "YNAB_TOKEN": "..." }
}
}
}Tools: ynab_sync, ynab_list_transactions, ynab_spend_summary,
ynab_list_accounts, ynab_observe, and ynab_cli — a generic passthrough that
runs any CLI command and returns stdout, so agents get the full CLI surface
(notes, config, gist publishing, future commands) without MCP schema changes.
ynab-agent observe renders observed.md: trailing-3-month actual outflow vs your
modeled expense floor, category drift, and large-transaction flags. The intent is a
split-brain skill design: static facts live in your LLM skill file; daily-changing
reality lives in observed.md, regenerated on a schedule. See
docs/skill-integration.md.
src/core/ API client (backoff + jitter), SQLite schema, delta sync, queries
src/cli/ commander CLI
src/mcp/ MCP stdio server over the same core
src/observe/ observed.md generator
src/events/ (stub) transaction→life-event clustering + photos enrichment
- Split transactions are resolved to their subtransaction categories via the
effective_txview, so category math is correct. - Spend queries exclude transfers and off-budget (tracking) accounts.
- The SQLite mirror lives at
~/.local/share/ynab-agent/ynab.dbby default. node:sqliteprints an ExperimentalWarning on Node 22; harmless. UseNODE_NO_WARNINGS=1to silence.