news 2026/9/10 14:42:35

Actual Budget CLI 完全实战指南:在终端中查询与修改个人预算数据

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Actual Budget CLI 完全实战指南:在终端中查询与修改个人预算数据

Actual Budget CLI 完全实战指南:在终端中查询与修改个人预算数据

【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual

Actual Budget 是一款本地优先(local-first)的个人财务管理应用,而@actual-app/cli是它的官方命令行工具,让你不必打开网页就能在终端里查询和修改预算数据——账户、交易、分类、收款方、规则、排期交易一应俱全。本文以 packages/cli/README.md 为骨架,结合 packages/cli/src 下的源码实现,完整讲解 CLI 的安装、配置体系、全部命令、金额约定、缓存与锁机制,以及如何在 monorepo 内本地运行调试。读完本文,你将掌握用一行命令查余额、批量导入导出交易、执行 ActualQL 查询、自动化设置预算等实战技能。

一、认识 @actual-app/cli:定位与安装

CLI 的定位在 packages/cli/README.md 开头就已明确:它是 Actual Budget 的命令行接口,用于在终端中查询和修改预算数据。有一个关键前提必须理解:

该 CLI 连接的是正在运行的 Actual 同步服务器(sync server),它不会直接操作本地预算文件。

也就是说,CLI 是同步服务器的一个客户端:预算数据存储在服务器端,CLI 通过@actual-app/api与之通信,并会在本地保留一份缓存副本用于加速重复读取(详见后文"缓存机制"章节)。这一设计从 packages/cli/src/connection.ts 的withConnection实现中可以得到印证——每次命令执行都会先api.init建立连接,再按需下载/加载/同步预算。

安装与运行环境

npm install -g @actual-app/cli

安装要求Node.js >= 22,这一点同时写在 README 与 packages/cli/package.json 的engines字段中。安装后,npm 会注册两个可执行命令(见 packages/cli/package.json):

  • actual
  • actual-cliactual的别名)

两者都指向构建产物./dist/cli.js。CLI 基于commander构建(packages/cli/src/index.ts),因此每个命令都支持标准的--help帮助输出。

二、快速开始:三个命令上手

安装完成后,先通过环境变量配置连接信息,然后就能立即开始使用:

# 设置连接信息 export ACTUAL_SERVER_URL=http://localhost:5006 export ACTUAL_PASSWORD=your-password export ACTUAL_SYNC_ID=your-sync-id # 在 设置 → 高级 → Sync ID 中找到 # 列出你的账户 actual accounts list # 查看某个账户余额 actual accounts balance <account-id> # 查看某月预算 actual budgets month 2026-03

三个环境变量各自的职责:

变量用途
ACTUAL_SERVER_URLActual 同步服务器的 URL(必填)
ACTUAL_PASSWORD服务器密码(未使用 token 时必填)
ACTUAL_SYNC_ID预算的 Sync ID(大多数命令需要)

其中 Sync ID 需要在 Actual 网页端「设置 → 高级 → Sync ID」页面获取,它用于把 CLI 指向服务器上对应的那一个预算文件。

三、配置体系:从全局 Flag 到配置文件

3.1 配置解析优先级

CLI 按以下顺序解析配置,优先级从高到低

  1. CLI flags--server-url--password等)
  2. 环境变量
  3. 配置文件(通过 cosmiconfig 查找)
  4. 默认值dataDir默认是~/.actual-cli/data

这套优先级逻辑在 packages/cli/src/config.ts 的resolveConfig中逐字段实现,例如serverUrl的取值顺序是cliOpts.serverUrl ?? process.env.ACTUAL_SERVER_URL ?? fileConfig.serverUrl ?? ''dataDir的兜底默认值是join(homedir(), '.actual-cli', 'data')。最终解析出的配置结构CliConfig包含serverUrlpasswordsessionTokensyncIddataDirencryptionPasswordcacheTtllockTimeoutrefreshnoLock等字段。

需要特别指出的是,resolveConfig中有两道硬性校验(packages/cli/src/config.ts):

  • 未配置serverUrl直接报错:"Server URL is required..."
  • 未同时配置passwordsessionToken直接报错:"Authentication required..."

