The books agent
Each weekday morning this agent enters new bills and reconciles yesterday's transactions. A bill with every line under $1,000 posts without approval. Larger bills need an accountant's approval in Slack. Payroll calls are denied.
Requires Intuit's QuickBooks MCP server, built on the daemon's machine, and a Slack app.
The files
Section titled “The files”org: acme
mcp: quickbooks: command: node args: [/opt/quickbooks-online-mcp-server/dist/index.js] trusted: true env: QUICKBOOKS_CLIENT_ID: ${QUICKBOOKS_CLIENT_ID} QUICKBOOKS_CLIENT_SECRET: ${QUICKBOOKS_CLIENT_SECRET} QUICKBOOKS_REFRESH_TOKEN: ${QUICKBOOKS_REFRESH_TOKEN} QUICKBOOKS_REALM_ID: ${QUICKBOOKS_REALM_ID} QUICKBOOKS_ENVIRONMENT: production
channels: slack: type: slack token: ${SLACK_BOT_TOKEN} signing_secret: ${SLACK_SIGNING_SECRET} members: {U024BE7LH: user:acme/@maria, U0G9QF9C6: user:acme/@sam}
notify: targets: accounting: {channel: slack, room: "#accounting"}
roles: accountant: rules: [{verbs: [ask, read, events, decide], kinds: [agent], names: [books]}]bindings: - {org: acme, role: accountant, subjects: [user:acme/@maria, user:acme/@sam]}trusted: truemarks the server's results as trusted, not content from outside. Without it, every bill would need approval.- The
accountantrole allows@mariaand@samto message the agent and approve its calls.
allow: - quickbooks/search_* - quickbooks/get* - quickbooks/create-bill(params.bill.Line.Amount < 1000)ask: quickbooks/create-bill(params.bill.Line.Amount >= 1000): A bill with a line of $1,000 or more. quickbooks/create_invoice: This creates a customer invoice.deny: quickbooks/create-bill(params.bill.Line.AccountBasedExpenseLineDetail.AccountRef.value = 88): Payroll is off limits. quickbooks/create_bill_payment: Paying bills is for people.budget: {usd: 10.00, per: day, on_exhausted: ask}- On a list argument,
allowmatches only when every item matches.denymatches when any does. 88is a placeholder for your Payroll account ID in QuickBooks.
---description: Keeps the books for the accounting team.tools: [quickbooks/*, files]context: [VENDORS.md]channels: [slack]policy: booksnotify: {to: [accounting], on: [parked, failed, finished]}triggers: - name: close every: "0 7 * * 1-5" prompt: Reconcile yesterday's transactions, and enter the bills that came in.---You keep Acme's books in QuickBooks. Enter each bill against the right vendor and expense account.VENDORS.md says which account each vendor's bills go to; keep it current as the accountants correctyou. When you aren't sure, ask in one line. Each morning, post a short summary.Try it
Section titled “Try it”echo "$QUICKBOOKS_CLIENT_ID" | wardrik vault put QUICKBOOKS_CLIENT_ID --for api_key# ...and the other QuickBooks keys, the Slack token and signing secretsystemctl --user restart wardrikwardrik ask books 'Enter the March invoice from Northwind Freight: $640 for deliveries.'It looks up the vendor and posts the bill. A $2,400 bill is posted to #accounting for approval,
with the bill's lines as arguments.
What it shows
Section titled “What it shows”- Policy rules on call arguments: amounts and account IDs. See Policy.
- A
denythat no prompt can bypass. - Approvals in Slack, each recorded with the approver.
- Corrections are written to
VENDORS.mdand loaded into the next turn.