CORE DIRECTORY // SYSTEM.USER.DIANA_ISMAIL

Labs by Diana — Experiments that ship.

Side projects that got out of hand. AI tools built for problems I kept tripping over — now live, now yours.

Agentic-AIActive

Candiv

MODULE_012

TECHNICAL_OVERVIEW

ActiveAgentic-AI

Candiv sits alongside the tools agencies already use - Planable, Later, Notion - rather than replacing them. The entry point is a post submission: caption text plus a file attachment (image or short video). A BullMQ extraction worker detects the file type, normalises the asset, and enqueues a payload for the review worker. The review worker calls the LLM pipeline via @diabolicallabs/llm-client, routing video through Gemini’s Files API (Google provider) and image and text analysis through OpenAI. Both paths return to a shared scoring layer that grades the submission against the client’s rulebook and writes a CallRecord per review request.

The rulebook is the central data structure. Each client tenant has their own rulebook in PostgreSQL via Drizzle ORM, authored during onboarding and versioned per client. The compliance scorecard maps every verdict to the rule that triggered it - the absence of that citation trail was what made prior manual compliance review difficult to surface to clients. Better Auth handles tenancy and authentication; S3-compatible storage holds the uploaded media; Railway runs both the Next.js application and the BullMQ workers.

The multimodal routing was the architectural constraint that surfaced first in production. A single review request can contain an image, a video, and a caption, and Gemini’s Files API and OpenAI’s content blocks use different attachment formats. @diabolicallabs/llm-client’s multi-provider abstraction handles the format translation in the worker layer, so the scoring logic does not need to branch per provider.

PROJECT_LEARNINGS_LOG

KEY_LEARNING_01

Routing video to Gemini’s Files API while routing text and image analysis through OpenAI within the same review pipeline required @diabolicallabs/llm-client’s multi-provider abstraction to normalise two different content-block formats in a single worker pass. This constraint was invisible until the first video attachment hit the review worker - prior integration testing had used image-only posts.

KEY_LEARNING_02

Splitting the BullMQ pipeline into separate extraction and review workers was the right boundary, but any state that crosses the queue boundary must be serialisable. An early attempt to pass an ioredis client instance in job data failed silently - the job serialised without error, but the worker received a structurally broken object. The fix was reconnecting to Redis inside the worker process rather than inheriting the connection from the producer.

KEY_LEARNING_03

@typescript-eslint’s no-unsafe-assignment rule flagged Drizzle query return types as any in four places across the schema. The fix required explicit generic type parameters on each query call - a pattern now applied consistently across every Drizzle query in the codebase, because the framework does not enforce it by default.

SaaSBrand ComplianceMultimodal AIMulti-tenantNext.jsTypeScriptBullMQDrizzle ORMRailway

SYSTEM.INT // 2026 LABS_CORE v2.78.2

LATENCY: STATUS: NOMINAL