所以密码和会话令牌(session token)至少二选一,二者都没有时命令无法运行。

3.2 环境变量全表

变量说明
ACTUAL_SERVER_URLActual 同步服务器的 URL(必填)
ACTUAL_PASSWORD服务器密码(未使用 token 时必填)
ACTUAL_SESSION_TOKEN会话令牌(密码的替代方案)
ACTUAL_SYNC_ID预算 Sync ID(大多数命令需要)
ACTUAL_DATA_DIR缓存预算数据的本地目录
ACTUAL_CACHE_TTL缓存 TTL,单位秒(默认 60)
ACTUAL_LOCK_TIMEOUT预算目录锁的等待超时,单位秒(默认 10)
ACTUAL_NO_LOCK设为1时禁用预算目录锁

除此之外,从源码还可以发现一个 README 环境变量表中未列出的变量:ACTUAL_ENCRYPTION_PASSWORD,对应--encryption-password全局 Flag,用于端到端加密(E2E encryption)预算的解密(见 packages/cli/src/index.ts)。如果你的预算开启了端到端加密,需要在同步时提供这把加密密码,connection.ts中下载预算时会将config.encryptionPassword传给api.downloadBudget(packages/cli/src/connection.ts)。

3.3 配置文件

CLI 使用 cosmiconfig 查找配置文件,查找范围是当前工作目录到主目录之间的任意位置(向上逐级查找)。可以使用的文件名格式:

  • .actualrc(JSON 或 YAML)
  • .actualrc.json.actualrc.yaml.actualrc.yml
  • actual.config.jsonactual.config.yamlactual.config.yml
  • package.json中的"actual"

此外,还可以把配置放在全局配置目录的actual子目录中(Linux 上例如~/.config/actual/),支持的文件名:

  • config(JSON 或 YAML)
  • config.json
  • config.yaml
  • config.yml

配置查找顺序在 packages/cli/src/config.ts 中与 cosmiconfig 的searchPlaces完全对应。

一个典型的.actualrc.json示例:

{ "serverUrl": "http://localhost:5006", "password": "your-password", "syncId": "1cfdbb80-6274-49bf-b0c2-737235a4c81f", "cacheTtl": 60, "lockTimeout": 10, "noLock": false }

配置文件可用的键与全局配置一一对应:serverUrlpasswordsessionTokensyncIddataDirencryptionPassword(字符串键),cacheTtllockTimeout(非负整数键),noLock(布尔键)。配置文件的校验逻辑相当严格(packages/cli/src/config.ts):文件必须是对象、不能包含未知键、字符串键必须是字符串、数值键必须是非负整数、布尔键必须是布尔值,否则直接报错。

安全提示(重要):不要在配置文件中保存明文密码(包括上面示例里的password键)。如果文件确实包含密码:

  • 请设置严格的文件权限(Linux 上例如600);
  • 如果文件位于 git 仓库内,务必加入.gitignore
  • 更推荐使用ACTUAL_PASSWORDACTUAL_SESSION_TOKEN环境变量;
  • 或者在配置文件中使用会话令牌(session token)代替密码。

3.4 全局 Flags 全表

Flag说明
--server-url <url>服务器 URL
--password <pw>服务器密码
--session-token <token>会话令牌
--sync-id <id>预算 Sync ID
--data-dir <path>数据目录
--cache-ttl <seconds>缓存 TTL;0表示禁用缓存(默认 60)
--refresh本次调用强制同步,忽略缓存
--no-cache--refresh的别名
--lock-timeout <secs>锁等待超时(默认 10)
--no-lock禁用预算目录锁(谨慎使用)
--format <format>输出格式:json(默认)、tablecsv
--verbose显示信息性消息

以上 Flags 在 packages/cli/src/index.ts 中均有对应定义,且每个选项都标注了对应的环境变量。两个值得注意的细节:

  • --format使用 commander 的.choices(['json', 'table', 'csv'])约束取值,非法值会直接报错;
  • --cache-ttl--lock-timeout都经过parseNonNegativeIntFlag校验,必须是非负整数(packages/cli/src/index.ts)。

