achmadya.dev
Available
COMMAND PALETTE

Find something

10 resultsUse the links below to open a page
Projects
projectMandor PlateA reusable SaaS boilerplate with an API, dashboard, database, and tests in one monorepo.projectMCP QueryA suite of MCP servers for querying Excel and four databases over npx and stdio, with a small runtime and explicit error handling.
Writing
WritingRecording Personal Finances in a Spreadsheet with HermesHow I turn a transaction message into a structured Financial Planner entry with metadata, approval, and verification.WritingBuilding a Dedicated Workspace for Hermes to Work ReliablyHow I separated AI conversation from deterministic execution with a workspace, the kw CLI, skills, jobs, and an approval lifecycle.WritingHow I render Markdown and Mermaid in ReactThe rendering pipeline I use for safe Markdown, highlighted code, and responsive Mermaid diagrams.WritingDesigning an MCP tool call I can traceHow I separate protocol handling, database adapters, and public errors in a small MCP query server.WritingInstalling Hermes Agent and Understanding Its ArchitectureA complete guide to installing Hermes Agent and understanding profiles, skills, tools, gateway, schedules, Kanban, memory, and agent architecture.WritingA monorepo as a context boundary for AIWhat changed when I put contracts, backend, frontend, and tests in one workspace for AI-assisted development.WritingLearning Microsoft SQL Server and its backup mechanismNotes on learning Microsoft SQL Server through an online-store case: from containers and queries to recovery models, backup chains, and restore operations.WritingBuilding CCTV Live Streaming and Playback on the Web with FFmpegR&D notes on taking Hikvision video from RTSP to the browser, including H.265 transcoding, MPEG-TS, WebSocket delivery, and time-based playback.
~/writing / hermes-finance-spreadsheet-workflow

Recording Personal Finances in a Spreadsheet with Hermes

Hermespersonal financeGoogle Sheetsautomationworkflow

This article continues Building a Dedicated Workspace for Hermes to Work Reliably. The previous article explained why I separated Hermes from a deterministic execution plane. Here I apply the same pattern to a concrete workflow: recording transactions in a Financial Planner spreadsheet.

The problem is not only writing one row

Recording a transaction looks simple. I could open the spreadsheet, find an empty row, and enter an amount and description.

The problems appear when the same action is repeated:

  • category names need to stay consistent;
  • source and destination accounts must not be reversed;
  • a transfer must not become income or an expense;
  • a new receivable and its repayment need a clear relationship;
  • amounts and dates need one consistent format;
  • changes to an external spreadsheet need an audit path;
  • an agent must not treat an ambiguous message as permission to write.

I therefore do not make Hermes a free-form spreadsheet editor. Hermes understands the message and helps prepare the transaction. The workspace and CLI enforce the rules, request approval, perform the write, and read the result back.

How this relates to the Hermes workspace article

The architecture follows the same boundary described in the previous article:

Merender diagram...

Hermes handles conversation and routing. The CLI is a contract that can be called manually or by a scheduler. The spreadsheet remains the record, but it does not receive a direct prompt-driven write outside the lifecycle.

The input format I use

I do not need a long command format for every transaction. A natural-language message is usually enough when the required fields are clear.

For example:

Paid 35,000 for lunch from the main account

Or:

Received a freelance payment of 2,500,000 into the main account

The message does not immediately become a spreadsheet row. The agent first normalizes the intent and checks that required information is present.

When a transaction is ambiguous, I prefer a question over a guess. For example, if two accounts have similar names or a category cannot be mapped confidently, the workflow stops at the draft stage.

Metadata is read before every transaction

Account and category values are not a list to guess from conversational memory. Before creating a plan, the workflow reads the active Financial Planner metadata.

Conceptually, that metadata contains:

  • valid accounts;
  • valid categories;
  • cashflow rules;
  • other field choices required by the spreadsheet;
  • the active setup configuration.

The command is:

.venv/bin/kw finance metadata --json

The JSON output becomes the validation source. If the spreadsheet uses a different category name from the everyday phrase, the adapter maps it according to metadata instead of silently creating a new category.

This also protects the workflow from common personal-spreadsheet problems: one category appearing with several spellings, a destination account being written to the wrong field, or an old transaction using a value that is no longer valid.

Mapping intent to a cashflow rule

One transaction message should match one cashflow rule. I do not let one message become several cashflow types without an explicit decision.

Conceptually, a rule may represent types such as:

IntentExampleRequired clarity
ExpensePaying for lunchamount, category, source account
IncomeReceiving a paymentamount, category, destination account
TransferMoving money between accountssource and destination accounts
New receivableLending moneyamount, category, source account, person
Receivable repaymentSomeone pays a debtoriginal receivable and destination account

The actual rule names and available fields still come from live metadata. This table describes the reasoning, not a replacement for the spreadsheet configuration.

