From the fourth E2E run: the agent correctly refused to reproduce a 104 KB SIE file token by token (silent mid-verifikat truncation) and dead-ended to the web wizard, and its replies were walls of compliance prose. 1. gnubok_create_sie_upload: signed same-origin upload URL (reuses the pending-document infra; .se/.sie/.si only, 50 MB HTTP cap). gnubok_sie_preflight and gnubok_import_sie accept upload_id as the byte-exact source, plus optional sha256 (hex of the raw bytes) verified on the upload_id/base64 paths so truncation is DETECTED, never silent. Inline content above 120k chars is refused with a pointer to the upload flow. Scope bookkeeping:write (same intent as import_sie). 2. Skill: brevity rule (max ~8 short lines per reply, one warning per step, no legal essays), memory-first rule (check what is already known before asking the opening questions), the upload-first SIE step, and gnubok_explain_voucher_gap after import for skipped voucher numbers. 3. CONNECTORS.md starter prompt rewritten memory-first so it stays copy-paste ready without the user's own data in it. Plugin v1.2.2. tools/list ceiling 62K to 62.4K documented in the bench. Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com> Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
188 lines
9.6 KiB
TypeScript
188 lines
9.6 KiB
TypeScript
import type { Skill } from './types'
|
|
|
|
const body = `# Onboarding: set up a company in Accounted from the conversation
|
|
|
|
From "my company is not in Accounted yet" to a working ledger without the
|
|
user opening the web app first. The only browser steps are the ones that
|
|
legally need a human with BankID: connecting (creating the account),
|
|
approving the bank consent, and authorising Skatteverket. Everything else
|
|
happens here.
|
|
|
|
**Momentum rule: one confirmation, then keep going.** The only stop in this
|
|
flow is the create-company preview ("stämmer detta? ja"). Never end a turn
|
|
with "säg till när du vill fortsätta": after the confirm, call the connect
|
|
tools immediately; when the user reports a connection done, verify it and
|
|
continue straight into import or categorization. Staged writes still go
|
|
through their normal approval, but that approval IS the conversation, not an
|
|
extra pause around it.
|
|
|
|
**Brevity rule: this is onboarding, not a course.** Keep every reply under
|
|
~8 short lines. At most ONE warning per step, one line, and only when it
|
|
changes what the user should do right now. No legal essays, no deadline
|
|
tables, no cross-checks the user did not ask about (bolagsstämma dates,
|
|
EU-moms edge cases, K-regelverk). The user can always ask for depth; the
|
|
flow must never make them scroll past it.
|
|
|
|
**Memory first.** Before asking the opening questions, check what you
|
|
already know about the user (memory, earlier conversation): orgnr, company
|
|
name, bank, previous system. Ask only for what is genuinely missing.
|
|
|
|
## When to use
|
|
|
|
- "Sätt upp bokföring för mitt AB / min enskilda firma"
|
|
- "Jag har precis startat bolag, hur kommer jag igång?"
|
|
- "Lägg till ett nytt bolag" (an existing user adding a second company)
|
|
- A byrå/consultant onboarding a new client company (pass \`team_id\`)
|
|
|
|
## Step 0: connect
|
|
|
|
If this session is not connected yet, the first company-scoped call (for
|
|
example \`gnubok_create_company\`) returns an authentication challenge that the
|
|
client shows as a Connect prompt. Tell the user: "Klicka på Connect; har du
|
|
inget konto skapar du det där (BankID eller e-post), det tar en minut." The
|
|
call is retried automatically once connected. Do not send the user to the web
|
|
app to sign up first.
|
|
|
|
## Step 1: THREE opening questions, then look up
|
|
|
|
Open with exactly three questions, together:
|
|
|
|
1. **Organisationsnummer?** (10 digits; an enskild firma's org number is the
|
|
owner's personnummer, fine to use here)
|
|
2. **Har du bokfört i ett annat system tidigare?** (Fortnox, Visma, Bokio,
|
|
Björn Lundén, Briox, Wint, annat system, eller helt nytt bolag)
|
|
3. **Vilken bank har företaget?** (so the bank connect link later opens that
|
|
bank's consent directly instead of a picker)
|
|
|
|
Then call \`gnubok_lookup_company\` with the org number. The registry answers
|
|
most of the form; present the facts as a SHORT summary to confirm ("Jag
|
|
hittade Example AB, Storgatan 1 i Stockholm, godkänd för F-skatt och
|
|
momsregistrerad. Stämmer det?") and ask ONLY what \`still_to_ask\` lists.
|
|
Never re-ask what the registry answered.
|
|
|
|
Rules baked into that split (same as the web onboarding):
|
|
|
|
- **F-skatt** from the registry is a fact, both true and false.
|
|
- **VAT** is a fact ONLY when positively registered. "No VAT registration
|
|
found" is a question, never an assumption (ML 17 kap 24 §).
|
|
- **Moms period** is ALWAYS the user's answer when VAT-registered. Rules of
|
|
thumb if unsure: under 1 MSEK turnover may report VAT yearly, under 40
|
|
MSEK quarterly, above monthly.
|
|
- **Accounting method is NOT a question**: it defaults by form (AB =
|
|
faktureringsmetoden, enskild firma = kontantmetoden) and the preview
|
|
flags the default. Name it in the readback ("faktureringsmetoden,
|
|
standard för AB, säg till om du vill ha kontantmetoden") so the user can
|
|
override in the same "ja". Cash requires turnover under 3 MSEK.
|
|
- **Enskild firma name**: verksamhetsnamnet is freely choosable; suggest the
|
|
registered name but let the user pick. An AB's registered name is a fact.
|
|
- **Fiscal year**: registry data becomes a confirm question, never an open
|
|
one. No closed period in the registry = FIRST räkenskapsår: suggest a
|
|
start at the registration date. The end differs by form: an enskild
|
|
firma MUST end 31 December; an AB may pick any end within 18 months of
|
|
the start (BFL 3 kap 3 §), with 31 December as the common default, so
|
|
present the AB's choice rather than assuming it.
|
|
|
|
\`not_found\`/\`unavailable\`: fall back to asking the \`still_to_ask\` list and
|
|
continue. Only \`aktiebolag\` and \`enskild_firma\` are supported today.
|
|
|
|
## Step 2: preview, ONE confirm, create, keep moving
|
|
|
|
Call \`gnubok_create_company\` WITHOUT \`confirm\`. Read the preview back in
|
|
plain Swedish (form, orgnr, fiscal period dates, VAT + period, method).
|
|
After the user's "ja": call it again with \`confirm: true\`, and in the SAME
|
|
turn continue with step 3 or 4. Creation sets up chart, settings, first
|
|
fiscal period, tax deadlines, and starts the 30-day trial; the connection
|
|
uses the new company automatically.
|
|
|
|
## Step 3 (existing bookkeeping): import it FIRST
|
|
|
|
When the user had a previous system, history comes before the bank: it is
|
|
the fastest path to a ledger that shows real value, and bank history rarely
|
|
reaches far enough back anyway.
|
|
|
|
1. Tell them where to export: **Fortnox** Register → Exportera → SIE 4,
|
|
**Visma eEkonomi** Bokföring → Export SIE, **Bokio** Inställningar →
|
|
Exportera data → SIE, **Björn Lundén / Briox / Wint** under Export.
|
|
Every Swedish system exports SIE4 (.se/.sie); ask them to attach the
|
|
file here in the chat.
|
|
2. When the file arrives, get its BYTES to the server without retyping
|
|
them. Preferred (and REQUIRED for anything beyond a small file): call
|
|
\`gnubok_create_sie_upload\`, PUT the raw file bytes to the returned
|
|
\`upload_url\` (from your code sandbox when you have one), compute the
|
|
file's sha256, then call \`gnubok_sie_preflight\` with \`upload_id\` +
|
|
\`sha256\` + the same \`filename\`. Small files may go inline
|
|
(\`file_content_base64\` + \`sha256\` preferred over plain
|
|
\`file_content\`). NEVER reproduce a large file token by token: the
|
|
tools refuse oversized inline content because a mid-verifikat
|
|
truncation imports silently incomplete bookkeeping.
|
|
3. Summarize the preflight in a few lines: source system, fiscal years,
|
|
verifikat count, balance status, org-number match, the one warning that
|
|
matters. On the user's go-ahead: \`gnubok_import_sie\` with the same
|
|
source (\`upload_id\` or content) and the preflight's \`mappings\`. It
|
|
stages for approval; after commit verify with
|
|
\`gnubok_get_trial_balance\`, and explain any skipped voucher numbers
|
|
with \`gnubok_explain_voucher_gap\` (BFNAR 2013:2; an unexplained gap
|
|
blocks year-end).
|
|
4. Multiple fiscal years = multiple files: import oldest first so IB/UB
|
|
chains. The web wizard at \`/import?mode=sie\` is the fallback when no
|
|
upload path works; Fortnox users can also run the full API migration
|
|
(invoices, customers, documents) at
|
|
\`/import?mode=migration&provider=fortnox\`.
|
|
|
|
## Step 4: connect bank and Skatteverket (together, no pause)
|
|
|
|
Call \`gnubok_connect_bank\` (pass \`bank\` from step 1 so the link opens that
|
|
bank's consent directly) AND \`gnubok_connect_skatteverket\` in the same
|
|
turn; on claude.ai/Desktop both render connect cards with buttons.
|
|
|
|
- Bank: BankID + PSD2 consent, then an **account selection dialog** in the
|
|
browser: transactions start syncing when the user saves it. Banks cap
|
|
PSD2 history (often ~90 days); older history is the SIE import's job.
|
|
- Skatteverket: BankID as firmatecknare; enables skattekonto sync and
|
|
moms/AGI filing. Optional, never block on it.
|
|
|
|
When the user says they are done (or comes back), re-call
|
|
\`gnubok_connect_bank\` to verify \`connected\`, then go DIRECTLY to step 5.
|
|
|
|
## Step 5: first bookkeeping, immediately
|
|
|
|
Call \`gnubok_list_uncategorized_transactions\` as soon as the bank is
|
|
connected: do not ask whether to proceed. Walk the categorize flow
|
|
(\`gnubok_suggest_categories\`, \`gnubok_categorize_transaction\`, approval).
|
|
If nothing has synced yet, say so and check again on the user's next
|
|
message instead of making them ask.
|
|
|
|
## Tools
|
|
|
|
- \`gnubok_lookup_company\`: registry facts + prefill from the orgnr; call first
|
|
- \`gnubok_create_company\`: preview (no confirm) then create (confirm=true)
|
|
- \`gnubok_create_sie_upload\`: byte-exact upload URL for the SIE file
|
|
- \`gnubok_sie_preflight\`: scan a shared SIE file, nothing written
|
|
- \`gnubok_import_sie\`: staged import; use the preflight's mappings
|
|
- \`gnubok_connect_bank\` / \`gnubok_connect_skatteverket\`: status + connect links
|
|
- \`gnubok_list_companies\`, \`gnubok_get_agent_briefing\`: state checks
|
|
- \`gnubok_list_uncategorized_transactions\`: the first real bookkeeping step
|
|
|
|
## Pitfalls
|
|
|
|
- A VAT-registered company without a moms period is refused on purpose; do
|
|
not work around it by claiming the company is not VAT-registered.
|
|
- Do not create a company twice on a retry: check \`gnubok_list_companies\`
|
|
if a create call was interrupted.
|
|
- A preflight org-number mismatch means the file is another company's
|
|
bookkeeping: stop and confirm, never import across companies.
|
|
- Bookkeeping duty starts when the company exists in Accounted with a fiscal
|
|
period. Never create a company "to try things out" for a real
|
|
organisation; use the sandbox in the web app for demos.
|
|
`
|
|
|
|
export const onboardingSkill: Skill = {
|
|
slug: 'onboarding',
|
|
name: 'Onboarding: New Company Setup',
|
|
summary:
|
|
'Set up a company in chat: orgnr + previous system first, prefill via gnubok_lookup_company, one confirm to create, SIE history via preflight + staged import, then bank/Skatteverket cards.',
|
|
tags: ['onboarding', 'setup', 'company', 'bank', 'skatteverket', 'sie', 'migration', 'agent-first'],
|
|
body,
|
|
tier: 'workflow',
|
|
}
|