A visual agent orchestration platform for Snowflake's Cortex Code Agent SDK. Cortex Swarm provides a web-based interface to provision, connect, monitor, and control multi-agent pipelines — without writing SDK boilerplate.
- Visual DAG Workspace — drag-and-drop agent and gate nodes connected by typed edges (
trigger,results,content,prompt) using React Flow. Color-coded edge chips + gear icon for inline edits. - Pipeline Architect — describe a pipeline in natural language and an LLM-powered architect emits a fenced JSON spec, asks structured multiple-choice clarifying questions, and provisions the full DAG for you.
- Pipeline Orchestration — automatic cascading execution. Multi-input nodes use AND-join semantics by default (wait for all upstream to complete) and receive a labeled merged context (
### From <agent>blocks). - Human-in-the-Loop Gates — insert approval gates that pause execution until a human approves (continue) or rejects (halt).
- Real-Time Monitoring — WebSocket-powered live streaming of agent activity, tool calls, and token usage.
- Pipeline Timeline — Gantt-chart visualization showing queued, running, and completed phases for each agent, with edges drawn between them.
- Edge Inspector — clicking an edge shows the exact computed payload that will be passed to the downstream agent (via
GET /graph/edges/{id}/preview), plus the prompt template if any. - Silent-failure & wait-state surfacing — agents that completed without producing meaningful output are flagged with a warning chip; downstream nodes show a "Waiting for …" badge while upstream is in flight.
- Full Agent Lifecycle — spawn, stop, re-run, inspect, and delete agents from the UI; version + build timestamp chip in the header so you always know which deploy you're looking at.
┌─────────────────────────────────────────────────────────┐
│ React + Vite Frontend │
│ ├── React Flow v12 (DAG workspace, custom edges) │
│ ├── Zustand (state management) │
│ ├── TanStack Query (polling + cache) │
│ └── WebSocket (real-time agent streaming) │
└──────────────────────┬──────────────────────────────────┘
│ HTTP + WebSocket
┌──────────────────────▼──────────────────────────────────┐
│ FastAPI Backend (Python 3.11+) │
│ ├── AgentManager (asyncio orchestration engine) │
│ ├── Graph + Edge model (DAG with typed edges) │
│ ├── Architect agent (NL → pipeline spec) │
│ └── WebSocket broadcast (per-session events) │
└──────────────────────┬──────────────────────────────────┘
│ subprocess
┌──────────────────────▼──────────────────────────────────┐
│ Cortex Code Agent SDK v1.0.0 │
│ └── Wraps Cortex Code CLI as managed subprocess │
└──────────────────────┬──────────────────────────────────┘
│ Snowflake connection
┌──────────────────────▼──────────────────────────────────┐
│ Snowflake (SQL execution, data access) │
└─────────────────────────────────────────────────────────┘
There are two ways to run Cortex Swarm: locally for development, or deployed to Snowpark Container Services (SPCS) for use inside Snowflake.
- Python 3.11+
- Node.js 18+
- Snowflake account with the Cortex Code CLI configured (a working
~/.snowflake/connections.toml) cortex-code-agent-sdkv1.0.0+ installed in the backend venv
Run the FastAPI backend and the Vite dev server side by side. Vite proxies /agents, /graph, /ws, etc. to localhost:8000, so you only need to point your browser at the frontend.
Backend (terminal 1):
cd cortex-swarm/backend
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
SNOWFLAKE_CONNECTION_NAME=<your-connection> uvicorn app.main:app --reload --port 8000Frontend (terminal 2):
cd cortex-swarm/frontend
npm install
npm run devOpen http://localhost:5173. The header shows a dev · <build time> chip so you know you're on the local build.
Tip: the backend reads
SNOWFLAKE_CONNECTION_NAMEto decide which connection from yourconnections.tomleach spawned agent uses.
Cortex Swarm is designed to run on Snowpark Container Services (SPCS) inside Snowflake's security perimeter. The container uses an OAuth bridge that captures SNOWFLAKE_HOST, SNOWFLAKE_ACCOUNT, and SNOWFLAKE_WAREHOUSE at startup and writes them to ~/.snowflake/connections.toml, with a token-refresh loop keeping the OAuth token current. Spawned agents inherit this connection automatically.
One-time setup (compute pool, image repo, and service — substitute your DB/schema/role/connection):
snow sql --connection <CONN> -q "
CREATE COMPUTE POOL IF NOT EXISTS CORTEX_AGENT_POOL
MIN_NODES = 1 MAX_NODES = 1 INSTANCE_FAMILY = CPU_X64_S;
CREATE IMAGE REPOSITORY IF NOT EXISTS PLATFORM_ANALYTICS.PUBLIC.CORTEX_AGENT_REPO;
"Build, tag, push (run from the cortex-swarm/ directory):
cd cortex-swarm
BUILD_VERSION=$(git rev-parse --short HEAD) docker build \
--build-arg BUILD_VERSION=$BUILD_VERSION \
--platform linux/amd64 \
-t cortex-swarm:latest .
snow spcs image-registry login --connection <CONN>
REGISTRY=<account>.registry.snowflakecomputing.com/platform_analytics/public/cortex_agent_repo
docker tag cortex-swarm:latest $REGISTRY/cortex-swarm:latest
docker push $REGISTRY/cortex-swarm:latestCreate or update the service using service-spec.yaml:
# First time
snow sql --connection <CONN> -q "
CREATE SERVICE PLATFORM_ANALYTICS.PUBLIC.CORTEX_SWARM_SERVICE
IN COMPUTE POOL CORTEX_AGENT_POOL
FROM SPECIFICATION_FILE = '$(pwd)/cortex-swarm/service-spec.yaml';
"
# Subsequent updates
snow sql --connection <CONN> -q "
ALTER SERVICE PLATFORM_ANALYTICS.PUBLIC.CORTEX_SWARM_SERVICE
FROM SPECIFICATION_FILE = '$(pwd)/cortex-swarm/service-spec.yaml';
"Verify and grant access:
snow sql --connection <CONN> -q "
SELECT SYSTEM\$GET_SERVICE_STATUS('PLATFORM_ANALYTICS.PUBLIC.CORTEX_SWARM_SERVICE');
SHOW ENDPOINTS IN SERVICE PLATFORM_ANALYTICS.PUBLIC.CORTEX_SWARM_SERVICE;
GRANT USAGE ON SERVICE PLATFORM_ANALYTICS.PUBLIC.CORTEX_SWARM_SERVICE TO ROLE <YOUR_USER_ROLE>;
"When the service status shows READY, open the public URL listed by SHOW ENDPOINTS. The version chip in the header confirms which build is live.
Coco_Agent_Platform/
├── cortex-swarm/
│ ├── backend/
│ │ ├── app/
│ │ │ ├── main.py # FastAPI app + WebSocket + edge preview endpoint
│ │ │ ├── agent_manager.py # AND-join cascade, merged context, silent-failure detection
│ │ │ ├── architect.py # NL → pipeline-spec architect, structured questions
│ │ │ ├── models.py # Pydantic models (sessions, graphs, edges)
│ │ │ └── edges.md # Canonical edge-type contract docs
│ │ └── requirements.txt
│ ├── frontend/
│ │ ├── src/
│ │ │ ├── pages/Canvas.tsx # React Flow DAG workspace
│ │ │ ├── components/
│ │ │ │ ├── AgentNode.tsx # Agent card (with waiting-for + warning chips)
│ │ │ │ ├── GateNode.tsx # Human gate card
│ │ │ │ ├── PipelineEdge.tsx # Custom edge with type chip + gear icon
│ │ │ │ ├── PipelineArchitect.tsx # Conversational pipeline designer
│ │ │ │ ├── DetailSidebar.tsx # Agent + Edge Inspector panes
│ │ │ │ ├── Dashboard.tsx # KPIs, timeline, agent table
│ │ │ │ └── ErrorBoundary.tsx # Surfaces render errors
│ │ │ ├── store/agentStore.ts # Zustand state
│ │ │ └── api/agents.ts # API client
│ │ └── package.json
│ ├── Dockerfile # SPCS image
│ └── service-spec.yaml # SPCS service spec
├── screenshots/ # README assets
├── PRD.md # Product requirements
├── TECH_SPEC.md # Technical specification
├── DESIGN.md # UI/UX design document
└── BUILD_PLAN.md # Implementation plan
The full contract lives in cortex-swarm/backend/app/edges.md. Quick reference:
| Type | Color | Payload sent to downstream | Use for |
|---|---|---|---|
trigger |
gray | empty string | Fan-out from a coordinator with no payload |
results |
cyan | upstream agent's final assistant message | Default — analyst → summarizer chains |
content |
violet | full transcript (text + tool calls) | When downstream needs intermediate reasoning |
prompt |
emerald | prompt_template with {upstream_result} substituted |
When the edge itself reframes upstream output |
When a node has multiple incoming edges, the orchestrator waits for all upstream sources to complete (the default join_mode: all) and then fires the downstream once with a labeled merged context. Set join_mode: any on a node config to switch to ANY-join semantics.
Gates pause pipeline execution for human review. When all upstream nodes feeding a gate complete, the gate enters pending. A human can then approve (continue pipeline) or reject (halt pipeline).
Running a graph resets all nodes to queued, then starts root nodes (nodes with no incoming edges). As each agent completes, _cascade_downstream checks readiness for every outgoing edge target and fires any whose dependencies are satisfied — never double-firing a target that is already running.
| Layer | Technology |
|---|---|
| Frontend | React 19, Vite, TypeScript |
| Graph Viz | React Flow v12 (@xyflow/react) |
| State | Zustand |
| Data Fetching | TanStack Query v5 |
| Backend | FastAPI, uvicorn, asyncio |
| Agent SDK | cortex-code-agent-sdk v1.0.0 |
| Styling | Tailwind CSS v4 |
| Deployment | Snowpark Container Services (SPCS) |
Internal / Snowflake use.
