Accounting Integration Skills #
Classification: Internal-Only
One Claude Code command covers every accounting-provider job, from a brand-new connector to adding one missing document type:
research integration for <Provider>
The accounting-integration skill behind it first checks what already exists for the provider, then runs the right track through the same five phases: research, plan, implement, test, release. The skills live in .claude/skills/ and are available in any Claude Code session started in the repo.
What gets built #
- Publish AP bills, AR invoices and direct expenses. Bank statements too, when the provider’s API can take them; when it can’t, the research brief records why and the work ships without them.
- Read only what publish and the AI features need: catalogs (accounts, items, tax rates, tags, locations, currencies), contacts with contact write-back, and document reads. Publish uses the detail read to check a document’s status before deleting or republishing it; Hinoki knowledge setup and self-prompt use the history reads.
- No import. Syncing provider documents into tofu is no longer a product feature (the Import button and auto-import were removed in #5269), so no track builds it.
How the skill picks a track #
Step 0 reads the code: the provider’s arm in IntegrationProvider::capabilities(), the bank statement arm of supports_publish_for_type(), whether the connector’s read and publish methods are real or stubs, and what .plans/<slug>/ already holds.
| What the code shows | Track | What runs |
|---|---|---|
| no connector | A | read-only research and publish research in one pass, then read-only implementation followed by publish on the same branch |
| a read-only connector | B | publish only: AP, AR, DE, and BS if possible |
| publishes, but some types are missing | C | only the missing types, usually bank statements |
| publishes all four types | D | nothing; it reports the support matrix |
On 2026-09-28 the providers mapped onto the tracks like this. The skill re-detects on every run, so trust its Step 0 over this table.
| Providers | State | Track |
|---|---|---|
| MYOB, AutoCount, Dynamics 365 Business Central, Odoo, FreeAgent, Jaz, NetSuite | read-only | B |
| Sage, Bukku, Money Forward, QuickBooks Online | publish AP/AR/DE, no bank statements | C |
| Xero, freee, Zoho Books | publish all four | D |
| any provider without a connector | none | A |
Before anything starts, Claude shows what it found and asks you to confirm the track, the types (default AP + AR + DE, BS if possible), and the integration branch.
Phases and stops #
| Phase | Track A (new provider) | Track B (publish only) | Track C (missing types) |
|---|---|---|---|
| 1. Research | readonly-research-integration-research-tasks, then publish-integration-research in new-provider mode with publish-integration-error-research alongside; publish-integration-validator-combinations runs once the error catalog is written |
publish-integration-research and publish-integration-error-research in parallel, then publish-integration-validator-combinations |
publish-integration-research for the missing types, plus the error research and validator combinations if AP, AR or DE is among them |
| Stop 1: you review | both briefs, the publish error catalog, the resources Claude asks for, the decisions | the error catalog and the decisions | same as B |
| 2. Plan | readonly-integration-plans workflow (one plan per 3.x task), then the publish plan |
the publish plan | the publish plan |
| Stop 2: you approve | plans, branch, release shape | plan | plan |
| 3. Implement | read-only waves (readonly-integration-implement), then publish P0–P5 and PV, the tofu validator (publish-integration-orchestrator), on the same branch |
publish P0–P5 and PV | the missing type’s task |
| 4. Test | readonly-research-review on 3.x PRs, the publish-integration-testing checklist on P PRs, then the whole branch and the manual test |
publish-integration-testing and the manual test |
same, scoped |
| Stop 3: you check | support matrix and manual-test log | same | same |
| 5. Release | one PR to main, release notes once |
same | same |
Claude marks each approved file (the briefs and the error catalog at Stop 1, the plan at Stop 2, the manual-test log at Stop 3) with a Status: APPROVED <date> line, and the plan’s header records the track and the branch. Those are how a later session knows where to resume, even after the code on the branch has changed, so you can close the session at any stop and come back with:
continue integration for <Provider>
The skills behind it #
| Skill | Role |
|---|---|
accounting-integration |
entry point: detects the state, picks the track, runs the phases |
readonly-research-integration-research-tasks |
track A research: the read-only brief, plus the publish brief in the same pass |
readonly-integration-plans (workflow) |
track A plans: one per read-only task 3.0–3.6, each reading the publish brief’s read-side requirements |
readonly-integration-implement |
track A read-only waves, then hands over to publish on the same branch |
readonly-research-* (per task) and readonly-research-review |
the read-only task manuals and their review gate |
publish-integration-orchestrator |
the publish track: decisions, the publish plan (P0–P5), implementation waves, release |
publish-integration-research |
the publish brief, with a decision table per document type |
publish-integration-error-research |
the publish error catalog: every way the provider rejects an AP bill, AR invoice or direct expense, sorted by the layer that must catch it |
publish-integration-validator-combinations |
the errors that only appear when two or more values meet, probed in the sandbox and added to the catalog |
publish-integration-implement |
the publish implementation manual, with one reference file per task |
publish-integration-testing |
tests, the publish review checklist, and the manual test guide |
The publish implementation skill’s reference files are read by Claude when needed; you don’t call them directly:
.claude/skills/publish-integration-implement/references/
├── foundation.md # capabilities, policy, scopes, error keys, HTTP helpers, auto-publish, docs
├── invoice-shared.md # what AP and AR share: validate/upload, merge-back, status, delete
├── ap-bill.md # AP bill specifics
├── ar-invoice.md # AR invoice specifics
├── direct-expense.md # direct expense specifics
├── bank-statement.md # bank statement (runs synchronously in bonsapi)
├── tofu-validator.md # task PV: the provider's rules in tofu-validator-core, run live in the review form
├── attachments.md # attachment upload, linking, limits
├── journal-based-providers.md # providers with journals only (Money Forward style)
└── webapp.md # deep links, status labels, gates, contact fields
Before you start #
- A sandbox company for the provider, or a test company you’re allowed to write to. Some providers (Money Forward) have none; then every test document must be cleaned up afterwards.
- Write access: write scopes on the provider’s OAuth app, or a write-enabled API key. The integration-account owner registers scopes on the provider’s portal.
- A working local environment:
mise run dev, and the provider credentials in.config.yaml(see Configuration File).
Walkthrough: MYOB (track B, read-only → publish) #
The Claude replies below are illustrative; the real wording will differ.
1. Start #
you › research integration for MYOB
claude › MYOB: variant Myob, module myob, slug myob.
State: read-only. The capabilities arm has no .with_publish();
fetch_invoice, fetch_direct_expense and create_contact are implemented;
no .plans/myob/publish/ yet; no open MYOB branch.
Track B: publish only. Confirm:
1. Types: AP bill, AR invoice, direct expense, bank statement if possible?
2. Branch: <you>/eng-XXXX-myob-publish?
you › yes, yes
2. Research #
Claude runs publish-integration-research. It reads the MYOB write API and the existing accounting/myob/ connector, and writes .plans/myob/publish/<date>-myob-publish-research.md with:
- a field-mapping table per type (tofu field → MYOB field, required or not, the error key if missing);
- the bank statement verdict: in scope, or not possible with the evidence;
- the error keys users will see (for example
errorMessage.myob.BILL_NUMBER_REQUIRED); - webapp impact (deep-link URL per type, status labels);
- Decisions for the user, and a NEEDS CONFIRMATION list.
If MYOB’s docs are incomplete, drop sample request/response JSON or screenshots into .plans/myob/resources/; the research treats them as ground truth.
3. Plan (Stop 1 and Stop 2) #
Claude asks the decisions that change behaviour for customers:
claude › 5 decisions need you:
1. Republish: MYOB can update bills in place. Update in place,
or delete-then-create like the other providers?
2. A bill paid in MYOB: block republish with a message?
3. Auto-publish off on first connect?
4. Direct expense: Spend only, or Receive too?
5. MYOB is already live read-only: existing connections must
reconnect for the write scopes. Reset their auto-publish flags
when publish ships?
you › 1 update in place, 2 yes, 3 yes, 4 Spend only, 5 yes
Claude records the answers in the brief, then writes the publish plan, .plans/myob/publish/<date>-myob-publish-plan.md: the target support matrix and one section per task (P0 foundation, P1 invoices, P2 direct expense, P3 bank statement if in scope, P4 webapp, P5 docs), each with its files, error keys, decisions, tests and done-criteria. Nothing is coded until you approve the plan.
4. Implement #
- P0 foundation, alone first. Capabilities (
.with_publish()), write scopes and the reconnect message, error keys plus translations, HTTP write helpers, the attachment size limit, auto-publish off on first connect, and stubs for every publish method. Thenmise run ci, the review checklist, and a PR into the integration branch. - P1–P5, parallel agents (one worktree each, each opening a PR into the integration branch): invoices (AP and AR together, because they share the write model), direct expense, bank statement (if in scope), webapp (deep links, status labels, removing the read-only banner and Early badge), docs (the internal publish section, plus the user-facing guide or help-center article if MYOB has one).
Each agent reports back with a PR link, what it verified in the sandbox, and what still needs a live check. Working alone without agents? Tell Claude “do it sequentially on one branch”; the order stays the same.
5. Test (Stop 3) #
Claude fills test gaps (write-model JSON tests, every error-mapping arm, status mapping, webapp deep-link tests), runs mise run ci and the publish review checklist over the whole branch, then walks you through publish-integration-testing/references/manual-testing.md:
- connect, and check auto-publish is off;
- publish an AP bill, AR invoice and direct expense; open each “View in MYOB” link and check totals match to the cent;
- edit and republish; mark a bill paid in MYOB and confirm republish is refused;
- delete in tofu; check error messages are translated (switch the UI to Japanese);
- check the database through the
tofu-internal-mcpexecute_sqltool.
Results go into .plans/myob/publish/<date>-myob-publish-manual-test.md. Clean up every test document in MYOB afterwards.
6. Release #
Claude writes the release notes once, on the integration branch → main PR, one per affected project (bonsapi, bonsai-accounting-sync, webapp), each 150 characters or fewer, and opens the PR with the submit-github-pr skill. The description lists the support matrix, your decisions, the reconnect note for the new scopes, and anything still untested.
Track A: a provider with no connector #
The same command starts it. What differs from track B:
- Research writes two briefs in one pass:
.plans/<slug>/<date>-<slug>-phase1-research.md(API, auth, regions, per-object coverage, test data, readiness verdict, task list 3.0–3.6 plus P0–P5) and the publish brief, whose section 11 lists what each read-only task must deliver for publish (write scopes, payment state in the detail read, account flags the write endpoints accept, contact fields). - Write scopes are requested from day one (tasks 3.0 and 3.1), so no customer ever reconnects for publish.
- Plans: the
readonly-integration-plansworkflow writes one plan per read-only task, then Claude writes the publish plan, which also fixes the order of the read-only tasks. - Implementation order: the read-only waves (3.1 first, then 3.0/3.4/3.5/3.6, then 3.2.x, then 3.3) on branch X, then P0–P5 on the same X. The docs tasks 3.5 and 3.6 describe the read side; P5 adds publishing to them once it exists.
- Release shape (you choose at Stop 2): by default read-only and publish ship together in one PR to
main. If read-only should go live earlier, X goes tomainafter the read-only waves, and publish continues as track B. - The manual test adds a read-side section (pickers, contact creation, CSV export, heartbeat) before the publish checks.
Track C: adding bank statements to a provider that publishes #
you › research integration for Sage
claude › Sage publishes AP/AR/DE; bank statements are not enabled.
Track C: research bank statement publish for Sage?
The research answers one question first: can the provider’s API take a bank statement (a statement import, one transaction per line, or a bank feed)? If not, the brief records “not possible” with the evidence, Claude offers to note the verdict in the provider’s internal doc so nobody researches it again, and the job ends there. If it can, the plan is a single bank statement task plus the small shared changes it needs (the gate in both supports_publish_for_type and the webapp’s supportsPublishForType, error keys), followed by the bank statement parts of the checklist and the manual test.
Running one step on its own #
Each skill still works alone:
| You want to… | Type |
|---|---|
| write only the publish research brief | /publish-integration-research myob |
| implement one publish type (needs the approved brief and plan) | /publish-integration-implement implement AP bill publish for myob |
| fix a publish bug in an existing connector | describe the bug, e.g. Zoho bank statement publish sends split children, fix it; the implement skill loads the matching reference |
| review your changes against the publish checklist | /publish-integration-testing review my diff |
| review a teammate’s PR | /publish-integration-testing review PR #<number> |
| walk through the manual test | /publish-integration-testing how do I manually test myob publish |
| review a read-only task diff | /readonly-research-review |
Where files end up #
| Path | What |
|---|---|
.plans/<slug>/<date>-<slug>-phase1-research.md |
track A read-only brief, readiness verdict and task list |
.plans/<slug>/<date>-<slug>-<task>-plan.md |
track A read-only task plans |
.plans/<slug>/publish/<date>-<slug>-publish-research.md |
publish brief and decisions |
.plans/<slug>/publish/<date>-<slug>-publish-plan.md |
publish plan (P0–P5), and in track A the order of the read-only tasks |
.plans/<slug>/publish/<date>-<slug>-publish-manual-test.md |
manual test log |
.plans/<slug>/resources/ |
provider samples you supply |
libs/rust/bonsai-integration/src/accounting/<module>/ |
connector code: mod.rs, model/*_write.rs, model/error.rs |
libs/rust/bonsai-model/src/integration.rs |
capabilities and publish policy |
apps/webapp/src/shared/utils/integration.ts |
deep links, status labels, bank statement gate |
config/i18n/en/error.json, config/i18n/en/webapp.json |
error and status label strings (other locales generated with mise run i18n) |
docs/internal/content/docs/integrations/<provider>.md |
the provider’s publish documentation |
Everything under .plans/ is gitignored. <slug> is the connector module with _ replaced by - (money_forward → money-forward).
Tips #
- Answer every decision before implementation starts; a guessed decision usually means reverted code.
- Read the precedent connectors’ code (
sage/,freee/,bukku/,zoho/,money_forward/), not their PR descriptions; several PR descriptions no longer match what shipped. - Keep concurrent Rust agents to about three; parallel
cargobuilds slow the machine down. - To change how the skills behave, edit the files in
.claude/skills/. Each rule lives in one file; the others point to it.