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.
| Owner | Vidar (Master of Craft) |
| Last reviewed | 2026-05-07 by Vidar |
| Next review | 2026-06-07 |
| Update trigger | Any 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)
| Layer | Tool | Purpose | Notes |
|---|---|---|---|
| Language | TypeScript | All frontend code | Strict mode; ts-rs generates types from Rust |
| Framework | React 19 | Component model, hooks, concurrent rendering | Latest major; a few patterns from earlier majors deliberately retained |
| Routing | React Router v7 | Page-level routing | Declarative routes, no nested-route gymnastics |
| State (client) | Zustand | Domain stores, one per concern | Preferred over Redux/RTK; avoid context-as-state |
| UI library | Mantine v9 | Components, layout, theming | All @mantine/* packages at v9 (core, dates, form, hooks, notifications, charts, spotlight) |
| Drag-and-drop | @dnd-kit | Sortable list interactions | Used for reorderable UI surfaces |
| Styling | styled-components | Component-scoped CSS-in-JS | Use Mantine first; styled-components for one-off tweaks |
| Charts | Recharts + @mantine/charts | Time-series + categorical | Recharts for custom charts; Mantine/charts wrapper for standard ones |
| Crypto (frontend) | @scure/bip39 | BIP-39 mnemonic generation for invite codes | Used in device-pairing and group invite flows |
| QR codes | react-qr-code | QR display for invite/pairing flows | Used alongside @scure/bip39 |
| Date utilities | date-fns + dayjs | Date parsing, formatting, arithmetic | Both present; date-fns for utility functions, dayjs for display formatting |
| Screenshots | html-to-image | DOM-to-image export | Used for in-app report-issue screenshot capture |
| Build | Vite | Dev server, HMR, production bundle | Driven by Deno tasks (deno task dev / deno task build) |
| Testing | Vitest | Unit + integration | React Testing Library for component tests |
| E2E | Playwright | Browser automation | Used in test/e2e/ |
| Component explorer | Storybook | Isolated component development and docs | Dev-only; run via deno task storybook |
Backend (native side, runs as part of the Tauri app process)
| Layer | Tool | Purpose | Notes |
|---|---|---|---|
| Language | Rust | All backend code | Stable channel; recent toolchain |
| Framework | Tauri v2 (~2.10) | Desktop + mobile shell, IPC, plugin system | Plugins: dialog, http, os, process, shell, updater |
| Async runtime | Tokio | Async tasks, timers, channels | Default executor for all async work |
| Database | SQLite (via SQLx 0.8) | Local persistence | One DB per device; 48 migrations; encrypted snapshots planned (CAS-1093) |
| Migrations | SQLx migrate | Forward-only migrations in src-tauri/migrations/ | Skill: casaconomy-migration |
| Serialization | Serde | JSON, plus various binary formats | Standard |
| Type-bridging | ts-rs v11 | Generates .d.ts from Rust types | Auto-emits to src/types/bindings/; never edit those by hand |
| Logging | tracing | Structured logging | Subscribers configured per build mode |
| Crash reporting | Sentry (0.35) | Opt-in crash reporting | TelemetryService manages; off by default — user explicitly enables in settings |
| WebSocket | tokio-tungstenite (0.24) | Sync relay transport | Used by the sync service for real-time device coordination (CAS-748) |
| Cryptography | ed25519-dalek + x25519-dalek | Signing + key agreement | AEAD encryption for changesets; invite-code signatures (CAS-496, CAS-583) |
| OCR | ocrs + rten | On-device text recognition | Used in invoice capture pipeline (invoice_watcher.rs) |
| HTTP client | reqwest (0.12) | Outbound HTTP from Rust | Used for AI provider calls, Gmail OAuth, license validation |
Infrastructure (everything outside the app)
| Layer | Tool | Purpose | Notes |
|---|---|---|---|
| Domain + DNS | Cloudflare | casaconomy.com zone | Skill: casaconomy-cloudflare |
| Inbound mail | Cloudflare Email Routing | Forwards hello@, support@, licenses@, catch-all → Proton mailbox | Free tier; per-alias rules |
| Outbound mail | Resend | Transactional + human-typed mail from [email protected] | Skill: casaconomy-resend; envelope-from send.casaconomy.com for SPF isolation |
| Public site | Cloudflare Pages | casaconomy.com + www.casaconomy.com | Repo: abernerus/casaconomy-web (private); deploys from main |
| Secrets | ~/.paperclip/secrets/ | Per-machine token storage | Never committed; gitignored |
| Future (Phase 3 sync) | Cloudflare R2 | Encrypted snapshot storage | Activated 2026-04-29; not yet wired by code |
| Future (Phase 3 sync) | Cloudflare D1 | Sync metadata (devices, snapshots, accounts) | Same activation cycle |
| Future (Phase 3 sync) | Cloudflare Workers | Sync API at sync.casaconomy.com | TBD by Vidar’s breakdown of #313 |
| Future (Phase 4a licensing) | Cloudflare Workers + D1 + Resend | License issue/validate/activate at licenses.casaconomy.com | Schema-anticipates Phase 5 Stripe |
Build + tooling
| Layer | Tool | Purpose | Notes |
|---|---|---|---|
| Task runner | Deno | All deno task ... commands | NOT npm. Deno reads deno.json/deno.lock |
| JS deps | npm registry | TypeScript libraries | Resolved via Vite/Bun, NOT installed via npm CLI |
| JS test deps | Bun | Vitest + Playwright runtimes (where applicable) | Used by tooling, not as a primary runtime |
| Cargo target | Per-role shared dirs at ~/Projects/casaconomy/.cargo-targets/<role>/ | Concurrent-build isolation | Per-worktree config injected by ensure-worktree.sh |
| Pre-commit | .githooks/pre-commit | Refuses commits in main clone | Engineers commit in worktrees; Saga overrides for ops |
| Code guard (Claude) | .claude/hooks/casaconomy-cwd-guard.sh | Claude Code PreToolUse — blocks Edit/Write/Bash in main clone | Bypass: ALLOW_MAIN_CLONE_OPS=1 (Saga only via pc as saga) |
| Code guard (Codex) | .codex/hooks.json | Codex PreToolUse — same guard, aligned with Claude scope | Keep both guards in sync when updating Layer 2 rules |
Agent infrastructure
| Layer | Tool | Purpose | Notes |
|---|---|---|---|
| Orchestration | Paperclip | Multi-agent runtime, routines, JWT-based attribution | Skill: seneschal-ops (the pc CLI) |
| Adapter | claude_local | Most agents run on Claude Code | Models: Sonnet for engineers + reviewers, Haiku for routine fetchers, Opus reserved for chronicle prose |
| Adapter | oz_local | Ravens + Artificer pilot | Published as @abernerus/adapter-oz-local; CAS-977 |
| Sigil routing | GH labels (target-{ceo,cto,frontend,backend,devops,ux,qa,loremaster}) → Paperclip officer | Inbound issue assignment | Sync: paperclip-inbox-sync |
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.
| Category | Specifics |
|---|---|
| JS frameworks | Vue, Svelte, Angular, Solid, Lit. We are React. |
| JS-on-server | Express, Fastify, Next.js (server side), Nest. The backend is Rust/Tauri, not Node. |
| Vanilla-JS / Rails-flavoured | Stimulus, Turbo, Hotwire, jQuery. We do not have a server-rendered HTML surface. |
| CSS frameworks | Tailwind, Bootstrap, Bulma. Mantine + styled-components is the way. |
| State managers | Redux, RTK, MobX, Recoil, Jotai. Zustand only. |
| ORMs | Diesel, sea-orm, Prisma. SQLx is plain SQL by design. |
| Test frameworks | Jest, Mocha, Karma. Vitest only. |
| Bundlers | Webpack, Parcel, Rollup, esbuild standalone, Turbopack. Vite only. |
| Task runners | npm scripts, yarn scripts, pnpm scripts, just, make. Deno tasks only. |
| Desktop shells | Electron, NW.js. We chose Tauri specifically. |
| Mobile cross-platform | React Native, Flutter, Ionic, Capacitor, Expo. Tauri Mobile only. |
| Auth providers | Auth0, Clerk, Firebase Auth, Supabase Auth. License keys are our primary auth (Phase 4a/5). |
| Backend-as-a-service | Firebase, Supabase, AWS Amplify. We compose Cloudflare primitives directly. |
| Mail platforms | SendGrid, Mailgun, Postmark (considered, not chosen), AWS SES (used indirectly via Resend; not direct). Resend only. |
| Deployment platforms | Vercel, Netlify, Render, Fly.io. Cloudflare Pages + Workers only. |
| Storage | AWS S3, GCS, Backblaze B2 (considered). Cloudflare R2 only. |
| Secret managers | Vault, AWS Secrets Manager, 1Password CLI. Local files in ~/.paperclip/secrets/. |
| Self-hosted email | Postfix, Mailcow, Mailu. Hard no — IP reputation is a permanent operational tax. |
| Containers | Docker, Kubernetes, Helm. Casaconomy is a desktop app; the future Workers are serverless. No container orchestration. |
| Monitoring | Datadog, 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. |
| Analytics | Plausible, 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.
| When | What | Tracking |
|---|---|---|
| Phase 3 active | Cloudflare R2 sync + D1 metadata + sync.casaconomy.com Worker | #313 |
| Phase 4a active | Licensing API on Workers + D1 at licenses.casaconomy.com, Resend for license-key delivery | #315 |
| Phase 5 (deferred) | Stripe-paid licensing, webhooks, Customer Portal | #316 — not-ready |
| CAS-645 mobile | Tauri Mobile (iOS first, Android in Phase 1+) | TestFlight pipeline in place (CAS-1866); App Store submission pending |
| Maybe | AI-assisted categorisation (CAS-???) | ai_commands.rs + services/ai/ scaffolded; Anthropic + Gemini providers wired; UX pending |
| Maybe | Marketing site CMS-shaped if we outgrow plain HTML | No active tracker; revisit when content team grows |
What we removed
Tools we used and deprecated, for context.
| Tool | Removed | Reason |
|---|---|---|
adapter-oz-local source in repo | 2026-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 routine | 2026-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 repo | 2026-04-29 | Chronicle and character lore extracted to gripsborg-saga repo. See AGENTS.md §“The chronicle lives elsewhere”. |
(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
abernerusGH account for all agents — every agent has admin. No separation-of-duties theatre. Last-reviewer-merges policy is a direct consequence.
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
| Audience | What to read |
|---|---|
| Regent | Top of file (overview + stack-at-a-glance) for the mental model. Decision log when refreshing on a specific choice. |
| New officer onboarding | All 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 dependency | The 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 auditor | The whole doc is meant to be a complete picture of the actual stack without spelunking through Cargo.toml and deno.json. |