# Happydebits agent guide

Happydebits tracks recurring charges (subscriptions and other burns) in a **local-first** ledger. Humans and agents share one contract: schema-valid **action proposals**. The browser validates, previews burn impact, and applies only after confirm.

## Mental model

- **Ledger** = currency + subscriptions (ids, name, amount, interval, status, …).
- **Proposal** = add / update / set_status / delete actions with message, assumptions, optional clarifyingQuestion.
- **Pairing** = short-lived bridge so MCP/HTTP agents can read the ledger and park proposals without clipboard paste.
- **Confirm** = human-only write path. Agents must not assume apply succeeded.

## Onboarding (AgentMail-style)

1. Human opens `/agents` → **Start pairing**.
2. Copy MCP JSON (pairId + **agentSecret** + base URL) into Cursor/Claude MCP config. The device secret stays in the browser.
3. Run `node mcp/happydebits-mcp.mjs` via that config (repo checkout) or point HTTP tools at the pair API.
4. Agent calls `get_ledger` / `list_charges`, then `propose_actions`. Agents cannot confirm, dismiss, overwrite the ledger, or end the pair.
5. Human clicks **Review** on `/agents` (or import flow), confirms, optional undo.

Also read `/llms.txt` and `/llms-full.txt`. Schemas: `/ledger-action.schema.json`, `/ledger.schema.json`.

## Proposal shape (v1)

```json
{
  "version": 1,
  "message": "Pause the gym membership.",
  "clarifyingQuestion": null,
  "assumptions": [],
  "actions": [
    {
      "type": "set_status",
      "targetId": "exact-id-from-ledger",
      "targetName": "Gym",
      "status": "paused",
      "subscription": null,
      "changes": null,
      "confidence": 1,
      "reason": "User asked to pause this charge."
    }
  ]
}
```

### Action types

| type | needs | notes |
|---|---|---|
| `add` | `subscription` object | no targetId/changes/status |
| `update` | target + `changes` | patch fields only |
| `set_status` | target + `status` | active \| paused \| cancelled |
| `delete` | target | only when user explicitly wants delete; UI requires ack |

## Pair HTTP

Auth: `Authorization: Bearer <secret>` or `x-happydebits-pair-secret`.

Errors are stable JSON: `{ ok:false, code, message, hint, retryable }`.

Idempotency: pass `clientRequestId` on `POST .../proposal`. Retries with the same id return the same pending proposal (`deduped: true`).

Sessions expire (~30 minutes). Upstash Redis is used when configured; otherwise in-memory (fine for local `next dev`).

## MCP tools

- `get_ledger` — read paired snapshot
- `list_charges` — filter charges
- `propose_actions` — park proposal (never applies)
- `get_proposal` — list proposal status

Server entry: `mcp/happydebits-mcp.mjs`.

## Safety

- Do not log full ledgers to third parties.
- Do not auto-apply deletes/cancels.
- `/api/interpret` is optional NL→proposal for the human UI; MCP agents should build proposals directly from tools + schema when possible.
