Adopt shared-SA model, add DEPLOY guide, MIT license

- Install flow now assumes one admin-distributed service account JSON shared
  across the team. Each user creates their own Google Sheet and shares it
  with the SA email; per-user GCP project setup is gone.
- DEPLOY.md: a step-by-step walkthrough for non-technical users following
  along with an AI agent (Terminal basics, screenshots-worth of expected
  output, common-error table).
- scripts/append_row.py: sheet_id field accepts either a bare ID or a full
  Google Sheets URL; normalize_sheet_id() extracts the ID via regex.
- scripts/setup.md: rewritten as an admin guide (one-time GCP setup, key
  rotation) plus a troubleshooting reference.
- LICENSE: MIT (previously "private — internal use"). README license
  sections updated to match.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 11:08:48 +08:00
parent 499af13bd3
commit 4e40772150
8 changed files with 514 additions and 129 deletions

299
DEPLOY.md Normal file
View File

@@ -0,0 +1,299 @@
# AutoACCT — Install Guide for Non-Technical Users
This guide is written for people who don't write code for a living. If you can use email and Google Sheets, you can finish this in about 5 minutes. You will **not** need to understand any of the code you see, and you will **not** create anything inside Google Cloud — your admin already did that part for you.
If you are following this with an AI agent (Claude, OpenClaw, ChatGPT, etc.), you can paste any error or screenshot into the chat and ask "what does this mean?" — the agent will translate.
---
## What you are about to set up
By the end of this guide, you will be able to drop a photo of a receipt into a chat with your AI assistant and have it automatically appear as a new row in your own Google Sheet, with the amount converted to Hong Kong Dollars.
You will keep your own Google Sheet (only you can read it). A small "service account" that your admin already created will be allowed to add rows to your sheet — and nothing else. You can revoke that access at any time by un-sharing the sheet.
---
## Before you start: a 30-second checklist
Make sure you have all five of these. If any is missing, stop and get it before continuing.
| You need | How to check |
|---|---|
| **A Google account** | You can sign in to gmail.com |
| **A Mac or Linux computer** | This guide uses Mac. Linux is identical. **Windows users**: use WSL (Windows Subsystem for Linux), or ask your AI agent for the Windows-equivalent commands |
| **OpenClaw (or another AI client) installed** | You already use it to chat with an AI |
| **A JSON file your admin sent you** | A file usually named `autoacct-sa.json` — typically delivered through a password manager, encrypted email, or Slack DM. **If you don't have this, message your admin first.** |
| **A service-account email your admin gave you** | Looks like `autoacct@something.iam.gserviceaccount.com`. Your admin sent this together with the JSON. |
| **About 5 minutes** | Don't start during a phone call. |
---
## How to ask your AI agent for help
If you get stuck at any step:
1. Copy the step number and a short description of what went wrong.
2. If you can, take a screenshot.
3. Paste both into your AI chat and say something like: "I'm on Step 4 of the AutoACCT deploy guide and I see X. What should I do?"
The agent has access to this guide and can walk you through.
**Important:** If you do not understand a command, **ask before running it**. Do not paste any command you don't understand into a Terminal window.
---
# Part 1 — Get the code onto your computer (2 minutes)
## Step 1. Open the Terminal
The Terminal is a window where you type commands instead of clicking. You won't write any commands yourself — you'll only copy-paste them from this guide.
**On Mac:**
1. Press **Command (⌘) + Space** to open Spotlight search.
2. Type `terminal` and press **Enter**.
3. A small white-on-black (or black-on-white) window will appear.
That's the Terminal. Leave it open.
## Step 2. Copy the skill onto your computer + install its Python helpers
Copy the entire line below, click into the Terminal, paste, and press **Enter**:
```bash
git clone https://git.deepknow.site/Knowit/AutoACCT.git ~/.openclaw/workspace/skills/AutoACCT
```
**What you should see:** a few lines like `Cloning into '/Users/.../AutoACCT'...` followed by your prompt returning.
**If you see "git: command not found":** your Mac is missing developer tools. Run `xcode-select --install` and click through the popup. Then re-run the command above.
**If you see "fatal: destination path ... already exists":** you've run this before. Skip to the next command.
Now install the two Python packages the skill needs:
```bash
pip install google-api-python-client google-auth
```
**What you should see:** a flurry of `Collecting ...` / `Installing ...` lines ending with `Successfully installed ...`. Done.
**If `pip` is not found:** try `pip3` instead, or run `python3 -m pip install google-api-python-client google-auth`.
---
# Part 2 — Put your admin's key file in the right place (1 minute)
## Step 3. Find the JSON file your admin sent you
Locate the file (e.g. `autoacct-sa.json`). It is typically in:
- Your **Downloads** folder (if downloaded from email or a link)
- A folder you exported from a password manager (1Password / Bitwarden)
- An attachment on your desktop
**Treat this file like a password.** Anyone who has it can write to any Google Sheet you've shared with your admin's service account. Don't email it to yourself, don't post it anywhere, don't put it on a USB stick.
## Step 4. Move the JSON file to its permanent home
Paste this into the Terminal (assuming the file is in your Downloads folder and named `autoacct-sa.json`):
```bash
mkdir -p ~/.config/gcp
mv ~/Downloads/autoacct-sa.json ~/.config/gcp/autoacct-sa.json
chmod 600 ~/.config/gcp/autoacct-sa.json
```
**What you should see:** nothing visible. The Terminal returns silently — that means it worked.
**If you see "No such file or directory":** the file isn't in `~/Downloads`. Find where it actually is, and adjust the `mv` command. For example, if it's on your Desktop:
```bash
mv ~/Desktop/autoacct-sa.json ~/.config/gcp/autoacct-sa.json
```
**If the file has a different name** (e.g. `autoacct-project-12345.json`): use that name in the `mv` command, but **rename it to `autoacct-sa.json` while moving**:
```bash
mv ~/Downloads/autoacct-project-12345.json ~/.config/gcp/autoacct-sa.json
```
**Verify:** paste this into the Terminal:
```bash
ls -la ~/.config/gcp/
```
You should see one line containing `autoacct-sa.json` with permissions `-rw-------`.
---
# Part 3 — Make your Google Sheet and grant access (2 minutes)
## Step 5. Create a new blank sheet
1. In your web browser, go to **https://sheets.new**
2. A blank spreadsheet opens.
3. At the top-left where it says **Untitled spreadsheet**, click and rename it to something like `My AutoACCT Expenses`.
## Step 6. Note the tab name (very important)
Look at the bottom-left of your sheet. You'll see one tab:
- If you see `Sheet1` → write down "Sheet1"
- If you see `工作表1` → write down "工作表1"
You'll paste this exact name into `config.json` in Step 10. **Tab name and config must match exactly, or saving will fail.**
## Step 7. Paste in the table headers
1. Click cell **A1** (top-left cell).
2. Copy this **entire single line** (don't worry that it looks long — it's one line with invisible tab characters separating the 14 headers):
```
Date Merchant Category Amount Currency Amount (HKD) FX Rate FX Date Payment Method Line Items Raw OCR Note Receipt Logged At
```
3. Paste into cell A1. The 14 headers automatically spread across columns A through N.
**Verify:** Column A says `Date`, Column N (scroll right if needed) says `Logged At`.
## Step 8. Share the sheet with your admin's service account
This is the step that lets the skill write into your sheet.
1. Click the green **Share** button (top right of the sheet).
2. In the "Add people, groups, and calendar events" box, **paste the service-account email your admin gave you**. It looks something like:
```
autoacct@your-project-12345.iam.gserviceaccount.com
```
3. Make sure the role on the right says **Editor** (not Viewer / Commenter).
4. **Uncheck "Notify people"** — there's no real person on the other end of that email.
5. Click **Send** (or **Share**, depending on the dialog).
**Verify:** click Share again, scroll the list of people with access. You should see two entries: yourself (Owner) and the service-account email (Editor).
## Step 9. Copy the sheet's URL
Look at your browser's **address bar** — the URL of your sheet looks something like:
```
https://docs.google.com/spreadsheets/d/1abcDEF...xyz123/edit#gid=0
```
**Just copy the whole URL.** Click in the address bar, press **Command (⌘) + A** to select all, then **Command (⌘) + C** to copy.
(The script is smart enough to pull the sheet ID out of the URL. If you happen to know what the ID alone looks like, pasting just the ID also works — but the URL is easier to copy.)
---
# Part 4 — Connect the skill to your sheet (1 minute)
## Step 10. Create the config file
Back in your Terminal, paste and run:
```bash
cd ~/.openclaw/workspace/skills/AutoACCT
cp config.example.json config.json
```
Nothing visible happens — that's expected. The Terminal just made a copy of the template.
## Step 11. Edit the config file with your sheet ID and tab name
1. Open the config file with TextEdit (Mac's built-in text editor):
```bash
open -e config.json
```
A TextEdit window opens showing:
```json
{
"sheet_id": "PASTE_YOUR_GOOGLE_SHEET_URL_OR_ID_HERE",
"worksheet": "Sheet1",
"service_account_path": "~/.config/gcp/autoacct-sa.json",
"hkd_fx_provider": "frankfurter"
}
```
2. Replace `PASTE_YOUR_GOOGLE_SHEET_URL_OR_ID_HERE` with the URL you copied in Step 9. **Keep the double quotes around it.**
3. If your tab is `工作表1` (Chinese UI), change `"Sheet1"` to `"工作表1"`. Otherwise leave it.
4. **Leave the other two lines alone** — they already point at the JSON file you placed in Step 4.
The file should now look something like:
```json
{
"sheet_id": "https://docs.google.com/spreadsheets/d/1abcDEF...xyz123/edit#gid=0",
"worksheet": "Sheet1",
"service_account_path": "~/.config/gcp/autoacct-sa.json",
"hkd_fx_provider": "frankfurter"
}
```
5. Save: **Command (⌘) + S**, then close TextEdit.
**Important:** TextEdit sometimes converts plain quotes (`"`) into "smart quotes" (`"` and `"`). If your AI agent later complains about JSON errors, this is usually why. To prevent this:
- Before pasting: **TextEdit menu → Format → Make Plain Text** (if "Make Rich Text" is shown instead, you're already in plain text — good).
- Or ask your AI agent: "Open my config.json and check for smart quotes."
---
# Final test — Confirm it all works (30 seconds)
Paste this into the Terminal and run:
```bash
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
```
**What success looks like:**
```
OK 'Sheet1'!A2:N2
```
(or `'工作表1'!A2:N2` if you used the Chinese tab name)
Switch to your Google Sheet — there's a new row with `TEST` as the merchant. **You're done.** Delete the test row, then go drop a real receipt into your AI chat.
**What failure looks like, and how to fix it:** see the table below.
---
# Common problems
| You see | What it means | How to fix |
|---|---|---|
| `HTTP 403` or `The caller does not have permission` | You forgot Step 8 (sharing the sheet with the service-account email), or the email was typed incorrectly | Re-share the sheet with the exact email your admin gave you, role Editor. |
| `HTTP 400: Unable to parse range` | The `worksheet` in `config.json` doesn't match the actual tab name | Open `config.json`, fix it to exactly match the tab name at the bottom-left of your sheet (`Sheet1` or `工作表1`). |
| `HTTP 404` or `Requested entity was not found` | The `sheet_id` in `config.json` is wrong | Open your sheet in the browser, copy the **full URL** from the address bar, paste it into `sheet_id` (replacing whatever's there). |
| `FileNotFoundError ... autoacct-sa.json` | The JSON file isn't where `config.json` says it is | Run `ls -la ~/.config/gcp/` — confirm the file is there with the exact name `autoacct-sa.json`. If it has a different name, either rename it or update `service_account_path` in `config.json`. |
| `ImportError: No module named 'googleapiclient'` | You skipped or partially failed the `pip install` step | Re-run `pip install google-api-python-client google-auth`. If that fails, try `pip3` or `python3 -m pip install ...`. |
| `config.json not found` | You skipped Step 10 | Run `cp config.example.json config.json` from inside the skill folder. |
| `Expecting value: line 1 column 1` (JSON error) | Your `config.json` has smart quotes or is otherwise malformed | Re-open with TextEdit in plain-text mode (Format → Make Plain Text), or ask your AI agent to repair it. |
If your problem is not in this table: copy the **exact error text** and paste it to your AI agent along with "I'm following the AutoACCT deploy guide and I got this error at Step N."
---
# What to do when you want to change something later
| You want to... | What to do |
|---|---|
| Use a different sheet | Repeat Steps 59 on the new sheet (including the Share-with-service-account step), then update `sheet_id` and `worksheet` in `config.json`. |
| Stop the skill writing to a sheet | Open the sheet → Share → find the service-account email → click trash icon → Save. The skill will get HTTP 403 on the next attempt. |
| Move to a new computer | Repeat Parts 1, 2, and 4 on the new computer (re-clone, copy the JSON, copy `config.json`). Your sheet and its sharing don't change. |
| You think your JSON file leaked | Message your admin immediately. They can revoke the key on the GCP side; nothing they revoke can come back to bite you afterwards. |
---
# Summary of what just happened (so you understand what you set up)
1. **Your computer** has the AutoACCT skill in `~/.openclaw/workspace/skills/AutoACCT/`. When you drop a receipt photo into your AI chat, the AI runs `scripts/append_row.py`, which is a small Python program.
2. **The JSON file** at `~/.config/gcp/autoacct-sa.json` is the key that authenticates the Python program as a "service account" your admin created.
3. **The service account** is allowed to edit Google Sheets only when those sheets have been shared with its email. You shared *your* sheet with it in Step 8 — so it can only write to your sheet (and any other sheet you might share with it later).
4. **Other users on your team** have the **same JSON file** but their own sheets. The service account can write to each of their sheets only because each user has shared *their own* sheet with it. They cannot see your sheet, and you cannot see theirs.
That's it. Welcome to AutoACCT.

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2026 Knowit
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -14,9 +14,13 @@ Intended to be invoked manually inside OpenClaw today, and wired up to a WhatsAp
4. Appends one row to a configured Google Sheet (14 columns — see `schema.md`).
5. Replies with the row and flags any field it had to guess.
## Install
## Install (end users)
Follow the 6 steps below. Takes ~10 minutes.
Your admin will have given you **two things**: a service-account JSON key file (e.g. `autoacct-sa.json`) and a service-account email (e.g. `autoacct@your-project.iam.gserviceaccount.com`). If you don't have them, ask your admin first.
Follow the 4 steps below. Takes ~5 minutes.
> **Not comfortable with the terminal?** Use [`DEPLOY.md`](DEPLOY.md) instead — same install, but written for non-technical users with an AI agent walking them through.
### Step 1 — Clone the skill and install Python deps
@@ -25,69 +29,67 @@ git clone https://git.deepknow.site/Knowit/AutoACCT.git ~/.openclaw/workspace/sk
pip install google-api-python-client google-auth
```
### Step 2 — Create a Google Cloud service account
1. Open https://console.cloud.google.com/ and create a new project (e.g. `autoacct`).
2. In the top search bar, search **Google Sheets API** → click the result → **Enable**.
3. Left menu: **IAM & Admin → Service Accounts → + Create Service Account**
- Name: `AutoACCT` (any name works)
- Click **Create and Continue → Done** (skip the optional role step).
4. Click the new service account → **Keys** tab → **Add Key → Create new key → JSON → Create**.
A `.json` key file will download to your browser's Downloads folder.
5. **Copy the service account's email** (looks like `autoacct@<project>.iam.gserviceaccount.com`) — you'll paste it in Step 4.
### Step 3 — Move the key file out of the repo
Never leave a service-account key inside the repo directory. Move it to `~/.config/gcp/`:
### Step 2 — Drop the admin's JSON key into `~/.config/gcp/`
```bash
mkdir -p ~/.config/gcp
mv ~/Downloads/<your-downloaded-file>.json ~/.config/gcp/autoacct-sa.json
mv ~/Downloads/autoacct-sa.json ~/.config/gcp/autoacct-sa.json
chmod 600 ~/.config/gcp/autoacct-sa.json
```
### Step 4 — Create the Google Sheet
(Replace `~/Downloads/autoacct-sa.json` with wherever you saved the file your admin sent.)
### Step 3 — Create your Google Sheet and share it with the service account
1. Open https://sheets.new (creates a fresh blank sheet).
2. Give it a title (e.g. `AutoACCT Expenses`).
3. **Note the tab name** at the bottom-left — default is `Sheet1` (English UI) or `工作表1` (Chinese UI). Write it down, you'll need the exact string in Step 5.
2. Title it (e.g. `My AutoACCT Expenses`).
3. **Note the tab name** at the bottom-left — `Sheet1` (English UI) or `工作表1` (Chinese UI). You'll paste it into `config.json` in Step 4.
4. Click cell **A1**, then paste this one line (the tabs split the headers across AN automatically):
```
Date Merchant Category Amount Currency Amount (HKD) FX Rate FX Date Payment Method Line Items Raw OCR Note Receipt Logged At
```
5. Click **Share** (top right) → paste the service-account email from Step 2 → role **Editor** → **Send** (you can uncheck "Notify people").
6. Copy the **Sheet ID** from the URL — it's the long string between `/d/` and `/edit`:
`https://docs.google.com/spreadsheets/d/`**`1abc...xyz`**`/edit`
5. Click **Share** (top right) → paste the **service-account email** your admin gave you → role **Editor** → **Send** (you can uncheck "Notify people").
6. **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 5 — Write config.json
### Step 4 — Write config.json
```bash
cd ~/.openclaw/workspace/skills/AutoACCT
cp config.example.json config.json
```
Open `config.json` in your editor and fill in **sheet_id** and **worksheet** with the values from Step 4:
Open `config.json` and fill in **sheet_id** (paste the URL from Step 3.6) and **worksheet** (the tab name from Step 3.3):
```json
{
"sheet_id": "1abc...xyz",
"sheet_id": "https://docs.google.com/spreadsheets/d/1abc...xyz/edit",
"worksheet": "Sheet1",
"service_account_path": "~/.config/gcp/autoacct-sa.json",
"hkd_fx_provider": "frankfurter"
}
```
> ⚠️ **Common pitfall**: if your Google Sheets UI is in Chinese, the default tab is named `工作表1` (not `Sheet1`). Put `"worksheet": "工作表1"` exactly. A mismatched tab name throws `HTTP 400: Unable to parse range`.
> **Common pitfall**: if your Google Sheets UI is in Chinese, the default tab is named `工作表1` (not `Sheet1`). Put `"worksheet": "工作表1"` exactly. A mismatched tab name throws `HTTP 400: Unable to parse range`.
### Step 6 — Sanity check
### Sanity check
```bash
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 the sheet. Delete the TEST row when you're done.
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`](scripts/setup.md) for the longer reference.
If you hit an error, see [`scripts/setup.md`](scripts/setup.md) for troubleshooting.
## Admin setup (one time, done by you before distributing)
Before users can run the steps above, **you** (the admin) create one shared service account and distribute the JSON to users. See [`scripts/setup.md`](scripts/setup.md) for the full admin guide — short version:
1. Create a GCP project, enable Sheets API, create a service account, download the JSON key.
2. Distribute the JSON file + the service-account email to your users via a secure channel (1Password / Bitwarden / encrypted email — **never commit to git**).
3. Tell users to follow the 4 steps above.
## Use
@@ -97,22 +99,17 @@ Caption is optional; use it to add context (payment method, split, category hint
## 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 (AN) |
| `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/setup.md` | One-time setup steps |
## Roadmap
- [ ] WhatsApp webhook layer (Meta Cloud API or Twilio) so images can be sent from a phone.
- [ ] Optional Google Drive upload so the `Receipt` column becomes a clickable image link.
- [ ] Monthly summary script (totals by category, currency breakdown).
| 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 (AN) |
| `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/setup.md` | Admin setup guide + troubleshooting |
| `DEPLOY.md` | Step-by-step install guide for non-technical users |
## License
Private — internal use.
[MIT](LICENSE) © 2026 Knowit

View File

@@ -14,9 +14,13 @@
4. 向已配置好的 Google Sheet 追加一行14 列,具体见 `schema.md`)。
5. 回复记账结果,并标注任何靠推测填入的字段。
## 安装
## 安装(用户端)
按下面 6 步操作,整个过程约 10 分钟
管理员admin会给你**两样东西**:一个 service-account JSON 密钥文件(如 `autoacct-sa.json`),以及一个 service-account 邮箱(形如 `autoacct@your-project.iam.gserviceaccount.com`)。没拿到先找管理员要
按下面 4 步操作,约 5 分钟。
> **不太熟悉命令行?** 用 [`DEPLOY.md`](DEPLOY.md)(英文)—— 同样的安装流程,但是为非技术用户写的逐步指南,可配合 AI agent 一步步操作。
### Step 1 — Clone 仓库 + 装 Python 依赖
@@ -25,61 +29,51 @@ git clone https://git.deepknow.site/Knowit/AutoACCT.git ~/.openclaw/workspace/sk
pip install google-api-python-client google-auth
```
### Step 2 — 建 Google Cloud 服务账号
1. 打开 https://console.cloud.google.com/,左上角下拉 → **New Project** → 随便起名(如 `autoacct`)→ Create
2. 顶部搜索框搜 **Google Sheets API** → 点进去 → **Enable**
3. 左侧菜单 **IAM & Admin → Service Accounts → + Create Service Account**
- Name 填 `AutoACCT`(随意)
-**Create and Continue → Done**(中间可选的 role 步骤跳过)
4. 点进刚建好的服务账号 → 顶部 **Keys** 标签 → **Add Key → Create new key → 选 JSON → Create**
浏览器会自动下载一个 `.json` 文件到你的 Downloads
5. **复制服务账号的 email**(形如 `autoacct@<项目名>.iam.gserviceaccount.com`Step 4 要用
### Step 3 — 把 key 文件挪出 repo
**千万不要**把 key 留在 repo 目录里。挪到 `~/.config/gcp/`
### Step 2 — 把管理员发的 JSON 放到 `~/.config/gcp/`
```bash
mkdir -p ~/.config/gcp
mv ~/Downloads/<你下载的文件名>.json ~/.config/gcp/autoacct-sa.json
mv ~/Downloads/autoacct-sa.json ~/.config/gcp/autoacct-sa.json
chmod 600 ~/.config/gcp/autoacct-sa.json
```
### Step 4 — 建 Google Sheet
`~/Downloads/autoacct-sa.json` 改成你实际保存文件的路径。)
### Step 3 — 建你自己的 Google Sheet 并把它 share 给 service account
1. 打开 https://sheets.new直接创建空白 sheet
2. 给 sheet 起个标题(如 `AutoACCT Expenses`
3. **记住左下角 tab 的名字** — 英文界面默认 `Sheet1`,中文界面默认 `工作表1`Step 5 要用这个**精确字符串**
2. 给 sheet 起个标题(如 `我的 AutoACCT 账本`
3. **记住左下角 tab 的名字** 英文界面默认 `Sheet1`,中文界面默认 `工作表1`Step 4 要用这个**精确字符串**
4. 点进 **A1** 单元格,粘贴下面这一整行(中间是 Tab 分隔,粘进去会自动拆到 A1N1
```
Date Merchant Category Amount Currency Amount (HKD) FX Rate FX Date Payment Method Line Items Raw OCR Note Receipt Logged At
```
5. 右上角 **Share** → 粘贴 Step 2 复制的服务账号 email → 权限选 **Editor** → **Send**"Notify people" 可以不勾)
6. 从 URL 里复制 **Sheet ID** —— `/d/` 和 `/edit` 之间那一长串
`https://docs.google.com/spreadsheets/d/`**`1abc...xyz`**`/edit`
5. 右上角 **Share** → 粘贴管理员给你的 **service-account 邮箱** → 权限选 **Editor** → **Send**"Notify people" 可以不勾)
6. **从浏览器地址栏直接复制 sheet 的完整 URL**,类似
`https://docs.google.com/spreadsheets/d/1abc...xyz/edit#gid=0`
(脚本会自动从 URL 里抽出 sheet ID所以完整链接或裸 ID 都行。)
### Step 5 — 写 config.json
### Step 4 — 写 config.json
```bash
cd ~/.openclaw/workspace/skills/AutoACCT
cp config.example.json config.json
```
用编辑器打开 `config.json`,把 Step 4 拿到的 **sheet_id** 和 **worksheet**tab 名)填进去:
用编辑器打开 `config.json`,把 Step 3 拿到的 **sheet_id**(粘 URL 即可)和 **worksheet**tab 名)填进去:
```json
{
"sheet_id": "1abc...xyz",
"sheet_id": "https://docs.google.com/spreadsheets/d/1abc...xyz/edit",
"worksheet": "Sheet1",
"service_account_path": "~/.config/gcp/autoacct-sa.json",
"hkd_fx_provider": "frankfurter"
}
```
> ⚠️ **常见坑**:如果你的 Google Sheets 界面是中文,默认 tab 名是 `工作表1`**不是** `Sheet1`。必须写成 `"worksheet": "工作表1"`。tab 名不对会报 `HTTP 400: Unable to parse range`。
> **常见坑**:如果你的 Google Sheets 界面是中文,默认 tab 名是 `工作表1`**不是** `Sheet1`。必须写成 `"worksheet": "工作表1"`。tab 名不对会报 `HTTP 400: Unable to parse range`。
### Step 6 — 冒烟测试
### 冒烟测试
```bash
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
@@ -87,7 +81,15 @@ echo '{"date":"2026-04-20","merchant":"TEST","category":"Other","amount":1,"curr
看到 `OK 'Sheet1'!A2:N2`(或中文 tab 名)并且 sheet 第 2 行出现 TEST就全通了。完事记得把这行测试数据删掉。
遇到报错可以参考 [`scripts/setup.md`](scripts/setup.md) 的详细版
遇到报错可以参考 [`scripts/setup.md`](scripts/setup.md) 的故障排查
## 管理员一次性配置(你做一遍,再把 JSON 发给用户)
用户能跑上面 4 步之前,**你(管理员)**先建好一个共享的 service account把 JSON 发给用户。完整管理员指南见 [`scripts/setup.md`](scripts/setup.md),简版流程:
1. 建 GCP 项目 → 启用 Sheets API → 建 service account → 下载 JSON key
2. 通过安全渠道把 JSON 文件 + service-account 邮箱发给每个用户1Password / Bitwarden / 加密邮件 ——**绝不能 commit 到 git**
3. 让用户按上面 4 步装
## 使用
@@ -97,22 +99,17 @@ echo '{"date":"2026-04-20","merchant":"TEST","category":"Other","amount":1,"curr
## 文件结构
| 文件 | 作用 |
|------------------------|-----------------------------------------------|
| `SKILL.md` | 入口文件 — OpenClaw 读它来决定如何执行 skill |
| `categories.md` | 固定的 14 个分类列表 |
| `schema.md` | Google Sheet 列顺序AN |
| `config.example.json` | 配置模板 → 复制为 `config.json`(已 gitignore|
| `scripts/fx_convert.py`| 原币种 → HKD 换算frankfurter.app |
| `scripts/append_row.py`| 向 Google Sheet 写入一行 |
| `scripts/setup.md` | 一次性配置步骤 |
## Roadmap
- [ ] WhatsApp webhook 接入层Meta Cloud API 或 Twilio实现手机端直接发图记账
- [ ] 可选的 Google Drive 上传,让 `Receipt` 列直接变成可点的图片链接
- [ ] 月度汇总脚本(按分类、按币种统计)
| 文件 | 作用 |
|---------------------------|---------------------------------------------------|
| `SKILL.md` | 入口文件 — OpenClaw 读它来决定如何执行 skill |
| `categories.md` | 固定的 14 个分类列表 |
| `schema.md` | Google Sheet 列顺序AN |
| `config.example.json` | 配置模板 → 复制为 `config.json`(已 gitignore |
| `scripts/fx_convert.py` | 原币种 → HKD 换算frankfurter.app |
| `scripts/append_row.py` | 向 Google Sheet 写入一行 |
| `scripts/setup.md` | 管理员配置指南 + 故障排查 |
| `DEPLOY.md` | 面向非技术用户的逐步安装指南(英文) |
## License
私有 — 仅供内部使用。
[MIT](LICENSE) © 2026 Knowit

View File

@@ -13,7 +13,7 @@ Default working language: **English**. All written output (row values, replies)
- Caption may be empty, or may add context (who paid, split %, category hint, payment method). Always incorporate caption if present.
## Prerequisites (check once per session)
1. `~/.openclaw/workspace/skills/AutoACCT/config.json` exists. If only `config.example.json` is present, **stop** and tell the user to copy it and fill in `sheet_id`, `worksheet`, `service_account_path`. Point them at `scripts/setup.md`.
1. `~/.openclaw/workspace/skills/AutoACCT/config.json` exists. If only `config.example.json` is present, **stop** and tell the user to copy it and fill in `sheet_id`, `worksheet`, `service_account_path`. Point them at the README install section.
2. Python deps installed: `google-api-python-client`, `google-auth`. If `append_row.py` fails with ImportError, instruct the user to run `pip install google-api-python-client google-auth` and retry.
## Workflow

View File

@@ -1,6 +1,6 @@
{
"sheet_id": "PUT_GOOGLE_SHEET_ID_HERE",
"worksheet": "Expenses",
"sheet_id": "PASTE_YOUR_GOOGLE_SHEET_URL_OR_ID_HERE",
"worksheet": "Sheet1",
"service_account_path": "~/.config/gcp/autoacct-sa.json",
"hkd_fx_provider": "frankfurter"
}

View File

@@ -16,6 +16,7 @@ from __future__ import annotations
import json
import os
import re
import sys
from datetime import datetime, timezone
from pathlib import Path
@@ -26,6 +27,13 @@ from googleapiclient.discovery import build
CONFIG_PATH = Path(__file__).resolve().parent.parent / "config.json"
def normalize_sheet_id(value: str) -> str:
# Accept either a bare sheet ID or a full Google Sheets URL —
# e.g. https://docs.google.com/spreadsheets/d/<ID>/edit#gid=0.
m = re.search(r"/d/([a-zA-Z0-9_-]+)", value.strip())
return m.group(1) if m else value.strip()
COLUMNS = [
"date", "merchant", "category", "amount", "currency",
"amount_hkd", "fx_rate", "fx_date", "payment_method",
@@ -63,7 +71,7 @@ def main() -> int:
svc.spreadsheets()
.values()
.append(
spreadsheetId=cfg["sheet_id"],
spreadsheetId=normalize_sheet_id(cfg["sheet_id"]),
range=f"{cfg['worksheet']}!A1",
valueInputOption="USER_ENTERED",
insertDataOption="INSERT_ROWS",

View File

@@ -1,39 +1,102 @@
# One-time setup
# Admin setup + troubleshooting
## 1. Python deps
```
pip install google-api-python-client google-auth
```
End users follow the 4-step install in the main README (or the gentler [`DEPLOY.md`](../DEPLOY.md)). This page covers two things they don't see:
## 2. Google Cloud service account
1. Create (or reuse) a GCP project.
2. Enable the **Google Sheets API** for the project.
3. Create a **service account**; skip the optional IAM steps.
4. In the service account, create a **JSON key** and download it.
5. Move the key to a safe path, e.g. `~/.config/gcp/autoacct-sa.json`, then:
```
chmod 600 ~/.config/gcp/autoacct-sa.json
```
1. **Admin setup** — what you do once, before anyone can install
2. **Troubleshooting** — the errors users will report back to you
## 3. Prepare the Google Sheet
1. Create a new Google Sheet (or open an existing one).
2. Rename the first tab to `Expenses` (or update `worksheet` in config).
3. In row 1 add headers matching `schema.md` columns AN:
`Date | Merchant | Category | Amount | Currency | Amount (HKD) | FX Rate | FX Date | Payment Method | Line Items | Raw OCR | Note | Receipt | Logged At`
4. Open the service account JSON and copy the `client_email` value (looks like `...@...iam.gserviceaccount.com`).
5. Click **Share** on the sheet and add that email as **Editor**.
6. Copy the sheet ID from the URL: `https://docs.google.com/spreadsheets/d/<SHEET_ID>/edit`.
---
## 4. Skill config
```
cd ~/.openclaw/workspace/skills/AutoACCT
cp config.example.json config.json
# edit config.json: sheet_id, service_account_path
```
## Part A — Admin setup (one time)
## 5. 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"}' \
| python ~/.openclaw/workspace/skills/AutoACCT/scripts/append_row.py
```
You should see `OK Expenses!A2:N2` (or similar) and a new row in the sheet. Delete the TEST row when done.
The shared-key model: you create **one** Google Cloud service account and distribute its JSON key + email address to every user. Each user creates their own Google Sheet and shares it with that one service-account email. The service account can only write to sheets that have been explicitly shared with it.
### A.1 — Create the Google Cloud project + service account
1. Go to https://console.cloud.google.com/ and create a new project (e.g. `autoacct`).
2. In the top search bar, search **Google Sheets API** → click the result → **Enable**.
3. Left menu: **IAM & Admin → Service Accounts → + Create Service Account**.
- Name: `AutoACCT` (any name works)
- Click **Create and Continue → Done** (skip the optional IAM role step — the service account doesn't need any GCP roles, since it gains write access per-sheet via sheet-level sharing).
4. Click the new service account → **Keys** tab → **Add Key → Create new key → JSON → Create**.
A `.json` key file downloads to your browser's Downloads folder.
5. **Copy the service account's email** (e.g. `autoacct@<project>.iam.gserviceaccount.com`).
6. Rename the downloaded file to `autoacct-sa.json` (recommended — DEPLOY.md assumes this name).
### A.2 — Distribute the key + email to users
The JSON is a private key. Use a secure channel:
| Channel | Verdict |
|---|---|
| **Password manager shared vault** (1Password, Bitwarden, Vaultwarden) | **Recommended.** Easy to revoke, no copies floating in inboxes. |
| Encrypted email / Signal / private DM | OK for small teams. |
| Cloud drive with strict per-user ACLs | OK if your org already uses one. |
| **Plain email** | Do not. |
| **Git repo (even private)** | Do not — `.gitignore` already excludes `*-sa.json`. |
Tell each user:
- The JSON file (attach / share)
- The service-account email (so they know who to share their sheet with)
- Pointer to [`DEPLOY.md`](../DEPLOY.md) if they want hand-holding, or [`README.md`](../README.md) if they're comfortable with the terminal
### A.3 — Verify your own install first
Before sending the JSON to anyone, run through the user-side install yourself (Steps 111 of `DEPLOY.md`) to confirm everything works end-to-end. It's also a chance to catch any GCP-side misconfiguration before users hit it.
### A.4 — Key rotation (when you need to)
Rotate the JSON key when:
- A user leaves the team (so you stop trusting their copy of the key)
- You suspect a leak
- Every 612 months as routine hygiene
To rotate:
1. In GCP Console → Service Accounts → keys → **Add Key** (creates a new one) → download.
2. **Delete the old key** in the same panel. (After deletion, any existing copies stop working.)
3. Re-distribute the new JSON to all current users via your secure channel.
4. Users replace their `~/.config/gcp/autoacct-sa.json` with the new file. No other changes needed — `config.json`, sheet sharing, etc. all stay intact.
---
## Part B — Troubleshooting (user errors you'll see)
### `HTTP 403` / `The caller does not have permission`
The user forgot to share their sheet with the service-account email, or typed the email wrong. Tell them to re-do Step 8 in DEPLOY.md (or Step 3.5 in README.md). Confirm the email you sent them matches exactly.
### `HTTP 400: Unable to parse range`
The `worksheet` value in `config.json` doesn't match the actual tab name. Most common cause: user has Chinese Sheets UI → tab is `工作表1`, but they wrote `"worksheet": "Sheet1"`. Fix the config.
### `HTTP 404` / `Requested entity was not found`
`sheet_id` in `config.json` is wrong. Tell user to re-copy the long string from `/d/.../edit` in their browser's URL bar.
### `FileNotFoundError ... autoacct-sa.json`
The JSON file isn't where `config.json` expects. Common causes:
- User saved with a different filename (e.g. `autoacct-project-12345.json`) and never renamed it.
- User skipped the `mv` step and the file is still in Downloads.
Run `ls -la ~/.config/gcp/` to check.
### `ImportError: No module named 'googleapiclient'`
Python deps not installed. Run `pip install google-api-python-client google-auth`. If `pip` is missing, try `pip3` or `python3 -m pip install ...`.
### `config.json not found`
User skipped the `cp config.example.json config.json` step. They need to be inside the skill directory when running it.
### JSON parse error (`Expecting value` / `Extra data`)
Smart quotes from TextEdit, or a stray comma. Fix in plain-text mode, or have an AI agent repair the file.
### Authorization or quota errors at scale
The shared SA shares one GCP project's quota. The default Sheets API quota (300 req/min per project) is generous for receipts — you would have to log thousands per minute to hit it. If you do hit quota, request an increase in the GCP console.
---
## Part C — When to abandon the shared-key model
The shared-key model is right for **trusted internal teams** (you know everyone with a copy of the JSON). Move to a different model if any of these happen:
- **You're distributing to strangers / customers.** They can write to each other's sheets if the JSON leaks. Move to OAuth (each user authenticates with their own Google account).
- **You can't trust users to keep the JSON private.** Same answer.
- **You need per-user audit trails.** Sheets API logs only "the SA wrote" — you can't tell from GCP which user did it. (Sheet revision history still shows it, since each user has their own sheet.)
In those cases, see the git history for an earlier Apps Scriptbased variant, or design a small backend that holds the key server-side and exposes a per-user-authenticated endpoint.