Blog

A Guide to OpenClaw Accounting Using Bitwave CLI

Agentic Finance

A Guide to OpenClaw Accounting Using Bitwave CLI
Give your OpenClaw agent a ledger, not just a wallet. Learn how to set up Bitwave CLI, a double-entry ledger built for agents, with guardrails for autonomous spend.
Table of Contents
Autonomous finance still requires accountable finance.
Schedule a Demo

If you're running OpenClaw, at some point your agent is going to touch money. Every provider call it makes has a price. And if you've given it a browser, a shell, or a payment plugin, it might eventually spend money on its own e.g. buying API credits, signing crypto transactions, or making ecommerce purchases.

To keep an honest, balance-checked record of what OpenClaw costs and what it spends, I’ll show you how to use Bitwave CLI, a plain-text, double-entry accounting CLI built explicitly for agents.

Two kinds of "agent spend"

It's worth segmenting these because they need different treatment:

  • The cost of running the agent. Every message OpenClaw's agent answers burns tokens against whatever LLM provider you've configured. Add image, video, or music generation, or transcription, and the bill grows. This is usage-based billing, like a phone bill.
  • The spend the agent initiates. This is the agent taking an action that moves real money. It's not a default OpenClaw capability, but it's increasingly common e.g. via the built-in browser tool driving a checkout flow, the exec tool shelling out to a payment API or wallet CLI, or a plugin/MCP server purpose-built for payments (Stripe checkout, crypto wallets, pay-per-use "agent payment protocol" style APIs).

Both need a ledger. After I show you how to set up bitwave-cli I’ll walk through both scenarios.

How to set up Bitwave CLI alongside OpenClaw

Do this once, regardless of which scenario applies to you. Everything below runs in a terminal on the same machine where OpenClaw's Gateway is running.

Install bitwave. Homebrew is the quickest path on macOS and Linux:

brew install bitwave-io/tap/bitwave

npm works too if that's already in your toolchain:

npm install -g bitwave

Or the install script which verifies a checksum and drops the binary in ~/.local/bin:

curl -fsSL https://cli.bitwave.io/install.sh | sh

Whichever route, confirm it's on your $PATH:

bitwave --help

Create a workspace directory next to, not inside, OpenClaw's own config. OpenClaw keeps its config and state under ~/.openclaw/; give bitwave its own directory instead, e.g.:

mkdir ~/openclaw-books && cd ~/openclaw-books
bitwave init --name openclaw-2026 --base-currency USD

This creates a .bitwave.toml and an empty default.journal in the current directory. That directory is the workspace, so every bitwave command from here on needs to be run from inside it (or you point at it explicitly).

Decide who's going to run the bitwave commands, because it changes where this directory needs to be reachable from. If a human runs entries manually, or a plain cron job on the gateway host runs them, ~/openclaw-books is all you need - nothing about OpenClaw's own sandboxing applies. But if you want the agent itself to write entries (as part of a cron job or hook it triggers via its exec tool) check first whether that agent's exec calls run directly on the host or inside a sandboxed container:

openclaw sandbox explain --agent <your-agent-name>

This prints the agent's effective sandbox mode and workspace access. If it reports the agent runs unsandboxed (mode: "off" or host exec), ~/openclaw-books is already reachable and you're done.

If it reports a sandboxed/containerized exec target, the workspace directory needs to be bind-mounted into that container (via docker.binds in your OpenClaw config) before any agent-triggered bitwave command will find it. Here’s an example of adding a bind bound in the OpenClaw config:

{
  "agents": {
    "defaults": {
      "sandbox": {
        "docker": {
          "binds": ["/home/you/openclaw-books:/openclaw-books:rw"]
        }
      }
    }
  }
}

The format is host:container:mode 

Put it under agents.defaults.sandbox.docker.binds to apply to every agent, or under a specific agent in agents.list[] to scope it to just one. Restart the affected sandbox (openclaw sandbox recreate) so the new bind takes effect, then re-run openclaw sandbox explain to confirm the mount shows up before trusting any agent-triggered bitwave command to find it.

Scenario A: accounting for what OpenClaw costs to run

The accounting boils down to the same three steps: get the usage number, post it to the right expense account, reconcile at period end.

Account design. One expense account per cost source. For example:

bitwave acct add Expenses:LLM:Anthropic
bitwave acct add Expenses:LLM:OpenAI
bitwave acct add Expenses:Media:ImageGen
bitwave acct add Expenses:Transcription:Deepgram
bitwave acct add Assets:Prepaid

