Skip to content

Tech Stack

Casaconomy tech stack — index + decision log

The authoritative reference for what Casaconomy uses, what it doesn’t, why those choices were made, and what’s planned to change. Read this before proposing a new dependency, evaluating an external skill for fit, or onboarding into the codebase.

OwnerVidar (Master of Craft)
Last reviewed2026-05-18 by Vidar
Next review2026-06-18
Update triggerAny commit that adds a top-level dependency, retires a tool, or changes a major architectural choice. The same PR updates this file.

Stack at a glance

Frontend (web technologies, run inside Tauri’s WebView)

LayerToolPurposeNotes
LanguageTypeScriptAll frontend codeStrict mode; ts-rs generates types from Rust
FrameworkReact 19Component model, hooks, concurrent renderingLatest major; a few patterns from earlier majors deliberately retained
RoutingReact Router v7Page-level routingDeclarative routes, no nested-route gymnastics
State (client)ZustandDomain stores, one per concernPreferred over Redux/RTK; avoid context-as-state
UI libraryMantine v9Components, layout, themingAll @mantine/* packages at v9 (core, dates, form, hooks, notifications, charts, spotlight)
Drag-and-drop@dnd-kitSortable list interactionsUsed for reorderable UI surfaces
Stylingstyled-componentsComponent-scoped CSS-in-JSUse Mantine first; styled-components for one-off tweaks
ChartsRecharts + @mantine/chartsTime-series + categoricalRecharts for custom charts; Mantine/charts wrapper for standard ones
Crypto (frontend)@scure/bip39BIP-39 mnemonic generation for invite codesUsed in device-pairing and group invite flows
QR codesreact-qr-codeQR display for invite/pairing flowsUsed alongside @scure/bip39
Date utilitiesdate-fns + dayjsDate parsing, formatting, arithmeticBoth present; date-fns for utility functions, dayjs for display formatting
Screenshotshtml-to-imageDOM-to-image exportUsed for in-app report-issue screenshot capture
BuildViteDev server, HMR, production bundleDriven by Deno tasks (deno task dev / deno task build)
TestingVitestUnit + integrationReact Testing Library for component tests
E2EPlaywrightBrowser automationUsed in test/e2e/
Component explorerStorybookIsolated component development and docsDev-only; run via deno task storybook

Backend (native side, runs as part of the Tauri app process)

LayerToolPurposeNotes
LanguageRustAll backend codeStable channel; recent toolchain
FrameworkTauri v2 (~2.10)Desktop + mobile shell, IPC, plugin systemPlugins: dialog, http, os, process, shell, updater
Async runtimeTokioAsync tasks, timers, channelsDefault executor for all async work
DatabaseSQLite (via SQLx 0.8)Local persistenceOne DB per device; 48 migrations; encrypted snapshots planned (CAS-1093)
MigrationsSQLx migrateForward-only migrations in src-tauri/migrations/Skill: casaconomy-migration
SerializationSerdeJSON, plus various binary formatsStandard
Type-bridgingts-rs v11Generates .d.ts from Rust typesAuto-emits to src/types/bindings/; never edit those by hand
LoggingtracingStructured loggingSubscribers configured per build mode
Crash reportingSentry (0.35)Opt-in crash reportingTelemetryService manages; off by default — user explicitly enables in settings
WebSockettokio-tungstenite (0.24)Sync relay transportUsed by the sync service for real-time device coordination (CAS-748)
Cryptographyed25519-dalek + x25519-dalekSigning + key agreementAEAD encryption for changesets; invite-code signatures (CAS-496, CAS-583)
OCRocrs + rtenOn-device text recognitionUsed in invoice capture pipeline (invoice_watcher.rs)
HTTP clientreqwest (0.12)Outbound HTTP from RustUsed for AI provider calls, Gmail OAuth, license validation

Infrastructure (everything outside the app)

LayerToolPurposeNotes
Domain + DNSCloudflarecasaconomy.com zoneSkill: casaconomy-cloudflare
Inbound mailCloudflare Email RoutingForwards hello@, support@, licenses@, catch-all → Proton mailboxFree tier; per-alias rules
Outbound mailResendTransactional + human-typed mail from hello@casaconomy.comSkill: casaconomy-resend; envelope-from send.casaconomy.com for SPF isolation
Public siteCloudflare Pagescasaconomy.com + www.casaconomy.comRepo: abernerus/casaconomy-web (private); deploys from main
Docs (this Book)Cloudflare Pages + CF Accessdocs.casaconomy.com — Starlight site with access gateCF Pages project: casaconomy-book; CF Access policy: team members only; live 2026-05-18
Secrets~/.paperclip/secrets/Per-machine token storageNever committed; gitignored
Sync relayCloudflare WorkersSync API at sync.casaconomy.com/vaults/*workers/sync-relay/; changeset + baseline machinery live (CAS-3461); device-identity layer in flight (CAS-3676/3684)
Sync snapshotsCloudflare R2Encrypted vault snapshotsBucket: casaconomy-sync-snapshots; preview: casaconomy-sync-snapshots-preview
Sync metadataCloudflare D1Device registry, snapshot index, account recordsDatabase: casaconomy-sync-relay
Sync broadcastCloudflare Durable ObjectsPer-vault live CHANGESET-LIVE channel (VaultChannel)Bundled in workers/sync-relay/; free plan uses SQLite-backed DOs
Provider pluginsCloudflare WorkersDeclarative financial-data provider adaptersSigned plugin catalog + generic engine in app (CAS-3499); workers/fake-providers/ is the E2E test harness
Licensing APICloudflare Workers + D1 + ResendLicense issue/validate/activate at licenses.casaconomy.comworkers/licensing/; schema anticipates Phase 5 Stripe

Build + tooling

LayerToolPurposeNotes
Task runnerDenoAll deno task ... commandsNOT npm. Deno reads deno.json/deno.lock
JS depsnpm registryTypeScript librariesResolved via Vite/Bun, NOT installed via npm CLI
JS test depsBunVitest + Playwright runtimes (where applicable)Used by tooling, not as a primary runtime
Cargo targetPer-role shared dirs at ~/Projects/casaconomy/.cargo-targets/<role>/Concurrent-build isolationPer-worktree config injected by ensure-worktree.sh
Rust cachesccache (shared store)Cross-worktree Cargo artifact cacheShared by all officers on the same machine; CAS-3615
JS dep cacheLockfile-keyed shared node_modulesCross-worktree npm artifact cacheSymlinked per worktree; CAS-3611
Pre-commit.githooks/pre-commitRefuses commits in main cloneEngineers commit in worktrees; Saga overrides for ops
Code guard (Claude).claude/hooks/casaconomy-cwd-guard.shClaude Code PreToolUse — blocks Edit/Write/Bash in main cloneBypass: ALLOW_MAIN_CLONE_OPS=1 (Saga only via pc as saga)
Code guard (Codex).codex/hooks.jsonCodex PreToolUse — same guard, aligned with Claude scopeKeep both guards in sync when updating Layer 2 rules

Agent infrastructure

LayerToolPurposeNotes
OrchestrationPaperclip (pinned 2026.517.0)Multi-agent runtime, routines, JWT-based attributionSkill: seneschal-ops (the pc CLI); version-pinned; upgrade via reversible PAPERCLIP_API_VERSION launchd env override (CAS-3624)
Adapterclaude_localMost agents run on Claude CodeModels: Sonnet for engineers + reviewers, Haiku for routine fetchers, Opus reserved for chronicle prose
Adapteroz_localRavens + Artificer pilotPublished as @abernerus/adapter-oz-local; CAS-977
Sigil routingGH labels (target-{ceo,cto,frontend,backend,devops,ux,qa,loremaster}) → Paperclip officerInbound issue assignmentSync: paperclip-inbox-sync
Git identityGH App per-officer bot accountsAll 11 officers commit under individual bot identitiesWired via GH App installation tokens; no more shared-committer ambiguity (CAS-3688)

What we don’t use

The anti-list. A skill, library, or pattern targeting any of these is not a Casaconomy fit by default. The Reader’s evaluation skill rejects subscriptions on this basis.

CategorySpecifics
JS frameworksVue, Svelte, Angular, Solid, Lit. We are React.
JS-on-serverExpress, Fastify, Next.js (server side), Nest. The backend is Rust/Tauri, not Node.
Vanilla-JS / Rails-flavouredStimulus, Turbo, Hotwire, jQuery. We do not have a server-rendered HTML surface.
CSS frameworksTailwind, Bootstrap, Bulma. Mantine + styled-components is the way.
State managersRedux, RTK, MobX, Recoil, Jotai. Zustand only.
ORMsDiesel, sea-orm, Prisma. SQLx is plain SQL by design.
Test frameworksJest, Mocha, Karma. Vitest only.
BundlersWebpack, Parcel, Rollup, esbuild standalone, Turbopack. Vite only.
Task runnersnpm scripts, yarn scripts, pnpm scripts, just, make. Deno tasks only.
Desktop shellsElectron, NW.js. We chose Tauri specifically.
Mobile cross-platformReact Native, Flutter, Ionic, Capacitor, Expo. Tauri Mobile only.
Auth providersAuth0, Clerk, Firebase Auth, Supabase Auth. License keys are our primary auth (Phase 4a/5).
Backend-as-a-serviceFirebase, Supabase, AWS Amplify. We compose Cloudflare primitives directly.
Mail platformsSendGrid, Mailgun, Postmark (considered, not chosen), AWS SES (used indirectly via Resend; not direct). Resend only.
Deployment platformsVercel, Netlify, Render, Fly.io. Cloudflare Pages + Workers only.
StorageAWS S3, GCS, Backblaze B2 (considered). Cloudflare R2 only.
Secret managersVault, AWS Secrets Manager, 1Password CLI. Local files in ~/.paperclip/secrets/.
Self-hosted emailPostfix, Mailcow, Mailu. Hard no — IP reputation is a permanent operational tax.
ContainersDocker, Kubernetes, Helm. Casaconomy is a desktop app; the future Workers are serverless. No container orchestration.
MonitoringDatadog, New Relic, OpenTelemetry pipelines. Note: Sentry IS used, but only for opt-in crash reporting via TelemetryService. It is off by default and never collects user data without consent.
AnalyticsPlausible, Fathom, Google Analytics, Posthog. None — Casaconomy doesn’t track users.

If a candidate skill or library targets something on this list, the answer is no fit. Some entries are reasoned-out (mail platforms, deployment); some are stack-mismatch (frameworks); some are philosophical (auth, analytics). All are firm.


What’s coming

Tools and systems planned but not yet integrated. Skills referencing these may legitimately propose subscriptions in advance.

WhenWhatTracking
Phase 5 (deferred)Stripe-paid licensing, webhooks, Customer Portal#316not-ready
CAS-645 mobileTauri Mobile (iOS first, Android in Phase 1+)TestFlight pipeline in place (CAS-1866); App Store submission pending
MaybeAI-assisted categorisationai_commands.rs + services/ai/ scaffolded; Anthropic + Gemini providers wired; UX pending
MaybeMarketing site CMS-shaped if we outgrow plain HTMLNo active tracker; revisit when content team grows

What we removed

Tools we used and deprecated, for context.

ToolRemovedReason
adapter-oz-local source in repo2026-04-28 (#292)Extracted to its own repo (abernerus/casaconomy-paperclip-adapter-oz) and published as @abernerus/adapter-oz-local on GH Packages. Now a dependency, not vendored.
iOS SDK 26.4 build skip in smoke routine2026-04-29 (recovered)Initial smoke test failed; turned out the SDK was installed — the diagnostic command was malformed. Skip is now condition-aware.
Lore/ in this repo2026-04-29Chronicle and character lore extracted to gripsborg-saga repo. See AGENTS.md §“The chronicle lives elsewhere”.
”Future (Phase 3 sync)” infrastructure rows2026-05-18R2/D1/Workers sync relay went live; moved to the Infrastructure table as current.

(This list is short by design — we add to it deliberately, not aspirationally.)


Decision log

Terse one-liners on the major picks. Each is the current answer; if any get revisited, log the change here.

  • Tauri over Electron — smaller bundle (~10MB vs 100MB+), native WebView, Rust backend. Memory and footprint won.
  • React over Vue/Svelte — team familiarity, ecosystem depth, predictable concurrent-rendering story. Not a religious pick.
  • Mantine over Tailwind/Bootstrap/Material — components-first; less custom CSS, more Mantine-style. Themes work cleanly.
  • Zustand over Redux — minimal boilerplate; the household has rules about not using context-as-state, and Zustand is the disciplined alternative.
  • SQLx over Diesel — plain SQL is more honest than ORM macros. Migrations are forward-only and small.
  • Deno over npm — task runner only; npm is not in our path. The deno tasks are documented in deno.json.
  • Cloudflare over AWS/Vercel — single ecosystem (DNS, mail, Pages, Workers, D1, R2), edge-first, no vendor sprawl.
  • R2 over S3 — same as above, plus zero egress fees, plus 10 GB free.
  • Resend over Mailgun/SendGrid/AWS SES direct — cleanest DX for the Cloudflare-shaped stack; Worker-friendly SDK.
  • Proton over Gmail-paid for the brand inbox — privacy posture matches the personal-finance product narrative.
  • Cloudflare Pages over Vercel/Netlify — already in the Cloudflare ecosystem; no extra account, deploys via Git push.
  • Local skills over external skill subscriptions by default — internal skills (e.g. casaconomy-cloudflare) are first-class. External subscriptions are exception, gated by the regent.
  • Paperclip over LangChain/AutoGPT/CrewAI — orchestration is house-shaped. Paperclip’s adapter-and-skills model fits how the agents actually work for us.
  • Single shared abernerus GH account for all agents — every agent has admin. No separation-of-duties theatre. Last-reviewer-merges policy is a direct consequence.
  • CI is not a merge gate — local tests/builds are — GitHub Actions budget exhausts in ~5–10 days; green CI is not reliable as a merge bar. The bar is: local build green + pre-commit-guard exit 0 + Assayer smoke pass. gh pr merge --admin is the sanctioned bypass while CI is down; this is not a temporary hack, it is the standing policy.
  • Provider plugins over bundled adapters (CAS-3499) — financial-data provider adapters are declarative Cloudflare Workers, not code bundled in the app binary. A signed plugin catalog lets us ship new providers and update existing ones without an app release. The fake-provider harness (workers/fake-providers/) runs in E2E tests without hitting real bank APIs.

Maintenance

When this doc must be updated:

  • A new top-level dependency lands. Whether Cargo, npm, or any infrastructure (a new Cloudflare product, a new external service) — the same PR adds it to the right table here.
  • A tool retires or is replaced. Deprecation goes in What we removed, with a one-line reason.
  • A major architectural choice is made. New entry in Decision log.
  • Quarterly review even when quiet. The Last reviewed line at the top has a one-month look-ahead. When that date passes, the next-reviewing officer (default: Vidar) skims the document and re-stamps it.

When this doc cannot be updated:

  • Don’t add aspirational tools. What’s coming is for items with a tracked CAS or merged design. Wishlists go elsewhere.
  • Don’t add anti-list entries without reasoning. Every don’t use line has a defensible why — the regent reads this doc and the why-column has to make sense.

If you change something here, ping Vidar in the PR. He owns the long-term shape.


How to use this doc

AudienceWhat to read
RegentTop of file (overview + stack-at-a-glance) for the mental model. Decision log when refreshing on a specific choice.
New officer onboardingAll of it. Then read docs/architecture/README.md for the system map.
The Reader (skill discovery + evaluation)Stack-at-a-glance + What-we-don’t-use are authoritative for fit-checks.
Engineer adding a dependencyThe relevant table — confirm the new dep doesn’t conflict with the anti-list. If it crosses a category boundary, raise it for discussion before merging.
External contributor or auditorThe whole doc is meant to be a complete picture of the actual stack without spelunking through Cargo.toml and deno.json.