The difference between source and destination accounts matters. For an expense, money leaves the From Account. For income, money enters the To Account. For a transfer, both sides are required and the transaction must not be counted as new income.

From a message to a frozen payload

After metadata and the rule match, the workflow creates a plan. The plan stores the payload that will be used if I approve the transaction.

A conceptual payload looks like this:

{
  "cashflow_type": "expense",
  "date": "2026-08-04",
  "description": "Lunch",
  "amount": 35000,
  "category": "<category-from-live-metadata>",
  "from_account": "<account-from-live-metadata>",
  "to_account": null
}

The account and category values are intentionally not real data in this example. In an actual execution, those values must come from the active setup metadata.

The payload is then frozen with an action ID and hash. After approval, the workflow does not rebuild the transaction from the conversation context. It executes the same payload.

The plan, approve, execute, verify lifecycle

This is the part of the workspace design I preserve:

metadata
  → normalize intent
  → match one cashflow rule
  → plan frozen payload
  → show fields for review
  → explicit approval
  → execute spreadsheet write
  → read-back verification

1. Metadata

The workflow retrieves current account, category, and rule choices.

2. Normalize intent

The natural-language message becomes structured fields: cashflow type, date, description, amount, and the relevant account fields.

3. Plan

The CLI creates a durable action. The payload, hash, and action ID are stored before the external write.

4. Review

I see a summary of the transaction that will be recorded. I use bullets so it remains easy to review from Telegram or a mobile device:

Type: Expense
Date: 2026-08-04
Description: Lunch
Amount: Rp35,000
Category: <from metadata>
From Account: <from metadata>

5. Approval

Words such as ok or approve count as approval only when the context is unambiguous. If there are multiple drafts or an uncertain field, the workflow does not guess which transaction was intended.

6. Execute

The approved action executes with the frozen payload. No field is silently changed between approval and execution.

7. Verify

The adapter reads the result back or checks the evidence returned by the spreadsheet. Completion is reported only when both the action and verification succeed.

Why not call the Google Sheets API directly?

Technically, an agent could call the Google Sheets API directly. That approach mixes several responsibilities:

  • the prompt starts defining spreadsheet structure;
  • category validation becomes inconsistent;
  • approval is reduced to a sentence in the conversation;
  • retries and verification are easy to skip;
  • changes are difficult to reproduce from logs.

With a CLI, Hermes only needs a small contract. The skill routes the conversation to the finance command, while the workspace implementation handles metadata, payloads, the spreadsheet adapter, and verification.

Hermes skill
      → kw finance metadata
      → kw finance plan
      → explicit approval
      → kw action execute
      → verified transaction result

The skill stays thin. It explains when to use the workflow and which rules matter, but it does not store transaction business logic inside a prompt.

A special case: receivable repayment

I do not record a receivable repayment as ordinary income. The workflow first needs to find the matching original receivable.

For example:

Andi paid back 500,000 into the main account

If exactly one matching new-receivable transaction exists, the workflow can map it as follows:

  • use the receivable repayment type;
  • inherit the category from the original receivable;
  • use the receiving account as the destination account;
  • preserve the relationship with the original transaction.

If there is no single match, the workflow asks for clarification. Recording it as general income just because money arrived would damage the history and cashflow analysis.

What this design gives me

The spreadsheet stays simple for a human, while the surrounding process has clear boundaries:

  • Hermes understands the message;
  • metadata keeps choices valid;
  • rules distinguish income, expense, transfers, and receivables;
  • a plan makes the change reviewable;
  • approval prevents an unauthorized write;
  • the adapter handles spreadsheet details;
  • verification confirms that the record was actually saved.

This is not an attempt to make finance tracking more complicated. The goal is to move complexity from an inconsistent conversation into a workflow that can be tested.

Boundaries and security

A finance workflow should not treat a spreadsheet as a safe place for everything. I keep several boundaries:

  • spreadsheet IDs and credentials never enter the repository;
  • OAuth tokens stay in local secret storage;
  • transaction data is not sent to public channels;
  • confirmations do not show combined balances unless requested;
  • read-only commands are separated from external writes;
  • approval cannot be skipped because a scheduler or agent thinks the transaction looks obvious.

For operations originating from email, an import job creates only a draft or pending_review state. Email detection does not automatically become a recorded transaction.

Closing thoughts

Financial recording is a small example of the principle from the Hermes workspace article: an agent can be flexible when understanding a goal, but external execution needs a contract, state, approval, and evidence.

With this pattern, I can write a transaction message naturally without turning the spreadsheet into an experiment area. Hermes helps me speak to the system. The CLI and adapter ensure that the Financial Planner rules are followed.

metadata
published
2026-08-04
topic
Hermespersonal financeGoogle Sheetsautomationworkflow
read time
5 min
Related