Attribute to channel, session, or cron job with --note rather than more accounts. You don't want a chart of accounts that grows with every Telegram thread.

Record spend on a rollup cadence, not per message (otherwise per-token entries turn into noise fast):

bitwave je new --date 2026-08-22 --payee "Anthropic API" \
  --posting "Expenses:LLM:Anthropic  $4.85" \
  --posting "Assets:Prepaid         -$4.85" \
  --note "period:2026-08-22 channel:telegram"

Tag entries with a period id so a scripted daily rollup is idempotent (re-running it shouldn't double-count). OpenClaw's own cron and heartbeat system is a natural place to trigger this: a daily cron job pulls usage from each provider and writes one bitwave je new per provider, per day.

Reporting is just bitwave bal --account Expenses:LLM, bitwave reg for the detail, and bitwave expense report --format csv when someone wants it in a spreadsheet.

Scenario B: accounting for what the agent spends on its own

Spend isn't a default OpenClaw capability; it only exists if you've enabled a tool with real financial reach: exec shelling out to a payment API or wallet CLI, browser driving a checkout flow, or a plugin/MCP server built for payments. Know exactly which tools on your agent can do this before you worry about how to record it.

The recording pattern is the same regardless of how the agent spends: record the entry as close to the action as possible, and never let the entry be fabricated to force a balance. bitwave enforces the second part for you: it refuses to write an entry that doesn't balance. The discipline you own is the first part.

Browser-driven purchases. If you've decided to let the agent go all the way to checkout, log the entry the moment the order confirms, using the real total, not an estimate:

bitwave je new --date 2026-08-22 --payee "Vendor via browser checkout" \
  --posting "Expenses:Procurement:Supplies  $58.20" \
  --posting "Assets:Checking               -$58.20" \
  --note "agent:main tool:browser order:1082"

Exec'd payment API calls. If the agent shells out to Stripe or another payment API, write the bitwave je new call into the same script that fires the charge. That way the entry and the charge succeed or fail together:

bash
result=$(curl -s -X POST https://api.stripe.com/v1/charges ...)
bitwave je new --date "$(date +%Y-%m-%d)" --payee "Stripe charge" \
  --posting "Expenses:Vendor:Acme   \$120.00" \
  --posting "Assets:Checking       -\$120.00" \
  --note "stripe_charge_id:$(echo "$result" | jq -r .id)"

Crypto wallet spend. This one's built in: bitwave wallets send signs, broadcasts, and writes the balanced entry as a single step, so there's no gap between the transaction and the record:

bitwave wallets send --wallet treasury --network base \
  --to 0xVENDOR --amount-eth 0.02 \
  --category Expenses:Vendor:Acme --memo "invoice 1082"

Use --dry-run to preview the entry before it's real (useful for any spend-capable path, not just crypto).

Pay-per-use / agent-payment-protocol spend. If your agent is paying per API call or per browser session, volume gets high and amounts get small fast. Batch these into a rollup entry the same way you'd batch LLM token costs, rather than writing one journal entry per call:

# Sum today's micro-payments from wherever they're logged (a local
# file, the payment provider's usage API, etc.), then write one entry.
total=$(jq -s 'map(.amount) | add' payments-2026-08-22.jsonl)

bitwave je new --date 2026-08-22 --payee "Pay-per-use API (rollup)" \
  --posting "Expenses:API:PayPerUse  \$$total" \
  --posting "Assets:Prepaid         -\$$total" \
  --note "period:2026-08-22 calls:$(jq -s 'length' payments-2026-08-22.jsonl)"

Accepting payments, not just making them. If the agent runs the other direction - issuing invoices and collecting payment via a channel like WhatsApp or Telegram (Stripe/PayRam-style setups do this) - the same ledger takes the credit side: Assets:Checking up, Income:... up, same balance-check.

Get your OpenClaw agent a ledger today

Install Bitwave CLI, run bitwave init, and make your agent’s next transaction the first line in a real audit trail.

The accounting infrastructure for autonomous finance
Schedule a Demo
G2 High Performer Winter 2024G2 High Performer Winter 2024

Disclaimer: The information provided in this blog post is for general informational purposes only and should not be construed as tax, accounting, or financial advice. The content is not intended to address the specific needs of any individual or organization, and readers are encouraged to consult with a qualified tax, accounting, or financial professional before making any decisions based on the information provided. The author and the publisher of this blog post disclaim any liability, loss, or risk incurred as a consequence, directly or indirectly, of the use or application of any of the contents herein.

See more on Bitwave