---
name: dura
description: Use when a person asks you to read or record household cash in Dura (envelopes, spends, cash-ins, IOUs, receipts, loans from the piggy) or their savings group (mukando). Runs the dura CLI or the Dura API with their token.
---

# Dura for AI agents

Dura (https://dura.muchiround.com) is a shared cash-envelope budget for households. You are acting for one member of a household, with their API token. Everything you record shows up live on their partner's phone, so be accurate and say what you did.

## Setup (once)

1. The person creates a token in Dura: Settings, Your account, Apps and agents, Create a token. They give it to you through a secret store or an environment variable, never in a chat message you repeat back.
2. If you can run shell commands, install the CLI (Ruby 3.2+, no gems):

       mkdir -p ~/.local/bin && curl -fsSL https://dura.muchiround.com/cli/dura -o ~/.local/bin/dura && chmod +x ~/.local/bin/dura
       export DURA_TOKEN=...   # or: dura login --token -   (reads the token from stdin)

   Otherwise call the API directly: base URL `https://dura.muchiround.com/api/v1`, header `Authorization: Bearer $DURA_TOKEN`.
3. Check it works: `dura --json whoami` (API: `GET /me`). If the person is in more than one household, ask which one and run `dura use "<name>"`. A household marked `"private": true` is the person's own private pocket: only use it when they ask for it, and never mention it to anyone else.

## Before you write anything

- Read the table first: `dura --json table` (API: `GET /households/:id`). It has every envelope's id, name, balance, monthly budget and what's been spent this month, plus the IOUs.
- Amounts are in the household's currency, not cents: `74.99` means seventy-four ninety-nine. Responses give `*_cents` integers and a display string; quote the display string to the person.
- Refer to envelopes by id in API calls. In the CLI, a unique part of the name works (3+ letters); ambiguous names are refused on purpose.
- If you aren't sure which envelope something belongs to, or whether something was already recorded, ask. Money mistakes are worse than a question.

## Recording

| Job | CLI | API |
|---|---|---|
| A spend | `dura spend groceries 74.99 "Peanut butter"` | `POST /households/:id/spends {envelope_id, amount, note}` |
| Paid with another envelope's cash (makes an IOU) | `--from transport` | `paid_from_envelope_id` |
| A spend on an earlier day | `--date 2026-10-08` | `occurred_at` |
| Money swapped to cash and shared out | `dura cash-in 200 --electronic 210 --source payoneer --split groceries=120 --split piggy=80` | `POST /households/:id/cash_ins {cash, electronic, funding_source_id, splits}` |
| Move notes between envelopes | `dura move groceries school 10` | `POST /households/:id/moves` |
| Square up an IOU | `dura settle airtime transport` | `POST /households/:id/settlements` |
| Count the real cash | `dura count gas 10 --reason lost` | `POST /households/:id/cash_counts` |
| Fix a spend's amount or note | `dura edit 18 --amount 70.50` | `PATCH /households/:id/entries/18` (the id changes) |
| Pay a member their allowance (cash lands in their private pocket) | `dura allowance kuda 25 --from fun` | `POST /households/:id/allowances {member_id, amount, envelope_id}` |
| Put the envelopes in a new order (same for everyone; list them all, not the piggy) | `dura envelopes order gas groceries transport airtime` | `PUT /households/:id/envelopes/order {envelope_ids}` (`409 arrangement_stale`: re-read and retry) |
| Group envelopes into named sections (same for everyone) | `dura groups add Bills`, then `dura envelopes edit rent --group bills` | `POST /households/:id/envelope_groups {name}`, then `PATCH /households/:id/envelopes/:eid {group_id}` |
| Reorder groups, or delete one (its envelopes stay, ungrouped) | `dura groups order bills kids fun`, `dura groups delete bills` | `PUT /households/:id/envelope_groups/order {groups, ungrouped_envelope_ids}`, `DELETE /households/:id/envelope_groups/:gid` |
| Ask to borrow from the piggy (another member must approve) | `dura loans ask 2000 --months 12 Phone` (`--joint --into groceries` for the household) | `POST /households/:id/loans {kind, amount, months, purpose}` |
| Approve, decline or cancel a loan request | `dura loans approve phone` | `POST /households/:id/loans/:lid/approve` (`/decline`, `/cancel`) |
| Repay a loan | `dura loans repay phone`, or on payday `dura cash-in 600 --split groceries=500 --repay phone=100` | `POST /households/:id/loans/:lid/repay {amount, from_envelope_id}`, or `repayments` on a cash-in |
| Skip a month, new plan, forgive | `dura loans skip phone`, `dura loans reschedule phone 6`, `dura loans forgive phone 200` | `POST /households/:id/loans/:lid/skip` (`/reschedule {months}`, `/forgive {amount}`) |
| Undo anything | `dura undo 22` | `POST /households/:id/entries/22/reverse` |
| A receipt photo or PDF | `dura scan slip.jpg --wait`, check, then `dura confirm 12` | `POST /households/:id/receipt_scans`, then `POST .../confirm` |

## House rules

1. **One write per real event.** Give every write an idempotency key derived from the event, so a retry can't double-record it: `dura --idempotency-key "receipt-<hash>-line-3" spend ...` (API: header `Idempotency-Key`). The same key with a different request is refused.
2. **Report back** each write's `summary` and the envelope's new balance from the response. Don't do the arithmetic yourself.
3. **Undo, don't delete.** Entries are immutable. If you got one wrong, undo it and record it again, then tell the person both entry numbers.
4. **Receipts:** nothing is deducted until you confirm. Show the person the lines and suggested envelopes first unless they've told you to confirm on their behalf.
5. **Errors** come back as `{"error": {"code", "message"}}` (CLI: exit code 1, JSON on stdout). The message is written for people; pass it on. `ledger_error` means Dura refused the change, so nothing was written.
6. **Loans:** never approve, forgive or set an interest rate on your own initiative; those are the person's decisions. Don't suggest a rate. When you describe a loan, give `money_lent`, `amount_paid_to_borrower` and `interest_rate_flat` together, with `annual_equivalent`.
7. **Savings groups (mukando) are people's decisions.** Never confirm or dispute an entry, accept or decline a turn swap, accept the keeper's book, record a write-off or finalise a share-out on your own initiative. Show the person what is waiting (`dura --json mukando waiting`) and act only on her answer for that one entry. See "Savings groups" below.
8. **Keep the token secret.** Never print it, log it, commit it or paste it into a chat. If it leaks, the person revokes it from the same Apps and agents list.

## Reading

- `dura --json entries --envelope groceries --month 2026-10` lists activity (API: `GET /households/:id/entries`, filters `envelope_id`, `kind`, `month`, `since`, `until`, `page`, `per_page`).
- `dura --json month 2026-09` gives budget vs spent per envelope.
- `dura --json ious` shows which envelope owes which.
- `dura --json loans` lists loans from the piggy (`GET /households/:id/loans`); `dura --json loan phone` has the plan and history.

## Savings groups (mukando)

A savings group keeps its own book, apart from any household: never copy a group's money into household envelopes or the other way round. Its members are first names and member ids; the book is the group's, so use it only to answer the person you work for. Don't send other members' records anywhere else, post them, or keep them after the task. Pick the group with `--group ID|NAME` when she is in more than one (API: `GET /mukando/groups`). Every answer carries `meta.records_only`: Dura keeps the records and never holds or moves the money; say so if asked.

| Job | CLI | API |
|---|---|---|
| Her groups, this month, her position | `dura --json mukando`, `dura --json mukando show`, `dura --json mukando position` | `GET /mukando/groups`, `GET /mukando/groups/:gid`, `GET /mukando/groups/:gid/position` |
| The payout order, the book, the places, the loans | `dura --json mukando rotation`, `dura --json mukando book`, `dura --json mukando places`, `dura --json mukando loans` | `GET /mukando/groups/:gid/rotation`, `GET /mukando/groups/:gid/entries`, `GET /mukando/groups/:gid/locations`, `GET /mukando/groups/:gid/loans` |
| What's waiting for her to confirm | `dura --json mukando waiting` | `GET /mukando/confirmations` |
| Confirm or dispute, only with her answer for that entry | `dura mukando confirm 17`, `dura mukando dispute 17 "I paid $100"` | `POST /mukando/confirmations/:id/confirm` (`/dispute {note}`) |
| Keeper: record a payment in, the pot paid out, a handover | `dura mukando record contribution tsitsi --month 1 --into "chipo cash"`, `dura mukando record payout --month 1 --from "chipo cash"`, `dura mukando record handover 200 --from "chipo cash" --to ecocash` | `POST /mukando/groups/:gid/entries {kind, ...}` |
| Keeper: a pool loan (check first) and its repayments | `dura mukando record loan rudo 60 --from "chipo cash" --check`, then without `--check`; `dura mukando record repayment rudo 20 --into "chipo cash"` | `POST /mukando/groups/:gid/entries {kind: "loan", dry_run: true, ...}` |
| Keeper: put a wrong entry right | `dura mukando reverse 41 --note "Wrong amount"`, then record it again | `POST /mukando/groups/:gid/entries/:id/reverse` |

- Only the keeper records; anyone else gets `403 keeper_only`. Refusals are `422 mukando_error` with a message for people; pass it on.
- An entry counts once everyone it involves confirms it. Report `status` and `waiting_on` from the response; never call waiting money confirmed.
- Pool loans: show `money_lent`, `amount_paid_to_borrower` and `interest_rate_flat` together with `annual_equivalent`, and `rate_warning` word for word when it is there. Never suggest a charge: it is the group's rule, set when the cycle starts. Describe loans factually (what was lent, what is left, by when); never press anyone to pay.
- Starting a group, inviting, joining, starting a cycle, leaving and exporting records happen in the app, by the person herself.

Full docs: https://dura.muchiround.com/developers/api and https://dura.muchiround.com/developers/cli. Recipes (grocery run, weekly check-in, month end, importing history): https://dura.muchiround.com/developers/recipes.