四、命令总览与实战解析

4.1 命令总览表

命令说明
accounts管理账户
budgets管理预算与分配
categories管理分类
category-groups管理分类组
transactions管理交易
payees管理收款方
tags管理标签
rules管理交易规则
schedules管理排期交易
query运行 ActualQL 查询
server服务器工具与查找
sync刷新或检查本地缓存

运行actual <command> --help可以查看每个命令的子命令和选项。下面重点剖析几个最常用的命令组(均可在 packages/cli/src/commands 目录中看到实现)。

4.2 accounts:账户管理

accounts命令组(packages/cli/src/commands/accounts.ts)包含以下子命令:

  • accounts list [--include-closed]:列出所有账户。默认排除已关闭账户,加--include-closed才包含;输出会做稳定排序——预算内账户在前、预算外账户在后,并在每组内保持 API 的sort_order;同时批量拉取每个账户的余额。
  • accounts create --name <name> [--offbudget] [--balance <amount>]:创建账户,--balance是初始余额(整数分,默认0)。
  • accounts update <id> [--name <name>] [--offbudget <bool>]:更新账户名称或预算内外属性;不提供任何字段会报错。
  • accounts close <id> [--transfer-account <id>] [--transfer-category <id>]:关闭账户,可把剩余余额转入指定账户或分类。
  • accounts reopen <id>:重新打开已关闭的账户。
  • accounts delete <id>:删除账户。
  • accounts balance <id> [--cutoff <date>]:查询账户余额,--cutoff支持指定日期(YYYY-MM-DD),返回该日期节点的余额。

4.3 budgets:预算管理

budgets命令组(packages/cli/src/commands/budgets.ts)负责预算数据与分配操作:

  • budgets list:列出服务器上所有可用预算(此命令无需 Sync ID,skipBudget: true)。
  • budgets download <syncId> [--encryption-password <password>]:按 Sync ID 下载预算,加密预算需要提供加密密码。
  • budgets months:列出所有存在数据的预算月份。
  • budgets month <month>:查看指定月份(YYYY-MM)的完整预算数据。
  • budgets set-amount --month <month> --category <id> --amount <amount>:为某分类在指定月份设置预算金额(整数分)。
  • budgets set-carryover --month <month> --category <id> --flag <bool>:开启/关闭某分类的结转(carryover)。
  • budgets hold-next-month --month <month> --amount <amount>:为下月预留预算金额。
  • budgets reset-hold --month <month>:重置某月的预算预留。

4.4 transactions:交易增删改查与导入导出

transactions命令组(packages/cli/src/commands/transactions.ts):

  • transactions list --account <id> --start <date> --end <date>:列出指定账户在日期区间内的交易。
  • transactions add --account <id> [--data <json>] [--file <path>] [--learn-categories] [--run-transfers]:新增交易,--data传 JSON 数组,或用--file从文件/标准输入读取;--learn-categories启用分类学习,--run-transfers处理转账。
  • transactions import --account <id> [--data <json>] [--file <path>] [--dry-run]:导入交易(去重语义与add不同),--dry-run可以先预览导入结果而不真正写入。
  • transactions update <id> [--data <json>] [--file <path>]:更新指定交易字段。
  • transactions delete <id>:删除交易。

--data--file是互斥的 JSON 输入来源:--file -表示从标准输入读取,方便与其他命令用管道组合(详见readJsonInput的实现)。

4.5 query:用 ActualQL 查询数据

query命令组(packages/cli/src/commands/query.ts)是 CLI 中最强大的数据检索能力,底层使用 Actual 的查询语言 ActualQL(AQL):

  • query run:执行一条 AQL 查询。
  • query tables:列出可查询的表。
  • query fields <table>:列出某张表的所有字段及其类型。

query run的核心选项:

