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-schedulerregisters five repeatable jobs onto five named queues (lakshmi:account-sync,lakshmi:transaction-categorize,lakshmi:ai-recommendation,lakshmi:report-generation,lakshmi:data-export);lakshmi-workerdefines those same queues with retry/back-off policies and DLQs and runs a worker per queue. The queue-name constants are duplicated in bothscheduler/src/schedules.tsandworker/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.tsprovides a typed, idempotentLakshmiEventBus(kafkajs, LZ4 compression, per-userIdpartition 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)#
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.
LAKSHMI_AI_AGENTS_VERSION19resolveConfiguredModelProviders53AiAgentsHealth67AiAgentsOptions79createAiAgentsHealthPayload84startLakshmiAiAgents106The 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.
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.
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.
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.
LAKSHMI_SYNC_ENGINE_VERSION13SyncEngineHealth15SyncEngineOptions25createSyncEngineHealthPayload30startLakshmiSyncEngine47The 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.