Applications · entity catalog

lakshmi app

Authored subsystem deep-dive for lakshmi, layered on the code-linked entity catalog — what each system is, why it exists, and how it fits.

authored deep-dive
6entities1layers6deep-dives

On this page

The apps/lakshmi/ area: six Nx applications that make up the service tier of the Lakshmi personal-finance-intelligence platform — an HTTP/WebSocket gateway, a BullMQ worker and scheduler pair, two health-serving service shells (sync-engine, ai-agents), and a Manifest V3 browser extension.

What this area is#

Lakshmi is Oshun's personal-finance-intelligence product. apps/lakshmi/ contains its runnable services — not domain libraries, but the deployable process boundaries that front, schedule, and process the platform's finance workloads. The root apps/lakshmi/README.md enumerates five services (api-gateway, sync-engine, ai-agents, worker, scheduler) plus their ports; a sixth tracked project, the browser-extension, is a client surface rather than a server.

The honest split across the area is "real infrastructure, deferred domain logic." Three concerns are fully implemented: the gateway's edge plumbing (auth, RBAC, OAuth scope enforcement, rate limiting, OpenAPI generation, Kafka publishing, WebSocket pub/sub), the worker's BullMQ queue/retry/DLQ machinery, and the scheduler's repeatable-job registration. What is deliberately not yet implemented is the finance domain work those shells would call: the gateway's /v1 route handlers return empty placeholder payloads, and the worker's job processors log their phases and advance progress but stop short of real provider/DB/ML calls. Both are explicit in the source — handlers carry comments like // Domain service call will be implemented in @lakshmi/accounts library and processors carry // Real implementation: ... markers. No @lakshmi/* domain library exists in this area yet, so those are forward references, not present dependencies.

The two remaining services, sync-engine and ai-agents, are the thinnest: each is a single-file Node http server that answers /health and /ready only. ai-agents is candid about this in its own module docstring ("the financial agents themselves ... are NOT yet implemented in this service — this process currently serves health checks only").

How the area is shaped#

The services are wired together through two shared pieces of infrastructure rather than through direct imports:

  • Redis + BullMQ is the job spine. lakshmi-scheduler registers five repeatable jobs onto five named queues (lakshmi:account-sync, lakshmi:transaction-categorize, lakshmi:ai-recommendation, lakshmi:report-generation, lakshmi:data-export); lakshmi-worker defines those same queues with retry/back-off policies and DLQs and runs a worker per queue. The queue-name constants are duplicated in both scheduler/src/schedules.ts and worker/src/queues.ts, which is how the two processes meet — the scheduler produces, the worker consumes.
  • Kafka is the event spine for the gateway. api-gateway/src/kafka.ts provides a typed, idempotent LakshmiEventBus (kafkajs, LZ4 compression, per-userId partition keys) for domain events, with the gateway running in a documented degraded mode if Kafka is unreachable at boot.

The gateway is the only service with a substantial internal structure (middleware/, public-rest-api.ts, websocket.ts, kafka.ts, events.ts); the others are one or two source files each. All six share the same Nx target shape (build/lint/test/typecheck, with serve on the servers and e2e on the extension) and the scope:lakshmi, type:app, lakshmi:tier:app tags.

How it fits the wider system#

