Kairos: Agentic AI System Architect
An AI-orchestrated diagram canvas mapping streaming natural language prompts to interactive, phase-aware ReactFlow system architectures with Neon DB synchronization.





Kairos was built to solve the interface disconnect between natural language AI reasoning and structured visual diagrams. While text-based chat tools excel at brainstorms and static diagram tools (like Excalidraw or Mermaid.js) are great for drawing, bridging the two has historically been clunky. Kairos provides a single persistent environment where developers design, refine, and query system architectures through a collaborative, phase-aware AI assistant on a live-syncing coordinate canvas.
The Problem
Most system design tools force you to choose between static text schemas (Mermaid.js) or labor-intensive manual dragging (Miro, Visio). Existing AI diagram generators simply output a one-off chart that breaks the moment you ask for changes. Kairos addresses these core developer pain points:
- State Drift — Making changes in a chat window doesn't update the visual diagram, and editing the diagram manually isn't tracked by the AI's system context.
- Topological Mess — Direct AI generation of raw layout coordinates results in node overlaps, overlapping edge connectors, and illegible structures.
- Static Graph Nodes — Diagrams are usually rendered as passive images rather than active interactive nodes that developers can click, inspect, or query.
- Surgical Service Swaps — Modifying a single database or component in the architecture often requires regenerating the entire diagram, losing custom node positions and connections.
Architecture Sync Loop
Kairos resolves the state drift problem by establishing a persistent bi-directional synchronization loop. Instead of relying on client-side state, all coordinate mutations, chat histories, and node-level contexts are persisted in a serverless Neon PostgreSQL database via Drizzle ORM.
A background synchronizer, implemented via the useBlueprintPolling hook, queries the database every 8 seconds, executing optimistic UI merges when conflicts are detected. This ensures that manually dragged nodes and LLM-driven architectural mutations converge on a single source of truth.
Agentic Orchestration & Execution Flow
To achieve structural alignment between natural conversation and diagramming, Kairos relies on a centralized AI coordinator running in a Next.js App Router API edge handler. The execution flow progresses through distinct state transitions:
1. The Conversational Discovery Phase (Discovery)
- Objective: Establish the boundaries of the system design.
- Mechanism: The user initiates a conversation by describing their high-level intent (e.g., "Build a video encoding pipeline"). The agent evaluates this prompt and engages in a series of questions. Rather than suggesting specific tech stacks immediately, the agent probes for technical philosophy (e.g., Serverless vs. Edge-First), traffic expectations, throughput, latency targets, and compliance needs.
- Output: This phase updates the
currentPhasetoquestionnaireand populates thetechPhilosophycontext column in the Neon DB blueprint record.
2. The Ambiguity Resolution Phase (Questionnaire / MCQ)
- Objective: Narrow down architectural choice vectors before rendering coordinates.
- Mechanism: The coordinator requests a structured response from the Google Gemini Pro API. The model evaluates the accumulated chat history and produces exactly 3 to 5 targeted multiple-choice questions focusing on critical architectural junctions (e.g., choosing Apache Kafka vs. RabbitMQ for event ingestion).
- UI Ingest: The front-end renders these choices as interactive selector cards. When the user responds, their answers are appended to the historical context stream, resolving technical forks with 100% clarity.
3. The Layout Synthesis Phase (Diagram Generation)
- Objective: Generate a clean, structured JSON topology.
- Mechanism: The agent uses Gemini to output a structured JSON schema conforming to
diagramSchema. The model does not attempt to estimate coordinates, which prevents overlapping nodes. It outputs:- Nodes: Logical component IDs, human-readable labels, categorized service types (e.g.,
api-gateway,database,cache), brand icons, and localized descriptions. - Edges: Directed flow connections with transition annotations (e.g.,
source: "gateway",target: "auth-service",label: "JWT Verify").
- Nodes: Logical component IDs, human-readable labels, categorized service types (e.g.,
- Auto-Layout: The logical schema is piped into the server-side Dagre algorithm. Dagre computes the hierarchical swimlanes, parent-child groups, and node coordinates
(x, y)based on connection directions, saving the computed coordinates in the Neon Database.
4. Direct Canvas Mutations & QA (Refinement)
- Objective: Allow fine-grained editing and localized microservice queries.
- Mechanism: Once the diagram is rendered in xyflow/ReactFlow, the user can manually reposition nodes or click on any individual block. Clicking a node opens a dedicated Q&A Console that isolates the selected node's context (e.g. asking the AI: "Give me the optimal Terraform script for this Neon database block").
- Surgical Swapping: If a user wants to swap a service, a localized agent calls
/api/blueprints/diagram/swap/route.ts. The agent evaluates boundary implications, modifies the node's configuration, updates the JSON structure in Drizzle, and triggers a state sync without tearing down the surrounding canvas layout.
Schema Definition (Drizzle ORM)
The relational schema represents the complete visual topology alongside conversation history to give the LLM full retrospective awareness of both the layout boundaries and the user's intent:
export const blueprints = pgTable("blueprints", {
id: uuid("id").primaryKey().defaultRandom(),
title: text("title").notNull(),
description: text("description"),
userId: text("user_id").notNull(),
techPhilosophy: text("tech_philosophy"),
currentPhase: text("current_phase").default("discovery").notNull(),
layoutData: jsonb("layout_data").$type<{
nodes: Array<{
id: string;
type: string;
position: { x: number; y: number };
data: { label: string; icon?: string; type?: string; description?: string };
}>;
edges: Array<{
id: string;
source: string;
target: string;
animated?: boolean;
label?: string;
}>;
}>(),
createdAt: timestamp("created_at").defaultNow().notNull(),
updatedAt: timestamp("updated_at").defaultNow().notNull(),
});
export const chatHistory = pgTable("chat_history", {
id: uuid("id").primaryKey().defaultRandom(),
blueprintId: uuid("blueprint_id").references(() => blueprints.id, { onDelete: "cascade" }),
role: text("role").notNull(), // 'user' | 'assistant'
content: text("content").notNull(),
timestamp: timestamp("timestamp").defaultNow().notNull(),
});Key Technical Decisions
Phase-Aware Structured AI Pipeline
Unlike basic chatbot templates that attempt system generation in a single turn, Kairos enforces a modular four-stage state machine to capture requirements before building the diagram:
- Discovery — The assistant interviews the user about constraints, volume profiles, and functional goals.
- Questionnaire — Generates targeted, microservices-oriented multiple-choice questions (e.g. "SQL vs. NoSQL for transactional state?").
- Diagram Generation — Invokes the Gemini API with structured JSON output configurations containing the node hierarchy.
- Refinement — Unlocks visual coordinate adjustment, component swapping, and node-specific Q&A side-panels.
// app/api/chat/route.ts
// Standardized output schema for diagram generation
const diagramSchema = z.object({
nodes: z.array(z.object({
id: z.string(),
label: z.string(),
type: z.string(),
icon: z.string().optional(),
description: z.string().optional()
})),
edges: z.array(z.object({
id: z.string(),
source: z.string(),
target: z.string(),
label: z.string().optional()
}))
});Dagre-Driven Hierarchical Node Layouts
Direct generation of node coordinate coordinates (x, y) by LLMs is notoriously unreliable, resulting in overlapping clusters. Kairos splits this concern:
- The LLM solely generates the logical graph (nodes, edges, node-types, and custom properties).
- The server uses the Dagre hierarchical layout engine to resolve node parent/child boundaries, compute layout geometry, and space out clusters dynamically before saving the blueprint.
- Once rendered, developers can manually move nodes, and their custom coordinates are safely preserved without losing connections.
Surgical Service Swapping Mechanics
When a developer clicks a service node (e.g., swapping a Redis Cache for Keydb), the request is handled by a dedicated swap handler (/api/blueprints/diagram/swap/route.ts). Instead of rewriting the entire system layout:
- The API queries the context of the selected node and fetches target replacements.
- The Gemini AI engine compares the compatibility parameters, suggests changes to surrounding connection protocols, and yields the replacement metadata.
- A Drizzle transaction performs a surgical updates on the specific node index, maintaining all existing edge connector identifiers (
sourceandtargetlinks) to preserve structural integrity.
Feature Comparison
| Feature | Detail |
|---|---|
| Dynamic Canvas | Fully interactive xyflow graph supporting custom node dragging, selections, and scale zooming. |
| Phase-Aware Prompting | State-driven workflow transitioning from conversational discovery to JSON-validated diagrams. |
| Custom Icon Registry | Programmatically mapped technology icons (AWS, GCP, modern dev tools) rendered inline on nodes. |
| Node Q&A Console | Click a node to invoke localized Gemini models for microservices questions and configurations. |
| Surgical Swaps | Swap individual blocks with LLM evaluation of compatibility and connection retention. |
| Neon Sync Hook | 8-second polling synchronizer matching background server layout updates with the client view. |
| Unified Portal | Clerk-style authentication via Better-Auth managing secure workspace boundaries and databases. |
What I Learned
Building Kairos emphasized the value of separating logical structure from layout presentation. Trying to force LLMs to manage coordinates produces poor, unreadable designs. By restricting the AI to logical relationships and delegating the spatial layout to a dedicated engine like Dagre, we created a system that is both technically reliable and highly readable. Additionally, bi-directional polling proved crucial for resolving concurrent client-side layout adjustments without breaking state synchronization.