选项说明
--table <table>要查询的表(可用query tables查看)
--select <fields>逗号分隔的字段列表
--filter <json>JSON 格式的过滤条件,如'{"amount":{"$lt":0}}'
--where <json>--filter的别名(不能同时使用)
--order-by <fields>排序字段,可带方向:field1:desc,field2(默认 asc)
--limit <n>结果数量上限
--offset <n>跳过前 N 条(用于分页)
--last <n>显示最近 N 笔交易(隐含--table transactions--order-by date:desc
--count统计匹配行数而非返回数据
--group-by <fields>分组字段(配合聚合 select 使用)
--file <path>从 JSON 文件读取完整查询对象(-表示标准输入)

从 packages/cli/src/commands/query.ts 的TABLE_SCHEMA可以看到当前可查询的表:transactionsaccountscategoriespayeesrulesschedulestransactions表的字段非常丰富,包括idaccountdateamountpayeecategorynotesclearedreconciledis_parentis_childparent_idschedule,以及便捷的关联字段account.namepayee.namecategory.namecategory.group.name

--order-by支持date:desc,amount:asc,id这种带方向的多字段写法,解析逻辑在 packages/cli/src/commands/query.ts 的parseOrderBy中实现。

4.6 server 与 sync:服务器工具与缓存管理

server命令组(packages/cli/src/commands/server.ts):

  • server version:获取服务器版本(此命令不需要 Sync ID)。
  • server get-id --type <type> --name <name>:按名称查找实体 ID,--type可选accountscategoriespayeesschedules。在脚本中非常实用——先用名字查 ID,再拿去查询或写入。
  • server bank-sync [--account <id>]:触发银行同步,可只同步指定账户。

sync命令组(packages/cli/src/commands/sync.ts):

  • sync:立即把本地缓存与服务器同步。
  • sync --status:显示本地缓存有多"旧"(stale),返回syncedAtlastDownloadedAtageSecondsttlSecondsstale等字段。
  • sync --clear:删除本地缓存,下次命令会重新下载。

五、金额约定:整数分(cents)

所有作为输入传入的货币金额(无论是 Flag 还是 JSON)都使用整数分

CLI 值美元金额
5000$50.00
-12350-$123.50

例如-2500表示 -$25.00,50000表示 $500.00。这种约定避免了一切浮点精度问题,与 Actual 内部的数据存储方式一致。

输出格式化规则:

  • --format table--format csv输出时,会把分值字段自动转换为十进制(例如显示1665.00而不是166500);
  • --format json输出始终返回原始分值,方便程序化处理。

这个自动转换在 packages/cli/src/output.ts 中通过AMOUNT_FIELDS集合实现——amountbalancebalance_availablebalance_currentbalance_limitbudgetedspentcarryover这些字段在表格/CSV 输出时都会执行value / 100并保留两位小数。

值得一提的安全细节:CSV 输出对以=+-@、制表符、回车开头的非数值字符串做了公式注入防护(前缀'中和),但数值型金额(如-25.00)不会被打引号,保证负数金额在电子表格中仍以数值呈现(packages/cli/src/output.ts)。

六、实战示例合集

以下示例完整覆盖 README 中的常用场景,并补充了便于直接复制运行的注释:

# 以表格形式列出所有账户(默认排除已关闭账户) actual accounts list [--include-closed] --format table # 按名称查找实体 ID(脚本自动化第一步) actual server get-id --type accounts --name "Checking" # 新增一笔交易(金额为整数分:-2500 = -$25.00) actual transactions add --account <id> \ --data '[{"date":"2026-03-14","amount":-2500,"payee_name":"Coffee Shop"}]' # 导出整年交易到 CSV actual transactions list --account <id> \ --start 2026-01-01 --end 2026-12-31 --format csv > transactions.csv # 为某分类设置预算金额($500 = 50000 分) actual budgets set-amount --month 2026-03 --category <id> --amount 50000 # 运行一条 ActualQL 查询:最近 10 笔支出 actual query run --table transactions \ --select "date,amount,payee" --filter '{"amount":{"$lt":0}}' --limit 10 # 快捷方式:最近 5 笔交易 actual query run --last 5 # 统计交易数量 actual query run --table transactions --count # 按分类分组聚合(配合 --file 使用聚合表达式) echo '{"table":"transactions","groupBy":["category.name"],"select":["category.name",{"amount":{"$sum":"$amount"}}]}' | actual query run --file - # 分页 actual query run --table transactions --order-by "date:desc" --limit 10 --offset 20 # --where 是 --filter 的别名 actual query run --table transactions --where '{"payee.name":"Grocery Store"}' --limit 5 # 从 JSON 文件读取完整查询 actual query run --file query.json

query run还支持从标准输入读取查询 JSON(--file -),这让它天然适合被其他脚本和命令管道驱动。AQL 常用过滤操作符包括$eq$ne$lt$lte$gt$gte$like$and$or

七、常见坑与实用建议

1. 拆分交易(Split transactions)会重复计数。统计或求和交易时,务必过滤"is_parent": false。拆分交易的父交易持有总额,子交易持有各部分金额——把两者都算进去等于把总额数了两遍。这是 README 明确强调、且query帮助文本中反复出现的注意事项。

2. 未分类交易的category.namenull按分类过滤或分组时要把这个情况考虑进去。

3. AQL 不支持日期子字段。date.monthdate.year等不能作为查询字段使用。如果需要按月份分组,正确做法是用日期范围过滤拉取原始交易,然后在本地脚本中自行聚合。

4. 高频顺序请求的性能。CLI 默认会在本地缓存预算(见下一节),所以读多写少的脚本不再需要"单查询"式的规避方案。对于请求非常频繁的脚本,可以先执行一次actual sync,然后用较长的--cache-ttl做后续读取:

actual sync actual --cache-ttl 3600 query run ... actual --cache-ttl 3600 accounts list

这样后续的读命令在 TTL 内直接命中本地缓存,不产生网络往返。

5. 先查 ID 再操作。所有写操作(如transactions addbudgets set-amount)都要求传实体 ID。在脚本中建议先用actual server get-id --type ... --name ...把人类可读的名字解析成 ID,再执行后续操作,避免硬编码 UUID。

八、缓存机制深度解析

CLI 会在本地保留一份预算副本,让重复命令不必每次都打同步服务器。在默认 TTL(60 秒)内,读命令(listbalancequery run等)直接复用缓存,不做网络往返;写命令(addupdateset-amount等)则始终在写入前后各同步一次服务器。

缓存相关的操作:

  • actual sync—— 立即刷新缓存。
  • actual sync --status—— 查看本地缓存有多旧。
  • actual sync --clear—— 删除本地缓存,下次命令重新下载。
  • --refresh(或--no-cache)—— 单次调用强制同步。
  • --cache-ttl <seconds>—— 单次调用覆盖 TTL(用0禁用缓存)。

缓存的底层决策逻辑非常清晰,见 packages/cli/src/cache.ts 的decideSyncAction

  • 本地没有缓存状态 → 动作download(首次下载预算);
  • 缓存中的syncIdserverUrl与当前配置不一致 → 动作download(重新下载);
  • 写操作、或指定了--refresh、或 TTL 为0、或预算加密→ 动作sync(先加载再同步);
  • 距上次同步时间小于 TTL → 动作skip(直接用缓存);
  • 缓存过期(超过 TTL)→ 动作sync

缓存状态存放在数据目录下以syncId命名的子目录中的state.json文件里,包含versionsyncIdbudgetIdserverUrllastSyncedAtlastDownloadedAt等字段(packages/cli/src/cache.ts),目录结构为<dataDir>/.actual-cli/<syncId>/state.json。缓存写入采用"临时文件 + 原子重命名"策略,并用进程 PID + 随机数保证临时文件名唯一,避免并发写者互相破坏(packages/cli/src/cache.ts);同时缓存持久化是"尽力而为"的,写不进也不至于让命令崩溃。

从 packages/cli/src/connection.ts 可以看到完整流程:读缓存状态 →decideSyncAction决策 → 按需downloadBudget/loadBudget/sync→ 执行命令回调 → 若是写操作再sync一次并刷新lastSyncedAt

九、并发与锁机制

CLI 针对每个预算的缓存目录加锁:读操作加共享锁(多个并行读安全),写操作加排他锁(写操作串行化)。如果另一个 CLI 进程持锁,后续调用最多等待--lock-timeout秒(默认 10)然后报错退出。在可信的单进程环境中可以传--no-lock跳过加锁。

锁实现细节见 packages/cli/src/lock.ts:排他锁基于proper-lockfile的目录锁(锁文件lock),等待超时换算为重试策略;共享锁则在readers目录下写入以PID-随机数命名的标记文件,写操作要等所有 reader 标记消失才继续。实现里还包含陈旧 reader 清理——通过process.kill(pid, 0)探测进程是否存活,自动清扫死进程遗留的标记,避免死锁(packages/cli/src/lock.ts)。锁文件另有 30 秒的 stale 判定,崩溃进程遗留的锁也能被后续进程接管。

十、在 monorepo 中本地运行与开发

如果你想直接在这个仓库里跑 CLI(例如调试新功能或不想走 npm 全局安装),README 给出了完整流程:

# 1. 构建 CLI yarn build:cli # 2. 在另一个终端启动本地同步服务器 yarn start:server-dev # 3. 浏览器打开 http://localhost:5006,创建一个预算, # 然后在 设置 → 高级 → Sync ID 中拿到 Sync ID # 4. 直接从构建产物运行 CLI ACTUAL_SERVER_URL=http://localhost:5006 \ ACTUAL_PASSWORD=your-password \ ACTUAL_SYNC_ID=your-sync-id \ node packages/cli/dist/cli.js accounts list # 或者定义一个简写别名方便使用 alias actual-dev="node $(pwd)/packages/cli/dist/cli.js" actual-dev budgets list

yarn build:cli会调用 packages/cli/package.json 中的vite build将 TypeScript 源码编译到dist/。CLI 依赖@actual-app/api(工作区内的 packages/api)、commander(参数解析)、cosmiconfig(配置文件查找)、proper-lockfile(目录锁)、cli-table3(表格输出),这些依赖关系同样记录在 packages/cli/package.json。

结语

@actual-app/cli把 Actual Budget 的绝大部分核心操作带到了终端:账户、交易、分类、预算分配、规则、排期,乃至完整的 ActualQL 查询能力。配合环境变量/配置文件的三层配置体系、整数分的金额约定、本地缓存与细粒度锁机制,它非常适合承担定时脚本、CI 流水线、数据导出备份等自动化任务。需要进一步探索某个子命令的细节时,actual <command> --help永远是最好的起点——查询相关的actual query run --help还会直接列出所有可用表与常用过滤操作符。

【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 14:39:53

三维可视化拖拽工具:数字孪生的零代码革命

1. 项目概述&#xff1a;三维可视化的"拖拽革命"去年我在给某制造企业做数字孪生项目时&#xff0c;客户突然提出要调整生产线布局。按照传统开发流程&#xff0c;这需要前端重写Three.js场景代码、后端更新数据接口&#xff0c;至少耗费3人日。但当我打开新版的拖拽…

作者头像 李华
网站建设 2026/9/10 14:39:48

AI论文写作工具对比:千笔与WPS如何提升本科生学术效率

1. 项目概述&#xff1a;AI论文写作工具如何改变本科生学术生活 第一次接触学术论文写作的本科生&#xff0c;往往面临选题迷茫、结构混乱、语言表达不专业等典型问题。传统解决方案是反复阅读学长范文或依赖导师逐句修改&#xff0c;效率低下且学习曲线陡峭。如今AI写作助手的…

作者头像 李华
网站建设 2026/9/10 14:39:06

企业指标平台选型:ROI计算与降本增效实践

1. 指标平台选型的核心痛点与ROI计算逻辑在企业数据体系建设中&#xff0c;指标平台选型往往面临"价值难量化"的困境。传统评估方式通常聚焦于功能清单对比&#xff0c;却忽略了最关键的投入产出比分析。Aloudata CAN指标平台提出的ROI计算框架&#xff0c;直击三大核…

作者头像 李华