These are leaf applications: nothing else in the monorepo imports them, and within the area they depend on each other only indirectly (through Redis queue names and Kafka topics, never through TypeScript imports). The gateway is the public front door — it serves the v1 REST surface, an OpenAPI 3.1 document, an OAuth authorization-server metadata document, and the /v1/ws WebSocket upgrade. The browser extension is a separate client artifact that ships as a Chrome Manifest V3 bundle. The real external boundaries are downstream of the code present here: open-banking providers (Plaid/Yodlee/MX/Finicity/Tink), foundation- model providers (OpenAI/Anthropic/Google), object storage (MinIO buckets), and the not-yet-created @lakshmi/* domain libraries the handlers and processors are written to delegate into.

Entity catalog (6)#

The 6 tracked Nx projects in lakshmi, each a code-linked entity node — package, type, source path, declared targets, and its internal dependency graph (depends-on / used-by, resolved from the package manifests, §6/§8), read from the project graph. Grouped by architectural layer; walk the dependency links to travel the system. 6 of these carry an authored deep-dive (what / why / how it fits); the rest are generated scaffolds awaiting one.

unclassified (6)#

app

lakshmi-ai-agents

#

An AI financial-agent service shell (apps/lakshmi/ai-agents), and the most self-honest scaffold in the area — its src/index.ts docstring states the agents (scenario modeling, recommendations, NL query, bill negotiation, tax advisory) are "NOT yet implemented in this service — this process currently serves health checks only." What is real is resolveConfiguredModelProviders, which inspects the environment (OPENAI_API_KEY, ANTHROPIC_API_KEY, and Google/Gemini keys) and reports the subset of foundation-model providers actually configured, rather than asserting connections that may not exist. The health payload also surfaces the configured embedding model and agent concurrency. Beyond /health and /ready, there is no agent logic here.

buildtestlinttypecheckserve
scope: lakshmiowner: @GreyChimp
depends on@oshun/ai
app

lakshmi-api-gateway

#

The Hono HTTP/WebSocket front door (apps/lakshmi/api-gateway), and by far the most complete service in the area. Its edge layer is real and production-grade: JWT verification via jose (HS256) with subscription-tier RBAC (free/premium/family → permission sets) and per-route OAuth scope enforcement in src/middleware/auth.ts; Redis-backed rate limiting; a machine-generated OpenAPI 3.1 document and OAuth authorization-server metadata built from a 44-endpoint catalog in src/public-rest-api.ts; a typed idempotent Kafka producer in src/kafka.ts; and a room-based WebSocket manager in src/websocket.ts. The 44 /v1 route handlers in src/app.ts, however, are intentionally hollow — they validate input with Zod, enforce auth/scopes, then return empty placeholder payloads (e.g. c.json({ accounts: [] })) annotated with // Domain service call will be implemented in @lakshmi/<domain> library. So: the gateway is a working, secured, observable API surface, but the finance data behind it is not yet wired.

buildtestlinttypecheckserve
scope: lakshmiowner: @GreyChimp
depends on@lakshmi/db
app

lakshmi-browser-extension

#

A Chrome Manifest V3 browser extension (apps/lakshmi/browser-extension) that shows budget/price/coupon/cashback context while shopping. Several parts are real: src/shared/shopping-context.js is a genuine client-side analysis library (budget arithmetic, coupon ranking by estimated savings, best-offer and best- cashback selection, currency formatting, and price-text parsing); the background/service-worker.js handles install-time storage defaults and a runtime.onMessage settings query; and scripts/build.js packages src/ into dist/chrome/ while validating that the manifest is MV3 with a popup and content scripts (scripts/validate-extension.js is wired as the typecheck target, and Playwright as e2e). The honest caveat is the data and the injected overlay: DEFAULT_PROFILE is sample/seed data (example merchants like "Threadline"), and the injected content/content-script.js overlay uses hardcoded sample figures (spent 34000, budget 40000, a fixed best price) and does not yet call the shared analyzeShoppingContext analyzer or any live account data. So the extension is a working MV3 package with a real analysis module, but its on-page experience is currently a demo wired to placeholder numbers.

buildtestlinttypechecke2e
scope: lakshmiowner: @GreyChimp
app

lakshmi-scheduler

#

The BullMQ repeatable-job scheduler (apps/lakshmi/scheduler), and — alongside the worker's queue layer — one of the genuinely functional pieces of the area. src/schedules.ts builds five recurring tasks against the same five queue names the worker consumes, each with a real repeat policy (interval-based for the account-sync and categorization sweeps, cron-based for daily AI recommendations, daily report rollups, and hourly export maintenance) and env-overridable timing via getSchedulerConfigFromEnv. src/index.ts registers them with queue.upsertJobScheduler, which is a live Redis operation, and exposes a health endpoint reporting the registered task count, last registration time, and state. The data each scheduled job carries is system-level seed data (e.g. userId: 'system', connectionId: 'due-connections') since the worker side that would fan these out per-user is not yet implemented, but the scheduling mechanism itself is real and complete.

buildtestlinttypecheckserve
scope: lakshmiowner: @GreyChimp
app

lakshmi-sync-engine

#

A service shell for account synchronization (apps/lakshmi/sync-engine). Its module docstring describes orchestrating open-banking provider polling (Plaid, Yodlee, MX, Finicity, Tink), transaction ingestion, and balance refresh, but the implemented code in src/index.ts is only a Node http server that answers /health and /ready. The provider list it reports is a static array inside createSyncEngineHealthPayload, and the sync interval/concurrency are read from env vars — there is no polling, ingestion, or Kafka publishing in the service yet. Honest status: a health-serving scaffold awaiting the actual sync implementation.

buildtestlinttypecheckserve
scope: lakshmiowner: @GreyChimp
app

lakshmi-worker

#

The BullMQ background-job processor (apps/lakshmi/worker). The queue infrastructure in src/queues.ts is real and substantial: five typed queues plus five matching dead-letter queues, per-queue retry counts and back-off strategies (exponential for sync/categorize/AI, fixed for report/export), typed enqueue helpers with deduplicating job IDs, a QueueEvents-based DLQ forwarder that moves permanently-failed jobs (attempts exhausted) into the DLQ with failure metadata, and a typed createWorker factory wrapping processors in structured start/complete/fail logging. src/index.ts boots one worker per queue at domain-specific concurrencies with a graceful shutdown that drains workers, events, and queues. The five job processors (processAccountSync, processTransactionCategorize, processAiRecommendation, processReportGeneration, processDataExport) are the scaffolded part: they log each phase and call job.updateProgress(...) but replace the actual work with // Real implementation: ... comments referencing @lakshmi/integrations, @lakshmi/db, embeddings, and MinIO. So the BullMQ runtime is genuine; the finance work inside the jobs is deferred.

buildtestlinttypecheckserve
scope: lakshmiowner: @GreyChimp
depends on@lakshmi/db