record-expenses-to-google-sheets
Read every receipt file (PDFs and images) from a local folder, extract merchant/description/total via PDF text parsing + Gemini, and append one row per…
Skill by prakhar1114
Chalk Labs
Need help deploying record-expenses-to-google-sheets?
Chalk Labs sets up agents like this inside real teams: connected to your tools, tested on your data, with a human in the loop where it matters.
Install
Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.
npx agentmarket install skill/prakhar1114-record-expenses-to-google-sheets
Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.
Get the weekly diff
The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.
About
Use cases: documents, spreadsheets
Reviews
Write a reviewNo reviews yet. Installed it? Reviews come from verified installers only. How reviews work
Permissions
What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.
- Tools
- No tools found
- Secrets
- None asked for
- Install scripts
- None found
- Runs as
- Python package
Network hosts it talks to 1
codeload.github.com· found in install command
Files it touches
~/.claude/skills/record-expenses-to-google-sheets
What's inside
- Skill name
record-expenses-to-google-sheets- Description
- Read every receipt file (PDFs and images) from a local folder, extract merchant/description/total via PDF text parsing + Gemini, and append one row per receipt to a fixed Expenses Google Sheet (Idx / Description / Cost) at the bottom. Never deduplicates — every run appends every receipt currently in the folder.
- License
- MIT
- Instructions
- 109 lines in SKILL.md · view on GitHub
Before installing
- Ships executable scripts
- Instructions call the network
Agent Skills spec issues
- body: contains an absolute path from the author's machine
Files (7)
- SKILL.md
- inputs.example.json · inputs/
- inputs.template.json · inputs/
- fallback_plan.md · references/
- requirements.txt
- run.sh
- run.py · scripts/
SKILL.md (first lines)
# record-expenses-to-google-sheets
End-to-end automation that turns a folder of receipts into rows in a Google Sheet.
The target sheet URL is hardcoded inside `scripts/run.py` as `EXPENSES_SHEET_URL` (constant, not an input). The user's Chrome must already be signed into the Google account that owns the sheet — the skill drives that Chrome via the `browser` skill / `browser-harness`. No OAuth or API key needed.
## Inputs
`scripts/run.py --inputs-json <file>` expects JSON like:
```json
{ "receipts_folder_path": "/Users/prakharjain/Desktop/expenses" }
```
- `receipts_folder_path` (string, required): absolute path to the folder containing receipts. Every file directly in the folder with one of these extensions is processed (case-insensitive): `.pdf .png .jpg .jpeg .heic .webp .tiff .gif`. Subfolders and `.DS_Store` are ignored.
## Run
```bash
./run.sh # uses inputs/inputs.example.json
./run.sh inputs/inputs.template.json
./run.sh /abs/path/to/inputs.json
```
`run.sh` is self-bootstrapping: on first run it creates a virtual env at
`.venv/` (next to `run.sh`) and installs `requirements.txt` (just
`pdfplumber`) into it, then runs `scripts/run.py` with that interpreter. On
later runs it reuses the venv, only reinstalling if `pdfplumber` is missing.
The venv is gitignored — delete `.venv/` to force a clean rebuild. `python3`
must be on `$PATH` to create the venv.
Per-receipt pipeline:
1. **Enumerate** — `os.listdir` the folder, filter by extension, sort, absolute paths.
2. **Extract** —
- PDFs: `pdfplumber.extract_text()` per page, joined; the text is sent to Gemini with a JSON schema.
- HEIC images: converted to JPG via macOS-native `sips -s format jpeg <in> --out <tmp.jpg>` (Gemini rejects `.heic` directly). Other image types go to Gemini as-is.
- Gemini is reached by shelling out to `browser-harness -c '<python>'` and importing `ask_llm` from `browser_harness.helpers` (so the host Python doesn't need any vision deps). The structured response is `{merchant, description, item_price, total_paid}`.
3. **Append** — opens `EXPENSES_SHEET_URL` in a new Chrome tab, reads the existing sheet via `fetch("/spreadsheets/d/<ID>/gviz/tq?tqx=out:csv&gid=0", {credentials:"include"})` from the page's own origin (cookies authenticate), computes `next_idx = max(existing Idx values) + 1` and `next_row = last non-empty row + 1`. It then jumps to A`next_row` by clicking the Name Box and typing the address, and dispatches a synthetic `ClipboardEvent("paste")` carrying a TSV string in `text/plain` only (`text/html` collapses tabs → must be omitted). Sheets accepts the paste and writes Idx / Description / Cost across the new rows.
Re-runs always append — the skill does NOT deduplicate. Two runs against the same folder produce two sets of rows. To get distinct descriptions for receipts of the same product across billing periods, the Gemini prompt asks for the date or billing period in the description (e.g. `Claude Pro subscription (May 16 - Jun 16, 2026)`).
External tools required at run time:
- `python3` on `$PATH` to create the `.venv`. `pdfplumber` is installed automatically into `.venv/` from `requirements.txt` by `run.sh` (no manual `pip install` needed). If you invoke `scripts/run.py` directly instead of via `run.sh`, use `.venv/bin/python` or otherwise ensure `pdfplumber` is importable.
- `browser-harness` on `$PATH` (used both for Gemini calls and for driving Chrome). Install with `uv tool install -e /path/to/browser-harness` if not already present. Its dependencies are intentionally NOT in `requirements.txt` — it runs as a separate subprocess with its own environment.
- `sips` (macOS-built-in; required only when the folder contains `.heic` files).
- A Chrome window the user is already signed into the target Google account in. The skill connects via CDP; it does not log in for the user.
## Outputs
- Side effect: new rows appended to the Expenses Google Sheet (Idx / Description / Cost). The skill writes nothing to local disk besides progress logs on stderr.
- Programmatic result: the last `workflow_done` event on stderr carries `outputs.appended_rows` — one object per appended row with `idx`, `description`, `cost`, `source_file`.
## Progress log format
Every step transition is one JSON object per line on stderr:
- `{"event":"step_start","id":"<step_id>","title":"…"}`
- `{"event":"step_done","id":"<step_id>","outputs":{…},"summary":"…"}`
- `{"event":"step_failed","id":"<step_id>","error":"…","recoverable":true|false}` (process exits non-zero immediately after)
- `{"event":"workflow_done","outputs":{…}}`
Free-form `print` lines may be interleaved.
Step IDs in order: `enumerate_receipt_files`, `extract_receipt_fields`, `append_expense_rows_in_sheet`.
## Fallback
See `references/fallback_plan.md`. If `scripts/run.py` fails, the recorded UI flow (open Finder → open PDF in Preview → launch Chrome via Spotlight → open the bookmarked sheet → type Idx / Description / Cost) is enough for a human or `macos-computer-use` agent to finish the task.
Common automated failure modes and their handling:
- **Gemini schema rejection** — Gemini rejects nullable union types (`"type":["string","null"]`). The script uses non-nullable types and instructs the model to emit `0` / `""` instead. If schemas are tightened later, keep this constraint.
- **PDF without a text layer** — `pdfplumber.extract_text()` returns `""`. Currently the prompt still goes to Gemini with empty text and Gemini will guess; that's the wrong behavior. Future improvement: detect empty text and route the PDF through `pdftoppm` → JPG → image prompt instead.
- **Chrome not signed in / wrong account** — the `fetch` to gviz returns a Google login HTML page rather than CSV. The script will treat it as a parse failure. Fallback: ask the user to sign into Chrome with the right account; then re-run.
- **`browser-harness` not on PATH** — `subprocess.run(["browser-harness", ...])` raises `FileNotFoundError`. Install per the Run section above.
## ask_llm decision points
The skill makes exactly one Gemini call per receipt, in `extract_record()`:
- For PDFs: prompt is `GEMINI_TEXT_PROMPT + <extracted text>`, no image.
- For images: prompt is `GEMINI_IMAGE_PROMPT`, with the image file path (HEIC → JPG via `sips` first).
In both cases the JSON schema is:
```json
{
"type": "object",
"properties": {
"merchant": {"type": "string"},
"description": {"type": "string"},
"item_price": {"type": "number"},
"total_paid": {"type": "number"}
},
"required": ["merchant", "description", "item_price", "total_paid"]
}
```
The prompt explicitly requests that `description` include the date or billing period when present so that successive bills from the same merchant are distinguishable in the sheet.
## References
- `references/fallback_plan.md` — full human / `macos-computer-use` fallback playbook.
- `EXPENSES_SHEET_URL` and `SHEET_ID` constants in `scripts/run.py` — the only sheet-specific configuration. Replace both to point at a different sheet.From prakhar1114/ai_mime_marketplace, MIT.
More from prakhar1114/ai_mime_marketplace
- 0.529score
fetch-linkedin-message-threads
prakhar1114
Fetch recent LinkedIn Messaging thread URLs, contact names, last-message timestamps, and unread/new status from the user's already logged-in Chrome session.
SkillBFreshness: BClaude Code +9 - 0.529score
fetch-linkedin-message-history
prakhar1114
Fetch read-only LinkedIn message history from the user's logged-in browser for either a LinkedIn messaging thread URL or a LinkedIn profile URL.
SkillBFreshness: BClaude Code +9 - 0.529score
send-message-on-linkedin
prakhar1114
Send a message on LinkedIn from the user's logged-in Chrome session, given either a LinkedIn messaging thread URL or a LinkedIn profile URL plus the message…
SkillBFreshness: BClaude Code +9 - 0.529score
linkedin-search-people
prakhar1114
Search LinkedIn people results in the user's already logged-in Chrome browser and return structured profile-card data.
SkillBFreshness: BClaude Code +9 - 0.518score
send_connection_request
prakhar1114
Send one LinkedIn connection request from a profile URL using the user's logged-in browser session, optionally adding a custom note, and report whether it was…
SkillBFreshness: BClaude Code +9 - 0.479score
order-grocery-on-blinkit
prakhar1114
Add grocery items to the Blinkit (blinkit.com) cart using the user's already-logged-in Chrome.
SkillCFreshness: CClaude Code +9 - 0.479score
jira-get-fields
prakhar1114
Fetch Jira Cloud issue fields through Jira REST API v3 and return a compact, cleaned JSON payload.
SkillCFreshness: CClaude Code +9 - 0.479score
jira-update-fields
prakhar1114
Update a Jira Cloud ticket field using Jira REST API v3.
SkillCFreshness: CClaude Code +9 - 0.479score
reply-on-x
prakhar1114
Reply to an X post or comment from the user's already logged-in Chrome session using browser-harness, and return the posted reply URL.
SkillCFreshness: CClaude Code +9 - 0.479score
send-slack-message
prakhar1114
Post a message to a Slack channel using a Slack bot token via the Slack Web API, and return a clickable permalink to the posted message.
SkillCFreshness: CClaude Code +9 - 0.476score
subreddit-search
prakhar1114
Scrape top Reddit posts from a subreddit in Chrome, optionally filtered by a search query, and return title, URL, upvotes, comments, and body text.
SkillCFreshness: CClaude Code +9 - 0.476score
facebook-data-extractor
prakhar1114
Extract visible posts from a Facebook group for the last N days using the AI Mime browser harness and an existing logged-in Facebook Chrome session.
SkillCFreshness: CClaude Code +9
Signals
- Stars
- 0
- Forks
- 0
- Open issues
- 0
- Last commit (this folder)
- Jun 17, 2026 (4 months ago)
From GitHub (fetched Oct 24, 2026).
Details
- License
- MIT
- First seen
- Oct 24, 2026
- Last checked
- Oct 24, 2026
- Source
- GitHubgithub-graphql
More from prakhar1114
- 0.529score
fetch-linkedin-message-history
prakhar1114
Fetch read-only LinkedIn message history from the user's logged-in browser for either a LinkedIn messaging thread URL or a LinkedIn profile URL.
SkillBFreshness: BClaude Code +9 - 0.529score
send-message-on-linkedin
prakhar1114
Send a message on LinkedIn from the user's logged-in Chrome session, given either a LinkedIn messaging thread URL or a LinkedIn profile URL plus the message…
SkillBFreshness: BClaude Code +9 - 0.529score
fetch-linkedin-message-threads
prakhar1114
Fetch recent LinkedIn Messaging thread URLs, contact names, last-message timestamps, and unread/new status from the user's already logged-in Chrome session.
SkillBFreshness: BClaude Code +9 - 0.529score
linkedin-search-people
prakhar1114
Search LinkedIn people results in the user's already logged-in Chrome browser and return structured profile-card data.
SkillBFreshness: BClaude Code +9 - 0.518score
send_connection_request
prakhar1114
Send one LinkedIn connection request from a profile URL using the user's logged-in browser session, optionally adding a custom note, and report whether it was…
SkillBFreshness: BClaude Code +9 - 0.479score
jira-get-fields
prakhar1114
Fetch Jira Cloud issue fields through Jira REST API v3 and return a compact, cleaned JSON payload.
SkillCFreshness: CClaude Code +9
Done for you
Rather not set it up yourself?
Chalk Labs scopes, builds and runs agents for your team: the task audit, the eval harness, the integrations and the weekly ops report. Fixed scope, priced before we start.
See how we build AI agents →Read the case studies
Chalk Labs is a two-founder AI and growth studio. We build AI agents, CRMs and MVPs for Web3 and AI companies, and have shipped 50+ product and token launches.
- launches shipped
- 50+
- launches shipped
- media placements
- 500+
- media placements
- founders on every account
- 2
- founders on every account
Press we've placed: Forbes · CoinDesk · Decrypt · Cointelegraph · The Block
Rahil Jain, Co-founder, Chalk Labs. Ex-Goldman Sachs engineer. You talk to the person who builds it.
Get record-expenses-to-google-sheets running in your business
Tell us what you want to automate. A founder replies within one working day with a plan, not a pitch deck.
Cite this page
record-expenses-to-google-sheets skill. Agent Mart. https://agentmart.dev/skills/prakhar1114-record-expenses-to-google-sheets (last updated 2026-10-24)