append_row.py:
- Switch valueInputOption from USER_ENTERED to RAW.
- coerce() the row per-column: amount / amount_hkd / fx_rate become floats,
everything else stays a string. Combined with RAW, dates ("2026-04-20") no
longer get auto-parsed into Sheets date serials (e.g. 46153), while amounts
still land as proper numeric cells so SUM/AVERAGE keep working.
fx_convert.py:
- Cache frankfurter.app responses in ~/.cache/autoacct/fx_cache.json (atomic
write via .tmp + replace). Keyed by "<currency>_<date>". ECB historical
rates are immutable, so an indefinite TTL is safe. Measured locally:
cache hit 52ms vs cache miss 470ms (~9x).
setup.md: troubleshooting entries for pre-existing serial-date rows and for
the FX cache location.
Auth path also verified end-to-end via pure bash + openssl + curl (JWT
sign → token exchange → Sheets API 404 on bogus ID), proving the wire
format is correct independent of the Python client.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
AutoACCT for OpenClaw
English | 简体中文
An OpenClaw skill that turns a receipt image (optionally with a caption) into a structured row in a Google Sheet, with automatic HKD conversion.
Intended to be invoked manually inside OpenClaw today, and wired up to a WhatsApp webhook later.
What it does
- Reads a receipt / invoice / payment-screenshot image via vision.
- Extracts: date, merchant, category, amount, currency, payment method, line items, raw OCR, caption note.
- Converts the amount to HKD at that day's ECB reference rate via frankfurter.app (free, no API key).
- Appends one row to a configured Google Sheet (14 columns — see
schema.md). - Replies with the row and flags any field it had to guess.
Install (end users)
The repo bundles the team's Google service-account key, encrypted with AES-256. Ask your admin for one thing: the passphrase (it's in your team's password manager).
Follow the 4 steps below. Takes ~5 minutes.
Not comfortable with the terminal? Use
DEPLOY.mdinstead — same install, but written for non-technical users with an AI agent walking them through.Don't want to share a service account with the rest of the team? See
BYO-KEY.mdfor how to bring your own — more private, but ~15 minutes of extra GCP setup.
Step 1 — Clone the skill and install Python deps
git clone https://github.com/CharlesZhang2023/AutoACCT.git ~/.openclaw/workspace/skills/AutoACCT
cd ~/.openclaw/workspace/skills/AutoACCT
pip install google-api-python-client google-auth
Step 2 — Decrypt the bundled service-account key
bash scripts/decrypt-key.sh
You'll be prompted for the passphrase. On success the script writes the JSON to ~/.config/gcp/bookkeeping-sa.json (mode 600) and prints the service-account email — copy it; you'll paste it into Step 3.
Step 3 — Create your Google Sheet and share it with the service account
- Open https://sheets.new (creates a fresh blank sheet).
- Title it (e.g.
My AutoACCT Expenses). - Note the tab name at the bottom-left —
Sheet1(English UI) or工作表1(Chinese UI). You'll paste it intoconfig.jsonin Step 4. - Click cell A1, then paste this one line (the tabs split the headers across A–N automatically):
Date Merchant Category Amount Currency Amount (HKD) FX Rate FX Date Payment Method Line Items Raw OCR Note Receipt Logged At - Click Share (top right) → paste the service-account email that
decrypt-key.shprinted in Step 2 → role Editor → Send (you can uncheck "Notify people"). - Copy the full URL from your browser's address bar. Something like:
https://docs.google.com/spreadsheets/d/1abc...xyz/edit#gid=0(The script extracts the sheet ID for you — either the full URL or just the bare ID works.)
Step 4 — Write config.json
cd ~/.openclaw/workspace/skills/AutoACCT
cp config.example.json config.json
Open config.json and fill in sheet_id (paste the URL from Step 3.6) and worksheet (the tab name from Step 3.3):
{
"sheet_id": "https://docs.google.com/spreadsheets/d/1abc...xyz/edit",
"worksheet": "Sheet1",
"service_account_path": "~/.config/gcp/bookkeeping-sa.json",
"hkd_fx_provider": "frankfurter"
}
Common pitfall: if your Google Sheets UI is in Chinese, the default tab is named
工作表1(notSheet1). Put"worksheet": "工作表1"exactly. A mismatched tab name throwsHTTP 400: Unable to parse range.
Sanity check
echo '{"date":"2026-04-20","merchant":"TEST","category":"Other","amount":1,"currency":"HKD","amount_hkd":1,"fx_rate":1,"fx_date":"2026-04-20"}' | python3 ~/.openclaw/workspace/skills/AutoACCT/scripts/append_row.py
Success looks like: OK 'Sheet1'!A2:N2 and a new row appears in your sheet. Delete the TEST row when you're done.
If you hit an error, see scripts/setup.md for troubleshooting.
Admin setup (one time, done by you before distributing)
See scripts/setup.md for the full admin guide and secrets/README.md for the encryption mechanics. Short version:
- Create a GCP project, enable Sheets API, create a service account, download the JSON key.
- Encrypt the JSON with a strong random passphrase and commit
secrets/bookkeeping-sa.json.encto the repo (seesecrets/README.mdfor the openssl one-liner). - Store the passphrase in your team password manager. Tell users to follow the 4 install steps above.
- Rotate the passphrase when team members leave; rotate the underlying GCP key when the passphrase or any decrypted JSON might have leaked.
Use
In an OpenClaw session, drop a receipt image in and say "log this" (or similar). The skill auto-triggers on receipt-image requests — no slash command needed.
Caption is optional; use it to add context (payment method, split, category hint, free-text note).
Files
| File | Purpose |
|---|---|
SKILL.md |
Entry — OpenClaw reads this to invoke the skill |
categories.md |
Fixed category list (14 categories) |
schema.md |
Google Sheet column order (A–N) |
config.example.json |
Template → copy to config.json (gitignored) |
scripts/fx_convert.py |
Currency → HKD via frankfurter.app |
scripts/append_row.py |
Writes one row to Google Sheets |
scripts/decrypt-key.sh |
Decrypts bundled SA key to ~/.config/gcp/ |
scripts/setup.md |
Admin setup guide + troubleshooting |
secrets/bookkeeping-sa.json.enc |
Team SA key, AES-256 encrypted (safe to commit) |
secrets/README.md |
How the encryption works + rotation procedures |
DEPLOY.md |
Step-by-step install guide for non-technical users |
BYO-KEY.md |
Optional: create your own SA instead of using the shared one |
License
MIT © 2026 Knowit