Skip to main content

Architecture: Task Builder -- Visual Workflow Editor with MongoDB Persistence

Decision​

AlternativeProsConsDecision
MongoDB as source of truth with YAML seeding (chosen)Dynamic CRUD, no redeploy needed, seeding preserves existing workflowsRequires MongoDB dependencySelected
YAML file onlySimple, version-controlledRequires rebuild/redeploy for changes, no multi-userRejected
Git-backed YAML with auto-syncVersion-controlled, familiar workflowComplex sync logic, merge conflictsRejected
Repurpose existing agent_skills collectionReuses existing infrastructureDifferent schema/purpose, migration riskRejected

Solution Architecture​

Data Flow​

First Boot:
task_config.yaml ──seed──▢ MongoDB (task_configs collection)
└── POST /api/task-configs/seed
└── Idempotent: skips if collection is non-empty
└── Marks as is_system: true, owner_id: "system"

UI Workflow:
Task Builder ──▢ /api/task-configs (CRUD) ──▢ MongoDB
└── POST: create new workflow
└── PUT: update (owner or admin only)
└── DELETE: remove (owner or admin, not system configs)
└── GET: list visible configs (system + own + shared)
└── GET ?format=yaml: export in task_config.yaml format

Supervisor:
deep_agent_single.py ──pymongo──▢ MongoDB (primary)
──fallback──▢ task_config.yaml (if MongoDB down)
└── In-memory TTL cache (default 60s)
└── invoke_self_service_task works identically with both sources

MongoDB Schema​

Collection: task_configs

interface TaskConfig {
id: string; // "task-config-<timestamp>-<random>"
name: string; // unique workflow name
category: string; // e.g., "GitHub Operations"
description?: string;
tasks: TaskStep[]; // ordered workflow steps
owner_id: string; // "system" or user email
is_system: boolean; // true for YAML-seeded
visibility: "private" | "team" | "global";
shared_with_teams?: string[];
metadata?: {
env_vars_required?: string[];
estimated_duration?: string;
tags?: string[];
};
created_at: Date;
updated_at: Date;
}

interface TaskStep {
display_text: string; // UI label
llm_prompt: string; // LLM instructions with variable substitution
subagent: string; // target subagent (caipe, github, etc.)
}

Indexes: name (unique), category, owner_id, is_system, created_at (descending)

Visual Flow Editor​

Built with @xyflow/react, the Task Builder provides a visual canvas:

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Toolbar (two-row) β”‚
β”‚ [Name] [Category] [Description] β”‚
β”‚ [Import β–Ύ] [Preview] [Download] [Save] β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Step β”‚ β”‚ Property Editor β”‚
β”‚ Palette β”‚ Flow Canvas β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ ───────── β”‚ β”‚ β”‚ display_text β”‚ β”‚
β”‚ Search β”‚ β”Œβ”€β”€β”€β”€β”€β”€β” β”‚ β”‚ llm_prompt β”‚ β”‚
β”‚ ─────── β”‚ β”‚ Step1 │───┐ β”‚ β”‚ subagent β”‚ β”‚
β”‚ CAIPE β”‚ β””β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ β”‚ (dropdown) β”‚ β”‚
β”‚ GitHub β”‚ β”Œβ”€β”€β”€β”€β”€β”€β” β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β”‚ Jira β”‚ β”‚ Step2 │──┐ β”‚ β”‚
β”‚ ArgoCD β”‚ β””β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ Env Vars Panel β”‚
β”‚ AWS β”‚ β”Œβ”€β”€β”€β”€β”€β”€β” β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ ... β”‚ β”‚ Step3 β”‚β—€β”€β”€β”€β”€β”˜ β”‚ β”‚ VAR1: step 1 β”‚ β”‚
β”‚ (154 β”‚ β””β”€β”€β”€β”€β”€β”€β”˜ β”‚ β”‚ VAR2: step 2 β”‚ β”‚
β”‚ tools) β”‚ β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”΄β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Node types (color-coded, theme-aware via useTheme()):

  • UserInput (yellow): subagent: "caipe" -- collects user input
  • Generate (purple): processing subagents (github, backstage, jira, etc.)
  • Output (green): notification/completion steps

Layout: S-curve pattern with bezier edges; nodes alternate left-right.

Key UX Features​

FeatureImplementation
Step Templates palette154 draggable tool templates, searchable, categorized by agent
CAIPE Form BuilderStructured form editor for caipe subagent steps
File I/O visualizationNodes show file read/write badges; shared-file edges highlighted green
Unsaved changes guardZustand unsaved-changes-store.ts + GuardedLink wrapper; in-app dialog
Import dialogLoad from MongoDB, upload YAML, or import from HTTP URL
YAML preview/exportSyntax-highlighted preview with copy/download; js-yaml format
Workflow templatesTemplate picker dialog when creating new workflow
Clone workflowClone button on existing workflow cards

Supervisor Integration​

def load_task_config():
if os.getenv("MONGODB_URI"):
configs = _load_from_mongodb() # pymongo query
if configs:
_CACHE[key] = (configs, time.time()) # TTL cache
return configs
return _load_from_yaml() # fallback

The shared pymongo client (mongodb_client.py) provides a singleton connection.

Components Changed​

FileDescription
ui/src/types/task-config.tsTaskConfig and TaskStep interfaces
ui/src/app/api/task-configs/route.tsCRUD API with validation, auth, YAML export
ui/src/app/api/task-configs/seed/route.tsIdempotent YAML seeding endpoint
ui/src/store/task-config-store.tsZustand store for client-side task config state
ui/src/app/(app)/task-builder/page.tsxMain Task Builder page
ui/src/components/task-builder/TaskBuilderCanvas.tsxReact Flow canvas with S-curve layout
ui/src/components/task-builder/TaskStepNode.tsxCustom node component with subagent badges
ui/src/components/task-builder/TaskBuilderSidebar.tsxProperty editor sidebar
ui/src/components/task-builder/TaskBuilderToolbar.tsxTwo-row toolbar with metadata and actions
ui/src/components/task-builder/StepPalette.tsx154 draggable tool templates
ai_platform_engineering/utils/mongodb_client.pyShared pymongo client singleton
ai_platform_engineering/multi_agents/platform_engineer/deep_agent_single.pyModified load_task_config() for MongoDB-first with YAML fallback