Automated summary
Logs a naturally described expense into a personal Google Sheet through a Google Apps Script web app, after extracting the date, amount, category, description and payment method.
Strengths
- Natural-language extraction into fixed fields, with sensible defaults (today's date, card payment).
- A one-line confirmation before writing, so a misread expense isn't silently recorded.
- Self-contained one-time setup: the sheet headers and the doGet/doPost Apps Script code are provided in full.
- On failure it quotes the tool's error word for word instead of paraphrasing it or faking success.
Limitations
- Requires manually deploying an Apps Script web app with 'Anyone' access and storing its URL as a secret.
- Depends on a `run_js` tool and secret handling of the host environment, so it won't work as-is elsewhere.
- Fixed category and payment lists, append-only rows: no editing, deleting, reporting or multi-currency handling.
Use it when you want to record an expense in your Google Sheet without opening it, just by describing it.
Avoid it if you need to edit or delete entries, handle multiple currencies, or can't deploy a Google Apps Script.
Security analysis
CautionThe skill is not malicious: it does not exfiltrate secrets to an attacker, run destructive commands, or obfuscate actions. However, it handles a sensitive user secret and instructs deploying a publicly writable Google Apps Script webhook, so it warrants caution rather than being classified safe.
- •The user's Google Apps Script Web App URL is used as a bearer-style secret; because the deployment instructions require access set to 'Anyone', anyone who obtains the URL can append rows to the sheet.
- •Expense details are sent to an external Google Apps Script endpoint controlled by the user; this is legitimate but still external network data flow.
- •The Apps Script `doPost` handler performs no authentication or payload validation beyond JSON parsing, so any request to the URL can write arbitrary row data.
- •The skill instructs calling `run_js` even though no allowed-tools are declared, which may rely on host-specific tool permissions.
Examples
Log €12.50 for lunch at the ramen place, paid by card.Add an expense of 40 to my sheet: Health, pharmacy, yesterday, cash.Track 9.99 for a streaming subscription under Bills — just log it, no need to confirm.name: expense-tracker description: Log an expense to your Google Sheet by describing it naturally. metadata: require-secret: true require-secret-description: Paste your Google Apps Script Web App URL here. See the skill instructions for setup steps. homepage: https://github.com/Sprayer115/expense-tracker-skill
Expense Tracker
Log expenses to your personal Google Sheet just by describing them. The skill extracts the relevant details and appends a new row automatically.
Secret
The secret is your Google Apps Script Web App URL. See the setup section below for how to get it.
Instructions
You are an expense logging assistant. When the user describes an expense (or asks to log one), extract the following fields:
- date: The expense date in YYYY-MM-DD format. Default to today's date if not mentioned.
- amount: A numeric value (e.g. 12.50). Ask if unclear.
- category: One of: Food, Transport, Shopping, Health, Entertainment, Bills, Other. Infer from context.
- description: A short description of what was purchased/spent on.
- payment_method: One of: Cash, Card, PayPal, Bank Transfer, Other. Default to Card if not mentioned.
Before submitting, briefly confirm the details with the user in a single line (e.g. "Logging: 2026-04-08 | €12.50 | Food | Groceries at Rewe | Card — correct?").
Once confirmed (or if the user says to just log it), call run_js with:
- script_name:
index.html - data: a JSON string with the fields above, e.g.:
{"date":"2026-04-08","amount":12.50,"category":"Food","description":"Groceries at Rewe","payment_method":"Card"}
After the tool returns:
- If
resultis present: tell the user the expense was logged successfully, showing the logged details. - If
erroris present: tell the user exactly what the error says, word for word. Do not paraphrase or suggest setup steps — just quote the error directly.
Setup
You need to do a one-time setup to connect this skill to your Google Sheet.
Step 1 — Prepare your Google Sheet
Open your Google Sheet and make sure the first row has these headers (in this order):
| Date | Amount | Category | Description | Payment Method | Logged At |
Step 2 — Deploy the Apps Script
- In your Google Sheet: Extensions → Apps Script
- Delete any existing code and paste in the following:
// Health check — open the Web App URL in a browser to verify it's deployed
function doGet(e) {
return ContentService
.createTextOutput(JSON.stringify({ status: "Expense Tracker is running" }))
.setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
try {
var raw = e.postData.contents;
var data = JSON.parse(raw);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
sheet.appendRow([
data.date,
data.amount,
data.category,
data.description,
data.payment_method,
new Date().toISOString()
]);
return ContentService
.createTextOutput(JSON.stringify({ result: "ok" }))
.setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return ContentService
.createTextOutput(JSON.stringify({ error: err.message }))
.setMimeType(ContentService.MimeType.JSON);
}
}
- Click Deploy → New deployment
- Type: Web app
- Execute as: Me
- Who has access: Anyone
- Click Deploy and copy the Web App URL
Step 3 — Set the secret in Google AI Edge Gallery
When prompted for the secret in the app, paste the Web App URL you copied above.
Testing the webhook
Step 1 — Browser health check
Open your Web App URL directly in a browser. You should see:
{"status":"Expense Tracker is running"}
If you see a Google login page or 403, re-check the deployment settings (Access must be Anyone).
Step 2 — POST test with curl
curl -s -L 'YOUR_WEB_APP_URL' -H 'Content-Type: application/json' -d '{"date":"2026-04-08","amount":9.99,"category":"Food","description":"Test coffee","payment_method":"Card"}'
Expected response: {"result":"ok"}
Important: Do not add
-X POSTto the curl command. Apps Script URLs return a 302 redirect; curl handles it correctly when using-dalone (POST on first request, GET on redirect). Adding-X POSTforces POST on the redirect too — but without a body — causing a411 Length Requirederror.
From the file to a first result
The download contains exactly the content displayed on this page. This copy may differ from the latest version in the source repository.
View the source and supporting filesThis download contains SKILL.md only. Any scripts, references, templates and dependencies are not included. Get the required files from the source, preserving their directory structure, before continuing.
1. Download the file
Download SKILL.mdFrom the root of a test project, save the file as .skill-downloads/expense-tracker-via-google-sheets-ms2s7coq/SKILL.md, or use the command below. This folder is for inspecting the skill before installation.
Command for macOS/Linux or WSL: requires a POSIX shell and curl. On Windows without WSL, use the download button and create the folder manually.
mkdir -p '.skill-downloads/expense-tracker-via-google-sheets-ms2s7coq' && curl --fail --show-error --location 'https://skills-guides.com/api/skills/expense-tracker-via-google-sheets-ms2s7coq/download' --output '.skill-downloads/expense-tracker-via-google-sheets-ms2s7coq/SKILL.md.part' && mv '.skill-downloads/expense-tracker-via-google-sheets-ms2s7coq/SKILL.md.part' '.skill-downloads/expense-tracker-via-google-sheets-ms2s7coq/SKILL.md'2. Check prerequisites
Read SKILL.md before using it. If it references scripts or external services, inspect them and prepare the required access in your test environment.
Original excerpt: Setup
You need to do a one-time setup to connect this skill to your Google Sheet.
Step 1 — Prepare your Google Sheet
Open your Google Sheet and make sure the first row has these headers (in this order):
| Date | Amount | Category | Description | Payment Method | Logged At |
Step 2 — Deploy the Apps Script
- In your Google Sheet: Extensions → Apps Script
- Delete any existing code and paste in the following:
// Health check — open the Web App URL in a browser to verify it's deployed
function doGet(e) {
return ContentService
.createTextOutput(JSON.stringify({ status: "Expense Tracker is running" }))
.setMimeType(ContentService.MimeType.JSON);
}
function doPost(e) {
try {
var raw = e.postData.contents;
var data = JSON.parse(raw);
var sheet = SpreadsheetApp.getActiveSpreadsheet().getActiveSheet();
sheet.appendRow([
data.date,
data.amount,
data.category,
data.description,
data.payment_method,
new Date().toISOString()
]);
return ContentService
.createTextOutput(JSON.stringify({ result: "ok" }))
.setMimeType(ContentService.MimeType.JSON);
} catch (err) {
return ContentService
.createTextOutput(JSON.stringify({ error: err.message }))
.setMimeType(ContentService.MimeType.JSON);
}
}
- Click Deploy → New deployment
- Type: Web app
- Execute as: Me
- Who has access: Anyone
- Click Deploy and copy the Web App URL
Step 3 — Set the secret in Google AI Edge Gallery
When prompted for the secret in the app, paste the Web App URL you copied above.
Testing the webhook
Step 1 — Browser health check
Open your Web App URL directly in a browser. You should see:
{"status":"Expense Tracker is running"}
If you see a Google login page or 403, re-check the deployment settings (Access must be Anyone).
Step 2 — POST test with curl
curl -s -L 'YOUR_WEB_APP_URL' -H 'Content-Type: application/json' -d '{"date":"2026-04-08","amount":9.99,"category":"Food","description":"Test coffee","payment_method":"Card"}'
Expected response: {"result":"ok"}
Important: Do not add
-X POSTto the curl command. Apps Script URLs return a 302 redirect; curl handles it correctly when using-dalone (POST on first request, GET on redirect). Adding-X POSTforces POST on the redirect too — but without a body — causing a411 Length Requirederror.
The platforms on this page are catalog indications. The paths below follow tool documentation; they do not prove this skill has been run in those tools. No minimum tool version is confirmed for this listing.
3. Load the skill
After inspection, copy the complete folder into your project using one of the commands below, then open a new tool session. The command stops if a folder with the same name already exists: compare the files before replacing it.
Claude Code
test -f '.skill-downloads/expense-tracker-via-google-sheets-ms2s7coq/SKILL.md' && test -s '.skill-downloads/expense-tracker-via-google-sheets-ms2s7coq/SKILL.md' && mkdir -p '.claude/skills' && test ! -e '.claude/skills/expense-tracker' && cp -R '.skill-downloads/expense-tracker-via-google-sheets-ms2s7coq' '.claude/skills/expense-tracker'OpenSkills
OpenSkills must already be installed. The local install/read procedure is checked with OpenSkills 1.5.0, which requires Node.js ≥ 20.6.0. Catalog slugs are not resolved automatically.
Official OpenSkills installationopenskills install './.skill-downloads/expense-tracker-via-google-sheets-ms2s7coq'openskills read 'expense-tracker-via-google-sheets-ms2s7coq'Reading should display the installed file content and its base directory. It does not run the skill or install its dependencies.
For an agent that reads AGENTS.md, then sync the index. This command changes AGENTS.md: review the diff before using it.
openskills syncManual method or another tool: attach SKILL.md to a conversation, or open it in an agent that can read files. Include any required supporting resources. No universal folder is recognized by every tool.
4. Try a first task
Use a short, synthetic input: an API endpoint, a small document or an interface brief. In a new conversation, attach the file or give the agent its path, then adapt this request:
Read .skill-downloads/expense-tracker-via-google-sheets-ms2s7coq/SKILL.md and apply its instructions to this example: [describe a test input]. Identify any missing files, dependencies or access. Produce the result requested by the skill without inventing data or running unreviewed scripts.Expected result: output matching the skill instructions, or a precise list of missing prerequisites. A read confirmation alone does not validate a first use. If an external resource is unavailable, that path remains untested.
PDF Reader
Productivity
Read and extract text from PDF files, including documents, reports, contracts, and spreadsheets. Works with local files, URLs, and WhatsApp attachments. Use whenever PDF content is needed, even if not explicitly requested.
Discord Messaging Workflows
Productivity
Use the message tool to send, edit, and moderate Discord messages with interactive components.
Interactive Verdict Preview
Productivity
Generate an interactive HTML preview of keep/drop verdicts for maintainer review, then process the pasted feedback JSON.