The onboarding flow now mirrors the web wizard: ask for the
organisationsnummer first, look the company up in the public registry (one
TIC Lens call through the extracted extensions/general/tic/lib/lookup.ts,
shared with the /lookup HTTP route), and present the facts for confirmation
instead of interrogating the user.
The new gnubok_lookup_company tool (companies:read, company-independent,
default catalog) returns the registry facts, a prefilled
suggested_create_company_input, and a still_to_ask list that encodes the
same fact-vs-question rules as lib/onboarding-journey/reducer.ts: F-skatt
is a fact both ways, VAT is a fact only when positively registered (ML 17
kap 24 paragraf), moms period and accounting method are always asked, an
enskild firma's verksamhetsnamn is the user's choice, and a known fiscal
year becomes a confirm question. Registry outages degrade to the full
question list instead of failing onboarding.
The onboarding skill and the plugin's /accounted:setup command are updated
to the orgnr-first flow (plugin 1.2.0). tools/list ceiling bumped 61.2K to
61.5K with the reason 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>
Claude.ai's Add custom connector dialog auto-detects Authentication
"None" for a server that answers the handshake without credentials,
which is exactly what lazy auth does; a user who accepts that default
gets an error instead of the sign-in on the first company-scoped call.
State the two correct choices ("Required when the server asks", DCR
client registration) in the bridge README and the plugin's CONNECTORS.md.
Claude-Session: https://claude.ai/code/session_018wCdzRTatKiDByKB8hCNT6
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The Claude plugin is the one-click install for Cowork and Claude Code,
so it should also be the entry to agent-first onboarding (#1814).
/accounted:setup connects the bundled connector (creating the account on
the sign-in screen if needed), hands off to the server-side onboarding
skill when the account has no company, then the bank and Skatteverket
links. CONNECTORS.md documents the single bundled connector the way
Anthropic's own plugins do. Version 1.1.0 so marketplaces that sync on
version bumps pick it up. The plugin-refs guard now also validates
commands/*.md against the server.
Claude-Session: https://claude.ai/code/session_018wCdzRTatKiDByKB8hCNT6
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(mcp): distribution polish for agent-first onboarding: CIMD, plugin start skill, bridge hint
Fourth PR of agent-first onboarding (#1814).
- The OAuth AS metadata advertises client_id_metadata_document_supported
next to the existing `none` token auth, the pair Claude.ai, Claude Code
and Codex look for to use CIMD instead of registering a DCR client per
connection. authorize/token never keyed on client_id (the redirect-URI
allowlist is the trust boundary), so nothing else changes; DCR stays
for ChatGPT.
- The plugin's start skill no longer sends a user without an account to
the website: the /mcp OAuth screen creates the account, and a
NO_COMPANY_YET briefing failure routes to the onboarding skill and
accounted_create_company. README updated to match.
- `npx accounted-mcp` without ACCOUNTED_API_KEY prints the OAuth
alternative (Claude Code, Codex, Claude.ai connector) and that the
account can be created on the sign-in screen; package README too.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018wCdzRTatKiDByKB8hCNT6
* fix(oauth): do not advertise CIMD until redirect URIs are matched against the client document
CodeRabbit on #1866: advertising client_id_metadata_document_supported
makes Claude and Codex send URL client_ids and expects an exact
redirect_uri match against that document; the authorize endpoint only
checks the global allowlist and never fetches client metadata. The flag
is withheld until an SSRF-safe, cached CIMD fetch with exact redirect
matching exists. DCR stays the registration path (stateless, so free).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018wCdzRTatKiDByKB8hCNT6
---------
Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
The plugin has been installable from erp-mafia/accounted since #1088, but
three things would fail review at the Claude plugin directory:
- `homepage` pointed at https://app.gnubok.se/docs/api/connect-claude, which
404s. next.config.ts redirects /docs/api/* to the separate docs.gnubok.se
repo, where that page was never ported, so app/docs/api/connect-claude is
unreachable dead code. Point homepage at the plugin README instead.
- `license: MIT` was a bare claim with no artifact next to it. Add the MIT
text and make the README explicit that the plugin is MIT while the platform
it connects to is a separate AGPL-3.0 work.
- Version stayed at 0.1.0 for a plugin that has been live and working.
Also give /accounted:start a path for a user who installs from the directory
with no Accounted account: previously it only handled a not-yet-authenticated
MCP server, and a cold user would hit OAuth with nowhere to go.
Both manifests pass `claude plugin validate`, the same check the review
pipeline runs on every submission.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat: add Accounted MCP namespace
* fix(bookkeeping): stop flagging verifikat whose underlag lives on a referenced supplier invoice
The missing-underlag surfaces only accepted a document directly linked to
the entry, so payment verifikat for supplier invoices (doc on the
registration entry per design) and entries whose doc was pinned to the
bank transaction before matching were falsely flagged; opening the entry
showed the referenced doc and cleared the warning client-side, and it
came back on reload.
- verifikat_without_documents + transactions_without_documents now treat
an entry as covered when a supplier invoice referencing it (registration
or payment FK, or a supplier_invoice_payments row) carries a document
anchored to a journal entry (BFL 5 kap 7 paragraf hänvisning till
underlag; anchoring required because the WORM deletion guards key on
document_attachments.journal_entry_id)
- match-supplier-invoice routes (dashboard + v1) propagate the
transaction's pinned document onto the payment verifikat, mirroring the
categorize route; migration backfills rows already written (open
unlocked periods, company-guarded, never steals a linked doc)
- /api/documents/counts, the transactions-page badges, the bulk "Inget
underlag krävs" count and the push-notification scheduler share the
same reference-aware predicate, so every surface agrees with the RPC
- counts route validates journal_entry_ids as UUIDs (they are
interpolated into a PostgREST or-filter)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(transactions): align table columns flush with page edges
Collapse the checkbox gutter column to zero width and hang the
hover-revealed checkbox/expand chevron in the page margins, drop the
outer padding so DATUM sits flush left and STATUS flush right, and
tuck the overflow-menu dots under the middle of the STATUS header.
Applied to both the inbox and history tables so they stay identical.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(arsredovisning): tie anlaggningstillgangar note to booked depreciation
The ARL 5:8 roll-forward note recomputed depreciation from its own
day-based linear formula (365.25/12 month length, non-inclusive day
count, linear only), drifting ~20 kr per year per asset from the
ledger-driven resultat- and balansrakning and misstating non-linear
methods entirely. Note figures now come from posted
depreciation_schedules rows (the same source disposeAsset reverses),
falling back to the engine's computeAnnualDepreciation when nothing is
posted; pre-onboarding opening balances iterate prior years through
the engine. Adds a note-vs-trial-balance tie-out warning (accounts
1000-1299, over 1 kr) surfaced before download.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* refactor(stripe): move connect and sync surface from settings to import page
Stripe's transaction feed is a continuous import source in the same
category as the PSD2 bank connection, so its connect/sync surface now
lives on the import page as a source card (mode=stripe), gated
"kommer snart" on hosted like before; self-hosted keeps the full panel.
- Import page: Stripe card after Koppla bank, renders the existing
StripeSettingsPanel via the settings-panel registry
- OAuth callback and panel cleanup return to /import?mode=stripe
- Settings > Betalningar retired: nav item removed, route redirects,
PaymentsSettingsContent deleted, legacy ?tab=payments mapped
- New import.stripe_* strings in sv+en; dead settings_nav.payments removed
Crons and sync logic unchanged; payment-link settings stay in the
invoicing section.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* fix(underlag): paginate missing-underlag cron and harden doc-surface queries
Resolve PR review findings on bug/invalid-imports:
- notification-scheduler: fetchAllRows on all 5 global reads; past 1000 rows
the capped reads produced false "saknade underlag" notifications
- bulk-missing: LOOKUP_CHUNK 300->150 so the twice-embedded .or() id list
stays under the PostgREST URL limit
- bulk-missing + transactions page: UUID-guard the .or()-interpolated id
lists, matching documents/counts
- match-supplier-invoice (dashboard + v1): log documentId/journalEntryId on
the non-fatal doc-link warning
- well-known/oauth-protected-resource: document the tool_namespace allow-list
- messages/en: reword stripe_description
- DECISIONS.md: record the asset ibAck tie-out and Tailwind !important calls
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
* fix(tic): convert registrationDate from Unix seconds to millisecond epoch in lookup and profile tests
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Ships an installable Claude Code plugin (/plugin marketplace add
erp-mafia/accounted) that bundles the MCP connection (OAuth, zero-key)
with seven short workflow skills following the Swedish bookkeeping
rhythm: start, bookkeep, check, month-close, vat, payroll, year-end.
Wrappers are deliberately thin: they ground in the agent briefing and
Accounted:// resources, load server-side workflow skills and regulatory
atoms via gnubok_load_skill at need, and stage every write for user
approval. No knowledge is duplicated into the plugin.
A vitest cross-checks every skill slug, atom id, resource URI, and tool
name the wrappers reference against the MCP server source, so a server
rename fails CI instead of a user's chat session.
Assessment and follow-ups in dev_docs/claude_plugin.md (local, dev_docs
is unpublished by design).
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>